From c170c7b11bf049fa3dc40dfd238eb46a9159d0d9 Mon Sep 17 00:00:00 2001 From: wanghaishuo Date: Fri, 11 Apr 2025 14:37:50 +0800 Subject: [PATCH 1/9] base version of 3.40.1 Signed-off-by: ryne3366 --- README.OpenSource | 4 +- bundle.json | 2 +- include/sqlite3.h | 977 +- include/sqlite3ext.h | 22 +- include/sqlite3icu.h | 100 +- include/sqlite3tokenizer.h | 290 +- patch/0001-BaselineWithHistoryOH.patch | 3639 -- patch/0002-busy-debug.patch | 813 - patch/0003-suport-meta-recovery.patch | 1346 - patch/0004-Enable-and-optimize-ICU.patch | 2119 - ...ort-corruption-when-runtime-decteted.patch | 1446 - ...dd-extention-cksumvfs-and-check-page.patch | 1079 - patch/0007-BugFix-CurrVersion.patch | 301 - src/shell.c | 27851 ++++++------- src/sqlite3.c | 32823 +++++----------- 15 files changed, 21475 insertions(+), 51337 deletions(-) delete mode 100644 patch/0001-BaselineWithHistoryOH.patch delete mode 100644 patch/0002-busy-debug.patch delete mode 100644 patch/0003-suport-meta-recovery.patch delete mode 100644 patch/0004-Enable-and-optimize-ICU.patch delete mode 100644 patch/0005-Report-corruption-when-runtime-decteted.patch delete mode 100644 patch/0006-Add-extention-cksumvfs-and-check-page.patch delete mode 100644 patch/0007-BugFix-CurrVersion.patch diff --git a/README.OpenSource b/README.OpenSource index 51af6ce..d1cd452 100644 --- a/README.OpenSource +++ b/README.OpenSource @@ -3,9 +3,9 @@ "Name": "SQLite", "License": "Public Domain", "License File": "LICENSE", - "Version Number": "3.46.1", + "Version Number": "3.40.1", "Owner": "wangbingquan@huawei.com", - "Upstream URL": "https://sqlite.ac.cn/2024/sqlite-amalgamation-3460100.zip", + "Upstream URL": "https://www.sqlite.org/2022/sqlite-amalgamation-3400100.zip", "Description": "SQLite is a C-language library that implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine." } ] diff --git a/bundle.json b/bundle.json index cc2fc27..b733d95 100644 --- a/bundle.json +++ b/bundle.json @@ -1,7 +1,7 @@ { "name": "@ohos/sqlite", "description": "SQLite is a C-language library that implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine.", - "version": "3.46.1", + "version": "3.40.1", "homePage": "https://www.sqlite.org/", "license": "Public Domain", "publishAs": "code-segment", diff --git a/include/sqlite3.h b/include/sqlite3.h index 3b1a37a..4e24bca 100644 --- a/include/sqlite3.h +++ b/include/sqlite3.h @@ -146,9 +146,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.46.1" -#define SQLITE_VERSION_NUMBER 3046001 -#define SQLITE_SOURCE_ID "2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33" +#define SQLITE_VERSION "3.40.1" +#define SQLITE_VERSION_NUMBER 3040001 +#define SQLITE_SOURCE_ID "2022-12-28 14:03:47 df5c253c0b3dd24916e4ec7cf77d3db5294cc9fd45ae7b9c5e82ad8197f38a24" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -420,8 +420,6 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running. **
  • The application must not modify the SQL statement text passed into ** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running. -**
  • The application must not dereference the arrays or string pointers -** passed as the 3rd and 4th callback parameters after it returns. ** */ SQLITE_API int sqlite3_exec( @@ -530,7 +528,6 @@ SQLITE_API int 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)) @@ -566,7 +563,6 @@ SQLITE_API int 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)) @@ -764,11 +760,11 @@ struct sqlite3_file { ** ** 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 +** xLock() is always on 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, @@ -1179,6 +1175,7 @@ struct 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. +** ** **
  • [[SQLITE_FCNTL_EXTERNAL_READER]] ** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect @@ -1191,16 +1188,16 @@ struct 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. +** ** **
  • [[SQLITE_FCNTL_CKSM_FILE]] -** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use internally by the -** [checksum VFS shim] only. +** Used by the cksmvfs VFS module only. ** **
  • [[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. +** database is not a temp db, then this 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, it is a no-op, not an error. ** */ #define SQLITE_FCNTL_LOCKSTATE 1 @@ -1658,23 +1655,20 @@ SQLITE_API int sqlite3_os_end(void); ** must ensure that no other SQLite interfaces are invoked by other ** threads while sqlite3_config() is running. ** -** The first argument to 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 sqlite3_config() interface +** The sqlite3_config() interface ** may only be invoked prior to library initialization using ** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()]. -** The exceptional configuration options that may be invoked at any time -** are called "anytime configuration options". ** ^If sqlite3_config() is called after [sqlite3_initialize()] and before -** [sqlite3_shutdown()] with a first argument that is not an anytime -** configuration option, then the sqlite3_config() call will return SQLITE_MISUSE. +** [sqlite3_shutdown()] then it will return SQLITE_MISUSE. ** Note, however, that ^sqlite3_config() can be called as part of the ** implementation of an application-defined [sqlite3_os_init()]. ** +** The first argument to 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. +** ** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. ** ^If the option is unknown or SQLite is unable to set the option ** then this routine returns a non-zero [error code]. @@ -1782,23 +1776,6 @@ struct sqlite3_mem_methods { ** These constants are the available integer configuration options that ** can be passed as the first argument to the [sqlite3_config()] interface. ** -** Most of the configuration options for sqlite3_config() -** will only work if invoked prior to [sqlite3_initialize()] or after -** [sqlite3_shutdown()]. The few exceptions to this rule are called -** "anytime configuration options". -** ^Calling [sqlite3_config()] with a first argument that is not an -** anytime configuration option in between calls to [sqlite3_initialize()] and -** [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: -**
      -**
    • SQLITE_CONFIG_LOG -**
    • SQLITE_CONFIG_PCACHE_HDRSZ -**
    -** ** New configuration options may be added in future releases of SQLite. ** Existing configuration options might be discontinued. Applications ** should check the return code from [sqlite3_config()] to make sure that @@ -2129,7 +2106,7 @@ struct 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 behavior. +** negative value for this option restores the default behaviour. ** This option is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option. ** @@ -2144,22 +2121,6 @@ struct sqlite3_mem_methods { ** 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]] -**
    SQLITE_CONFIG_ROWID_IN_VIEW -**
    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. -** ** [[SQLITE_CONFIG_CORRUPTION]]
    SQLITE_CONFIG_CORRUPTION
    **
    The SQLITE_CONFIG_CORRUPTION option is used to configure the SQLite ** global [ corruption error]. @@ -2176,28 +2137,28 @@ struct sqlite3_mem_methods { ** function must be threadsafe.
    ** */ -#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ -#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ -#define SQLITE_CONFIG_SERIALIZED 3 /* nil */ -#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ -#define SQLITE_CONFIG_GETMALLOC 5 /* 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 /* sqlite3_mutex_methods* */ -#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */ -/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ -#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ -#define SQLITE_CONFIG_PCACHE 14 /* no-op */ -#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */ -#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ -#define SQLITE_CONFIG_URI 17 /* int */ -#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ -#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ +#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ +#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ +#define SQLITE_CONFIG_SERIALIZED 3 /* nil */ +#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ +#define SQLITE_CONFIG_GETMALLOC 5 /* 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 /* sqlite3_mutex_methods* */ +#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */ +/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ +#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ +#define SQLITE_CONFIG_PCACHE 14 /* no-op */ +#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */ +#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ +#define SQLITE_CONFIG_URI 17 /* int */ +#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ +#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ -#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ -#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ +#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ +#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, 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 */ @@ -2205,9 +2166,8 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ -#define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */ -#define SQLITE_CONFIG_CORRUPTION 31 /* xCorruption */ -#define SQLITE_CONFIG_ENABLE_ICU 32 /* boolean */ +#define SQLITE_CONFIG_CORRUPTION 30 /* xCorruption */ +#define SQLITE_CONFIG_ENABLE_ICU 31 /* boolean */ /* ** CAPI3REF: Database Connection Configuration Options @@ -2241,7 +2201,7 @@ struct 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 -** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero. +** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero. ** Any attempt to change the lookaside memory configuration when lookaside ** memory is in use leaves the configuration unchanged and returns ** [SQLITE_BUSY].)^ @@ -2338,7 +2298,7 @@ struct 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 behavior. The first parameter passed to this operation +** override this behaviour. 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 @@ -2391,12 +2351,8 @@ struct sqlite3_mem_methods { **
  • sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0); ** ** 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. 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. +** process requires the use of this obscure API and multiple steps to help +** ensure that it does not happen by accident. ** ** [[SQLITE_DBCONFIG_DEFENSIVE]]
    SQLITE_DBCONFIG_DEFENSIVE
    **
    The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the @@ -2435,7 +2391,7 @@ struct sqlite3_mem_methods { **
    ** ** [[SQLITE_DBCONFIG_DQS_DML]] -**
    SQLITE_DBCONFIG_DQS_DML
    +**
    SQLITE_DBCONFIG_DQS_DML **
    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 @@ -2444,7 +2400,7 @@ struct sqlite3_mem_methods { **
    ** ** [[SQLITE_DBCONFIG_DQS_DDL]] -**
    SQLITE_DBCONFIG_DQS_DDL
    +**
    SQLITE_DBCONFIG_DQS_DDL **
    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 @@ -2453,7 +2409,7 @@ struct sqlite3_mem_methods { **
    ** ** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]] -**
    SQLITE_DBCONFIG_TRUSTED_SCHEMA
    +**
    SQLITE_DBCONFIG_TRUSTED_SCHEMA **
    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 @@ -2473,7 +2429,7 @@ struct sqlite3_mem_methods { **
    ** ** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]] -**
    SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
    +**
    SQLITE_DBCONFIG_LEGACY_FILE_FORMAT **
    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 @@ -2482,7 +2438,7 @@ struct 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 generate database files that are compatible +** is now scarcely any need to generated 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 @@ -2491,40 +2447,8 @@ struct 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 descending indexes. +** either generated columns or decending indexes. **
    -** -** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]] -**
    SQLITE_DBCONFIG_STMT_SCANSTATUS
    -**
    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 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. -**
    -** -** [[SQLITE_DBCONFIG_REVERSE_SCANORDER]] -**
    SQLITE_DBCONFIG_REVERSE_SCANORDER
    -**
    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. -**
    -** ** */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ @@ -2545,9 +2469,7 @@ struct 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_STMT_SCANSTATUS 1018 /* int int* */ -#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */ -#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */ +#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes @@ -2769,13 +2691,8 @@ SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3*); ** ^A call to 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 sqlite3_interrupt() call returns. -** -** ^The [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 sqlite3_interrupt(sqlite3*); -SQLITE_API int sqlite3_is_interrupted(sqlite3*); /* ** CAPI3REF: Determine If An SQL Statement Is Complete @@ -3256,7 +3173,7 @@ SQLITE_API int sqlite3_set_droptable_handle( sqlite3 *db, void (*xFunc)(sqlite3*,const char*,const char*) ); -#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ +#endif /* ** CAPI3REF: Authorizer Return Codes @@ -3329,8 +3246,8 @@ SQLITE_API int sqlite3_set_droptable_handle( #define SQLITE_RECURSIVE 33 /* NULL NULL */ /* -** CAPI3REF: Deprecated Tracing And Profiling Functions -** DEPRECATED +** CAPI3REF: Tracing And Profiling Functions +** METHOD: sqlite3 ** ** These routines are deprecated. Use the [sqlite3_trace_v2()] interface ** instead of the routines described here. @@ -3400,8 +3317,8 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, **
    ^An SQLITE_TRACE_PROFILE callback provides approximately the same ** information as is provided by the [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 approximately -** the number of nanoseconds that the prepared statement took to run. +** X argument points to a 64-bit integer which is the estimated of +** the number of nanosecond that the prepared statement took to run. ** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes. ** ** [[SQLITE_TRACE_ROW]]
    SQLITE_TRACE_ROW
    @@ -3433,10 +3350,8 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, ** M argument should be the bitwise OR-ed combination of ** zero or more [SQLITE_TRACE] constants. ** -** ^Each call to either sqlite3_trace(D,X,P) or sqlite3_trace_v2(D,M,X,P) -** overrides (cancels) all prior calls to sqlite3_trace(D,X,P) or -** sqlite3_trace_v2(D,M,X,P) for the [database connection] D. Each -** database connection may have at most one trace callback. +** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides +** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2(). ** ** ^The X callback is invoked whenever any of the events identified by ** mask M occur. ^The integer return value from the callback is currently @@ -3466,7 +3381,7 @@ SQLITE_API int sqlite3_trace_v2( ** ** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback ** function X to be invoked periodically during long running calls to -** [sqlite3_step()] and [sqlite3_prepare()] and similar for +** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for ** database connection D. An example use for this ** interface is to keep a GUI updated during a large query. ** @@ -3491,13 +3406,6 @@ SQLITE_API int sqlite3_trace_v2( ** Note that [sqlite3_prepare_v2()] and [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 [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 [sqlite3_prepare()] while analyzing and generating -** code for complex queries. */ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); @@ -3534,18 +3442,13 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** **
    ** ^(
    [SQLITE_OPEN_READONLY]
    -**
    The database is opened in read-only mode. If the database does -** not already exist, an error is returned.
    )^ +**
    The database is opened in read-only mode. If the database does not +** already exist, an error is returned.
    )^ ** ** ^(
    [SQLITE_OPEN_READWRITE]
    -**
    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. [sqlite3_db_readonly()] can be -** used to determine whether the database is actually -** read-write.
    )^ +**
    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.
    )^ ** ** ^(
    [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]
    **
    The database is opened for reading and writing, and is created if @@ -3805,7 +3708,7 @@ SQLITE_API int sqlite3_open_v2( ** as F) must be one of: **
      **
    • A database filename pointer created by the SQLite core and -** passed into the xOpen() method of a VFS implementation, or +** passed into the xOpen() method of a VFS implemention, or **
    • A filename obtained from [sqlite3_db_filename()], or **
    • A new filename constructed using [sqlite3_create_filename()]. **
    @@ -3918,7 +3821,7 @@ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*); /* ** CAPI3REF: Create and Destroy VFS Filenames ** -** These interfaces are provided for use by [VFS shim] implementations and +** These interfces are provided for use by [VFS shim] implementations and ** are not useful outside of that context. ** ** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of @@ -3997,17 +3900,14 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename); ** ** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language -** 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.) +** text that describes the error, as either UTF-8 or UTF-16 respectively. ** ^(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 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. +** ^The sqlite3_errstr() interface returns the English-language text +** that describes the [result code], as UTF-8. ** ^(Memory to hold the error message string is managed internally ** and must not be freed by the application)^. ** @@ -4468,41 +4368,6 @@ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); */ SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt); -/* -** CAPI3REF: Change The EXPLAIN Setting For A Prepared Statement -** METHOD: sqlite3_stmt -** -** The 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 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 -** sqlite3_stmt_explain(S,E) will fail with SQLITE_ERROR if S cannot be -** reprepared because it was created using [sqlite3_prepare()] instead of -** the newer [sqlite3_prepare_v2()] or [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 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 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 [sqlite3_reset(S)] -** immediately prior to calling sqlite3_stmt_explain(S,E). -*/ -SQLITE_API int sqlite3_stmt_explain(sqlite3_stmt *pStmt, int eMode); - /* ** CAPI3REF: Determine If A Prepared Statement Has Been Reset ** METHOD: sqlite3_stmt @@ -4666,7 +4531,7 @@ typedef struct sqlite3_context 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 passed to indicate that +** ^ (2) The special constant, [SQLITE_STATIC], may be passsed 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 @@ -5345,33 +5210,20 @@ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt); ** ^The [sqlite3_reset(S)] interface resets the [prepared statement] S ** back to the beginning of its program. ** -** ^The return code from [sqlite3_reset(S)] indicates whether or not -** the previous evaluation of prepared statement S completed successfully. -** ^If [sqlite3_step(S)] has never before been called on S or if -** [sqlite3_step(S)] has not been called since the previous call -** to [sqlite3_reset(S)], then [sqlite3_reset(S)] will return -** [SQLITE_OK]. +** ^If the most recent call to [sqlite3_step(S)] for the +** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE], +** or if [sqlite3_step(S)] has never before been called on S, +** then [sqlite3_reset(S)] returns [SQLITE_OK]. ** ** ^If the most recent call to [sqlite3_step(S)] for the ** [prepared statement] S indicated an error, then ** [sqlite3_reset(S)] returns an appropriate [error code]. -** ^The [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 [sqlite3_step(S)] might return SQLITE_ROW but -** the overall statement might still fail and the [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 [sqlite3_reset(S)] even if -** no prior call to [sqlite3_step(S)] indicated a problem. ** ** ^The [sqlite3_reset(S)] interface does not change the values ** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S. */ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); - /* ** CAPI3REF: Create Or Redefine SQL Functions ** KEYWORDS: {function creation routines} @@ -5577,21 +5429,10 @@ SQLITE_API int 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 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. -**

    -** 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. +** 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. **

    ** ** [[SQLITE_INNOCUOUS]]
    SQLITE_INNOCUOUS
    @@ -5618,27 +5459,13 @@ SQLITE_API int sqlite3_create_window_function( **
    ** ** [[SQLITE_SUBTYPE]]
    SQLITE_SUBTYPE
    -** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call +** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call ** [sqlite3_value_subtype()] to inspect the sub-types of its arguments. -** This flag instructs SQLite to omit some corner-case optimizations that -** might disrupt the operation of the [sqlite3_value_subtype()] function, -** causing it to return zero rather than the correct subtype(). -** SQL functions that invokes [sqlite3_value_subtype()] should have this -** property. If the SQLITE_SUBTYPE property is omitted, then the return -** value from [sqlite3_value_subtype()] might sometimes be zero even though -** a non-zero subtype was specified by the function argument expression. -** -** [[SQLITE_RESULT_SUBTYPE]]
    SQLITE_RESULT_SUBTYPE
    -** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call -** [sqlite3_result_subtype()] to cause a sub-type to be associated with its -** result. -** Every function that invokes [sqlite3_result_subtype()] should have this -** property. If it does not, then the call to [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 -** [sqlite3_result_subtype()] should avoid setting this property, as the -** purpose of this property is to disable certain optimizations that are -** incompatible with subtypes. +** 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. +** sqlite3_value_subtype() will always return 0). **
    **
    */ @@ -5646,7 +5473,6 @@ SQLITE_API int sqlite3_create_window_function( #define SQLITE_DIRECTONLY 0x000080000 #define SQLITE_SUBTYPE 0x000100000 #define SQLITE_INNOCUOUS 0x000200000 -#define SQLITE_RESULT_SUBTYPE 0x001000000 /* ** CAPI3REF: Deprecated Functions @@ -5747,6 +5573,16 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** then the conversion is performed. Otherwise no conversion occurs. ** The [SQLITE_INTEGER | datatype] after conversion is returned.)^ ** +** ^(The sqlite3_value_encoding(X) interface returns one of [SQLITE_UTF8], +** [SQLITE_UTF16BE], or [SQLITE_UTF16LE] according to the current encoding +** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X) +** returns something other than SQLITE_TEXT, then the return value from +** sqlite3_value_encoding(X) is meaningless. ^Calls to +** sqlite3_value_text(X), sqlite3_value_text16(X), sqlite3_value_text16be(X), +** sqlite3_value_text16le(X), sqlite3_value_bytes(X), or +** sqlite3_value_bytes16(X) might change the encoding of the value X and +** thus change the return from subsequent calls to sqlite3_value_encoding(X). +** ** ^Within the [xUpdate] method of a [virtual table], the ** sqlite3_value_nochange(X) interface returns true if and only if ** the column corresponding to X is unchanged by the UPDATE operation @@ -5811,27 +5647,6 @@ SQLITE_API int sqlite3_value_type(sqlite3_value*); SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); SQLITE_API int sqlite3_value_nochange(sqlite3_value*); SQLITE_API int sqlite3_value_frombind(sqlite3_value*); - -/* -** CAPI3REF: Report the internal text encoding state of an sqlite3_value object -** METHOD: sqlite3_value -** -** ^(The 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 sqlite3_value_type(X) -** returns something other than SQLITE_TEXT, then the return value from -** sqlite3_value_encoding(X) is meaningless. ^Calls to -** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], [sqlite3_value_text16be(X)], -** [sqlite3_value_text16le(X)], [sqlite3_value_bytes(X)], or -** [sqlite3_value_bytes16(X)] might change the encoding of the value X and -** thus change the return from subsequent calls to 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 [sqlite3_value] object. Ordinary applications should -** not need to know what the internal state of an sqlite3_value object is and -** hence should not need to use this interface. -*/ SQLITE_API int sqlite3_value_encoding(sqlite3_value*); /* @@ -5843,12 +5658,6 @@ SQLITE_API int sqlite3_value_encoding(sqlite3_value*); ** information can be used to pass a limited amount of context from ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. -** -** Every [application-defined SQL function] that invoke this interface -** should include the [SQLITE_SUBTYPE] property in the text -** encoding argument when the function is [sqlite3_create_function|registered]. -** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype() -** might return zero instead of the upstream subtype in some corner cases. */ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); @@ -5947,56 +5756,48 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** METHOD: sqlite3_context ** ** These functions may be used by (non-aggregate) SQL functions to -** 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. +** 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. ** 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 sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data +** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata ** associated by the 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 auxiliary data +** function argument. ^If there is no metadata ** associated with the function argument, the sqlite3_get_auxdata(C,N) interface ** returns a NULL pointer. ** -** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the -** N-th argument of the application-defined function. ^Subsequent +** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th +** argument of the application-defined function. ^Subsequent ** calls to sqlite3_get_auxdata(C,N) return P from the most recent -** sqlite3_set_auxdata(C,N,P,X) call if the auxiliary data is still valid or -** NULL if the auxiliary data has been discarded. +** sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or +** NULL if the metadata has been discarded. ** ^After each call to 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 auxiliary data is discarded. -** SQLite is free to discard the auxiliary data at any time, including:
      +** once, when the metadata is discarded. +** SQLite is free to discard the metadata at any time, including:
        **
      • ^(when the corresponding function parameter changes)^, or **
      • ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the ** SQL statement)^, or **
      • ^(when sqlite3_set_auxdata() is invoked again on the same ** parameter)^, or **
      • ^(during the original sqlite3_set_auxdata() call when a memory -** allocation error occurs.)^ -**
      • ^(during the original sqlite3_set_auxdata() call if the function -** is evaluated during query planning instead of during query execution, -** as sometimes happens with [SQLITE_ENABLE_STAT4].)^
      +** allocation error occurs.)^
    ** -** Note the last two bullets in particular. The destructor X in +** Note the last bullet in particular. The destructor X in ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the ** sqlite3_set_auxdata() interface even returns. Hence 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 -** sqlite3_set_auxdata() has been called. Furthermore, a call to -** sqlite3_get_auxdata() that occurs immediately after a corresponding call -** to sqlite3_set_auxdata() might still return NULL if an out-of-memory -** condition occurred during the 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 +** sqlite3_set_auxdata() has been called. +** +** ^(In practice, metadata is preserved between function calls for ** function parameters that are compile-time constants, including literal ** values and [parameters] and expressions composed from the same.)^ ** @@ -6006,67 +5807,10 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** ** These routines must be called from the same thread in which ** the SQL function is running. -** -** See also: [sqlite3_get_clientdata()] and [sqlite3_set_clientdata()]. */ SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N); SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); -/* -** CAPI3REF: Database Connection Client Data -** METHOD: sqlite3 -** -** These functions are used to associate one or more named pointers -** with a [database connection]. -** A call to sqlite3_set_clientdata(D,N,P,X) causes the pointer P -** to be attached to [database connection] D using name N. Subsequent -** calls to sqlite3_get_clientdata(D,N) will return a copy of pointer P -** or a NULL pointer if there were no prior calls to -** 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: -**
      -**
    • An out-of-memory error occurs during the call to -** sqlite3_set_clientdata() which attempts to register pointer P. -**
    • A subsequent call to sqlite3_set_clientdata(D,N,P,X) is made -** with the same D and N parameters. -**
    • 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. -**
    -** -** 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: [sqlite3_set_auxdata()] and [sqlite3_get_auxdata()]. -*/ -SQLITE_API void *sqlite3_get_clientdata(sqlite3*,const char*); -SQLITE_API int sqlite3_set_clientdata(sqlite3*, const char*, void*, void(*)(void*)); /* ** CAPI3REF: Constants Defining Special Destructor Behavior @@ -6268,20 +6012,6 @@ SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); ** 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 -** [sqlite3_create_function|registered]. If the [SQLITE_RESULT_SUBTYPE] -** property is omitted from the function that invokes sqlite3_result_subtype(), -** then in some cases the 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 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 sqlite3_result_subtype(sqlite3_context*,unsigned int); @@ -6463,7 +6193,7 @@ SQLITE_API int sqlite3_rekey_v2( const void *pKey, int nKey /* The new key */ ); -#endif /* SQLITE_HAS_CODEC */ +#endif #ifdef SQLITE_ENABLE_CEROD /* @@ -6491,13 +6221,6 @@ SQLITE_API void sqlite3_activate_cerod( ** of the default VFS is not implemented correctly, or not implemented at ** all, then the behavior of sqlite3_sleep() may deviate from the description ** in the previous paragraphs. -** -** If a negative argument is passed to 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 sqlite3_sleep() is changed to zero before it is relayed -** down into the xSleep method of the VFS. */ SQLITE_API int sqlite3_sleep(int); @@ -6751,7 +6474,7 @@ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema); /* -** CAPI3REF: Allowed return values from sqlite3_txn_state() +** CAPI3REF: Allowed return values from [sqlite3_txn_state()] ** KEYWORDS: {transaction state} ** ** These constants define the current transaction state of a database file. @@ -6883,7 +6606,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); ** ^Each call to the sqlite3_autovacuum_pages() interface overrides all ** previous invocations for that database connection. ^If the callback ** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer, -** then the autovacuum steps callback is canceled. The return value +** then the autovacuum steps callback is cancelled. The return value ** from 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 @@ -6949,12 +6672,6 @@ SQLITE_API int 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 @@ -7348,6 +7065,15 @@ SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void)); */ SQLITE_API void 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 */ @@ -7408,10 +7134,6 @@ struct 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)(sqlite3_vtab *pVTab, const char *zSchema, - const char *zTabName, int mFlags, char **pzErr); }; /* @@ -7470,10 +7192,10 @@ struct 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 idxStr values are recorded and passed into the +** ^The idxNum and idxPtr values are recorded and passed into the ** [xFilter] method. -** ^[sqlite3_free()] is used to free idxStr if and only if -** needToFreeIdxStr is true. +** ^[sqlite3_free()] is used to free idxPtr if and only if +** needToFreeIdxPtr 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 @@ -7593,7 +7315,7 @@ struct sqlite3_index_info { ** the [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 sqlite3_vtab_collation() -** interface is not commonly needed. +** interface is no commonly needed. */ #define SQLITE_INDEX_CONSTRAINT_EQ 2 #define SQLITE_INDEX_CONSTRAINT_GT 4 @@ -7752,6 +7474,16 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL); */ SQLITE_API int sqlite3_overload_function(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} @@ -7899,7 +7631,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, 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 behavior. ^Calling this routine +** open blob handle results in undefined behaviour. ^Calling this routine ** with a null pointer (such as would be returned by a failed call to ** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function ** is passed a valid open blob handle, the values returned by the @@ -8126,20 +7858,18 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); ** ** ^(Some systems (for example, Windows 95) do not support the operation ** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() -** will always return SQLITE_BUSY. In most cases the SQLite core only uses -** 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 -** sqlite3_mutex_try() is required.)^ +** will always return SQLITE_BUSY. The SQLite core only ever uses +** sqlite3_mutex_try() as an optimization so this is acceptable +** behavior.)^ ** ** ^The 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 sqlite3_mutex_enter(), sqlite3_mutex_try(), -** sqlite3_mutex_leave(), or sqlite3_mutex_free() is a NULL pointer, -** then any of the four routines behaves as a no-op. +** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or +** sqlite3_mutex_leave() is a NULL pointer, then all three routines +** behave as no-ops. ** ** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()]. */ @@ -8381,7 +8111,6 @@ SQLITE_API int 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 @@ -8389,7 +8118,6 @@ SQLITE_API int 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 */ @@ -8411,8 +8139,7 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_TRACEFLAGS 31 #define SQLITE_TESTCTRL_TUNE 32 #define SQLITE_TESTCTRL_LOGEST 33 -#define SQLITE_TESTCTRL_USELONGDOUBLE 34 -#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */ +#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking @@ -8425,7 +8152,7 @@ SQLITE_API int sqlite3_test_control(int op, ...); ** The sqlite3_keyword_count() interface returns the number of distinct ** keywords understood by SQLite. ** -** The sqlite3_keyword_name(N,Z,L) interface finds the 0-based N-th keyword and +** The sqlite3_keyword_name(N,Z,L) interface finds the 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 sqlite3_keyword_name(N,Z,L) routine returns @@ -9868,7 +9595,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); ** [[SQLITE_VTAB_DIRECTONLY]]
    SQLITE_VTAB_DIRECTONLY
    **
    Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the -** the [xConnect] or [xCreate] methods of a [virtual table] implementation +** the [xConnect] or [xCreate] methods of a [virtual table] implmentation ** prohibits that virtual table from being used from within triggers and ** views. **
    @@ -9876,28 +9603,18 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); ** [[SQLITE_VTAB_INNOCUOUS]]
    SQLITE_VTAB_INNOCUOUS
    **
    Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the -** the [xConnect] or [xCreate] methods of a [virtual table] implementation +** the [xConnect] or [xCreate] methods of a [virtual table] implmentation ** 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. **
    -** -** [[SQLITE_VTAB_USES_ALL_SCHEMAS]]
    SQLITE_VTAB_USES_ALL_SCHEMAS
    -**
    Calls of the form -** [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. -**
    ** */ #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 @@ -9970,7 +9687,7 @@ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*); **
  • Otherwise, "BINARY" is returned. ** */ -SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); +SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int); /* ** CAPI3REF: Determine if a virtual table query is DISTINCT @@ -10004,45 +9721,24 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); **

  • ** ^(If the 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 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. +** 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. ** This mode is used for a DISTINCT query. **

  • -** ^(If the sqlite3_vtab_distinct() interface returns 3, that means the -** virtual table must return rows in the order defined by "aOrderBy" as -** if the 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 +** ^(If the 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 ** that have both DISTINCT and ORDER BY clauses. ** ** -**

    The following table summarizes the conditions under which the -** virtual table is allowed to set the "orderByConsumed" flag based on -** the value returned by sqlite3_vtab_distinct(). This table is a -** restatement of the previous four paragraphs: -** -** -** -**
    sqlite3_vtab_distinct() return value -** Rows are returned in aOrderBy order -** Rows with the same value in all aOrderBy columns are adjacent -** Duplicates over all colUsed columns may be omitted -**
    0yesyesno -**
    1noyesno -**
    2noyesyes -**
    3yesyesyes -**
    -** ** ^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" @@ -10079,7 +9775,7 @@ SQLITE_API int sqlite3_vtab_distinct(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 positive integer. ^(Then, under +** aConstraintUsage[].argvIndex to a postive 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 @@ -10148,20 +9844,21 @@ SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle); ** is undefined and probably harmful. ** ** The X parameter in a call to sqlite3_vtab_in_first(X,P) or -** sqlite3_vtab_in_next(X,P) should be one of the parameters to the +** sqlite3_vtab_in_next(X,P) must 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 [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_ERROR].)^ +** processing, then these routines return [SQLITE_MISUSE])^ or perhaps +** exhibit some other undefined or harmful behavior. ** ** ^(Use these routines to access all values on the right-hand side ** of the IN constraint using code like the following: ** **

     **    for(rc=sqlite3_vtab_in_first(pList, &pVal);
    -**        rc==SQLITE_OK && pVal;
    +**        rc==SQLITE_OK && pVal
     **        rc=sqlite3_vtab_in_next(pList, &pVal)
     **    ){
     **      // do something with pVal
    @@ -10259,10 +9956,6 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **
     ** 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).
    -**
     ** 
    ** [[SQLITE_SCANSTAT_NLOOP]]
    SQLITE_SCANSTAT_NLOOP
    **
    ^The [sqlite3_int64] variable pointed to by the V parameter will be @@ -10290,24 +9983,12 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN] ** description for the X-th loop. ** -** [[SQLITE_SCANSTAT_SELECTID]]
    SQLITE_SCANSTAT_SELECTID
    +** [[SQLITE_SCANSTAT_SELECTID]]
    SQLITE_SCANSTAT_SELECT
    **
    ^The "int" variable pointed to by the V parameter will be set to the -** 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]]
    SQLITE_SCANSTAT_PARENTID
    -**
    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]]
    SQLITE_SCANSTAT_NCYCLE
    -**
    The 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. +** "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. **
    */ #define SQLITE_SCANSTAT_NLOOP 0 @@ -10316,14 +9997,12 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** #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: sqlite3_stmt ** -** These interfaces return information about the predicted and measured +** This interface returns 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. @@ -10334,25 +10013,19 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** ** 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. -** -** 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 -** sqlite3_stmt_scanstatus() is equivalent to calling -** 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. +** 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. ** ** See also: [sqlite3_stmt_scanstatus_reset()] */ @@ -10362,19 +10035,6 @@ SQLITE_API int sqlite3_stmt_scanstatus( int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ void *pOut /* Result written here */ ); -SQLITE_API int sqlite3_stmt_scanstatus_v2( - 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 @@ -10465,10 +10125,6 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); ** function is not defined for operations on WITHOUT ROWID tables, or for ** DELETE operations on rowid tables. ** -** ^The 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 [sqlite3_preupdate_old()], [sqlite3_preupdate_new()], ** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces ** provide additional information about a preupdate event. These routines @@ -10508,7 +10164,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); ** When the [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 actually a write using the +** callback made with op==SQLITE_DELETE is actuall a write using the ** sqlite3_blob_write() API, the [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 @@ -10769,13 +10425,6 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const 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 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. @@ -10824,9 +10473,6 @@ SQLITE_API unsigned char *sqlite3_serialize( ** SQLite will try to increase the buffer size using 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 sqlite3_deserialize() interface will fail with SQLITE_BUSY if the ** database is currently in a read transaction or is involved in a backup ** operation. @@ -10835,13 +10481,6 @@ SQLITE_API unsigned char *sqlite3_serialize( ** S argument to 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 sqlite3_deserialize(D,S,P,N,M,F) to force the -** database file into rollback mode and work around this limitation. -** ** If 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 ** [sqlite3_free()] is invoked on argument P prior to returning. @@ -10891,19 +10530,6 @@ SQLITE_API int 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 @@ -11110,20 +10736,16 @@ SQLITE_API int sqlite3session_create( SQLITE_API void sqlite3session_delete(sqlite3_session *pSession); /* -** CAPI3REF: Configure a Session Object +** CAPIREF: Conigure a Session Object ** METHOD: sqlite3_session ** ** This method is used to configure a session object after it has been -** created. At present the only valid values for the second parameter are -** [SQLITE_SESSION_OBJCONFIG_SIZE] and [SQLITE_SESSION_OBJCONFIG_ROWID]. +** created. At present the only valid value for the second parameter is +** [SQLITE_SESSION_OBJCONFIG_SIZE]. ** -*/ -SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg); - -/* -** CAPI3REF: Options for sqlite3session_object_config +** Arguments for sqlite3session_object_config() ** -** The following values may passed as the the 2nd parameter to +** The following values may passed as the the 4th parameter to ** sqlite3session_object_config(). ** **
    SQLITE_SESSION_OBJCONFIG_SIZE
    @@ -11139,21 +10761,12 @@ SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg ** ** It is an error (SQLITE_MISUSE) to attempt to modify this setting after ** the first table has been attached to the session object. -** -**
    SQLITE_SESSION_OBJCONFIG_ROWID
    -** 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. */ -#define SQLITE_SESSION_OBJCONFIG_SIZE 1 -#define SQLITE_SESSION_OBJCONFIG_ROWID 2 +SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg); + +/* +*/ +#define SQLITE_SESSION_OBJCONFIG_SIZE 1 /* ** CAPI3REF: Enable Or Disable A Session Object @@ -11914,18 +11527,6 @@ SQLITE_API int sqlite3changeset_concat( ); -/* -** CAPI3REF: Upgrade the Schema of a Changeset/Patchset -*/ -SQLITE_API int sqlite3changeset_upgrade( - sqlite3 *db, - const char *zDb, - int nIn, const void *pIn, /* Input changeset */ - int *pnOut, void **ppOut /* OUT: Inverse of input */ -); - - - /* ** CAPI3REF: Changegroup Handle ** @@ -11972,38 +11573,6 @@ typedef struct sqlite3_changegroup sqlite3_changegroup; */ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp); -/* -** CAPI3REF: Add a Schema to a Changegroup -** METHOD: 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 -** 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 sqlite3changeset_apply(). Specifically, for each -** table in the changeset, there exists a database table with: -** -**
      -**
    • The name identified by the changeset, and -**
    • at least as many columns as recorded in the changeset, and -**
    • the primary key columns in the same position as recorded in -** the changeset. -**
    -** -** The output of the changegroup object always has the same schema as the -** database nominated using this function. In cases where changesets passed -** to 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 sqlite3changegroup_schema(sqlite3_changegroup*, sqlite3*, const char *zDb); - /* ** CAPI3REF: Add A Changeset To A Changegroup ** METHOD: sqlite3_changegroup @@ -12072,45 +11641,16 @@ SQLITE_API int sqlite3changegroup_schema(sqlite3_changegroup*, sqlite3*, const c ** 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. Except, if the changegroup -** object has been configured with a database schema using the -** 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. +** 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. ** -** 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. +** If no error occurs, SQLITE_OK is returned. */ SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); -/* -** CAPI3REF: Add A Single Change To A Changegroup -** METHOD: 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 [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 sqlite3changegroup_add_change( - sqlite3_changegroup*, - sqlite3_changeset_iter* -); - - - /* ** CAPI3REF: Obtain A Composite Changeset From A Changegroup ** METHOD: sqlite3_changegroup @@ -12359,30 +11899,9 @@ SQLITE_API int sqlite3changeset_apply_v2( ** Invert the changeset before applying it. This is equivalent to inverting ** a changeset using sqlite3changeset_invert() before applying it. It is ** an error to specify this flag with a patchset. -** -**
    SQLITE_CHANGESETAPPLY_IGNORENOOP
    -** 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: -**
      -**
    • a delete change if the row being deleted cannot be found, -**
    • an update change if the modified fields are already set to -** their new values in the conflicting row, or -**
    • an insert change if all fields of the conflicting row match -** the row being inserted. -**
    -** -**
    SQLITE_CHANGESETAPPLY_FKNOACTION
    -** 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 @@ -12915,8 +12434,8 @@ struct Fts5PhraseIter { ** EXTENSION API FUNCTIONS ** ** xUserData(pFts): -** Return a copy of the pUserData pointer passed to the xCreateFunction() -** API when the extension function was registered. +** Return a copy of the context pointer the extension function was +** registered with. ** ** xColumnTotalSize(pFts, iCol, pnToken): ** If parameter iCol is less than zero, set output variable *pnToken @@ -12948,11 +12467,8 @@ struct Fts5PhraseIter { ** created with the "columnsize=0" option. ** ** xColumnText: -** 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 +** 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 @@ -12962,10 +12478,8 @@ struct Fts5PhraseIter { ** Returns the number of phrases in the current query expression. ** ** xPhraseSize: -** 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. +** 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 @@ -12981,13 +12495,12 @@ 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(). If iIdx is less than zero or greater than -** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned. +** output by xInstCount(). ** -** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol +** Usually, output parameter *piPhrase is set to the phrase number, *piCol ** to the column in which it occurs and *piOff the token offset of the -** first token of the phrase. SQLITE_OK is returned if successful, or an -** error code (i.e. SQLITE_NOMEM) if an error occurs. +** first token of the phrase. Returns SQLITE_OK if successful, or an error +** code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. @@ -13013,10 +12526,6 @@ 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. @@ -13131,39 +12640,6 @@ 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 */ @@ -13201,13 +12677,6 @@ 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*); }; /* @@ -13402,8 +12871,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 (3)) or query -** text (method (2)), not both. Doing so will not cause any errors, but is +** provide synonyms when tokenizing document text (method (2)) or query +** text (method (3)), not both. Doing so will not cause any errors, but is ** inefficient. */ typedef struct Fts5Tokenizer Fts5Tokenizer; @@ -13451,7 +12920,7 @@ struct fts5_api { int (*xCreateTokenizer)( fts5_api *pApi, const char *zName, - void *pUserData, + void *pContext, fts5_tokenizer *pTokenizer, void (*xDestroy)(void*) ); @@ -13460,7 +12929,7 @@ struct fts5_api { int (*xFindTokenizer)( fts5_api *pApi, const char *zName, - void **ppUserData, + void **ppContext, fts5_tokenizer *pTokenizer ); @@ -13468,7 +12937,7 @@ struct fts5_api { int (*xCreateFunction)( fts5_api *pApi, const char *zName, - void *pUserData, + void *pContext, fts5_extension_function xFunction, void (*xDestroy)(void*) ); diff --git a/include/sqlite3ext.h b/include/sqlite3ext.h index 437cd3e..03b6f35 100644 --- a/include/sqlite3ext.h +++ b/include/sqlite3ext.h @@ -359,15 +359,10 @@ struct sqlite3_api_routines { const char *(*db_name)(sqlite3*,int); /* Version 3.40.0 and later */ int (*value_encoding)(sqlite3_value*); - /* Version 3.41.0 and later */ - int (*is_interrupted)(sqlite3*); - /* Version 3.43.0 and later */ - int (*stmt_explain)(sqlite3_stmt*,int); - /* Version 3.44.0 and later */ - void *(*get_clientdata)(sqlite3*,const char*); - int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*)); +#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK /* handle after drop table done */ int (*set_droptable_handle)(sqlite3*,void(*)(sqlite3*,const char*,const char*)); +#endif }; /* @@ -395,7 +390,7 @@ typedef int (*sqlite3_loadext_entry)( #ifdef SQLITE3_EXPORT_SYMBOLS extern const sqlite3_api_routines *sqlite3_export_symbols; #define sqlite3_api sqlite3_export_symbols -#endif /* SQLITE3_EXPORT_SYMBOLS */ +#endif #define sqlite3_aggregate_context sqlite3_api->aggregate_context #ifndef SQLITE_OMIT_DEPRECATED #define sqlite3_aggregate_count sqlite3_api->aggregate_count @@ -698,16 +693,11 @@ extern const sqlite3_api_routines *sqlite3_export_symbols; #define sqlite3_db_name sqlite3_api->db_name /* Version 3.40.0 and later */ #define sqlite3_value_encoding sqlite3_api->value_encoding -/* Version 3.41.0 and later */ -#define sqlite3_is_interrupted sqlite3_api->is_interrupted -/* Version 3.43.0 and later */ -#define sqlite3_stmt_explain sqlite3_api->stmt_explain -/* Version 3.44.0 and later */ -#define sqlite3_get_clientdata sqlite3_api->get_clientdata -#define sqlite3_set_clientdata sqlite3_api->set_clientdata +#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK /* handle after drop table done */ #define sqlite3_set_droptable_handle sqlite3_api->set_droptable_handle -#endif /* !defined(SQLITE_CORE) && (!defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE3_EXPORT_SYMBOLS)) */ +#endif +#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 diff --git a/include/sqlite3icu.h b/include/sqlite3icu.h index be58299..8c680bc 100644 --- a/include/sqlite3icu.h +++ b/include/sqlite3icu.h @@ -1,50 +1,50 @@ -/* -** 2001-09-15 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -*/ -#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) -/************** Include sqliteicu.h in the middle of main.c ******************/ -/************** Begin file sqliteicu.h ***************************************/ -/* -** 2008 May 26` -** -** 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 is used by programs that want to link against the -** ICU extension. All it does is declare the sqlite3IcuInit() interface. -*/ -#include "sqlite3sym.h" -#include "sqlite3tokenizer.h" - -#ifdef __cplusplus -extern "C" { -#endif - -SQLITE_API int sqlite3IcuInit(sqlite3 *db); - -/************** End of sqliteicu.h *******************************************/ -/************** Continuing where we left off in main.c ***********************/ -#endif - -#ifdef SQLITE_ENABLE_ICU -SQLITE_API void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); -#endif - -#ifdef __cplusplus -} /* end of the 'extern "C"' block */ -#endif \ No newline at end of file +/* +** 2001-09-15 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +*/ +#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) +/************** Include sqliteicu.h in the middle of main.c ******************/ +/************** Begin file sqliteicu.h ***************************************/ +/* +** 2008 May 26` +** +** 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 is used by programs that want to link against the +** ICU extension. All it does is declare the sqlite3IcuInit() interface. +*/ +#include "sqlite3sym.h" +#include "sqlite3tokenizer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +SQLITE_API int sqlite3IcuInit(sqlite3 *db); + +/************** End of sqliteicu.h *******************************************/ +/************** Continuing where we left off in main.c ***********************/ +#endif + +#ifdef SQLITE_ENABLE_ICU +SQLITE_API void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); +#endif + +#ifdef __cplusplus +} /* end of the 'extern "C"' block */ +#endif \ No newline at end of file diff --git a/include/sqlite3tokenizer.h b/include/sqlite3tokenizer.h index a7f10ca..b1a1f09 100644 --- a/include/sqlite3tokenizer.h +++ b/include/sqlite3tokenizer.h @@ -1,145 +1,145 @@ -/* -** 2001-09-15 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -*/ -/* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time. -** If tokenizers are to be allowed to call sqlite3_*() functions, then -** we will need a way to register the API consistently. -*/ -/* #include "sqlite3.h" */ - -/* -** Structures used by the tokenizer interface. When a new tokenizer -** implementation is registered, the caller provides a pointer to -** an sqlite3_tokenizer_module containing pointers to the callback -** functions that make up an implementation. -** -** When an fts3 table is created, it passes any arguments passed to -** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the -** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer -** implementation. The xCreate() function in turn returns an -** sqlite3_tokenizer structure representing the specific tokenizer to -** be used for the fts3 table (customized by the tokenizer clause arguments). -** -** To tokenize an input buffer, the sqlite3_tokenizer_module.xOpen() -** method is called. It returns an sqlite3_tokenizer_cursor object -** that may be used to tokenize a specific input buffer based on -** the tokenization rules supplied by a specific sqlite3_tokenizer -** object. -*/ -typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module; -typedef struct sqlite3_tokenizer sqlite3_tokenizer; -typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor; - -struct sqlite3_tokenizer_module { - - /* - ** Structure version. Should always be set to 0 or 1. - */ - int iVersion; - - /* - ** Create a new tokenizer. The values in the argv[] array are the - ** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL - ** TABLE statement that created the fts3 table. For example, if - ** the following SQL is executed: - ** - ** CREATE .. USING fts3( ... , tokenizer arg1 arg2) - ** - ** then argc is set to 2, and the argv[] array contains pointers - ** to the strings "arg1" and "arg2". - ** - ** This method should return either SQLITE_OK (0), or an SQLite error - ** code. If SQLITE_OK is returned, then *ppTokenizer should be set - ** to point at the newly created tokenizer structure. The generic - ** sqlite3_tokenizer.pModule variable should not be initialized by - ** this callback. The caller will do so. - */ - int (*xCreate)( - int argc, /* Size of argv array */ - const char *const*argv, /* Tokenizer argument strings */ - sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ - ); - - /* - ** Destroy an existing tokenizer. The fts3 module calls this method - ** exactly once for each successful call to xCreate(). - */ - int (*xDestroy)(sqlite3_tokenizer *pTokenizer); - - /* - ** Create a tokenizer cursor to tokenize an input buffer. The caller - ** is responsible for ensuring that the input buffer remains valid - ** until the cursor is closed (using the xClose() method). - */ - int (*xOpen)( - sqlite3_tokenizer *pTokenizer, /* Tokenizer object */ - const char *pInput, int nBytes, /* Input buffer */ - sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */ - ); - - /* - ** Destroy an existing tokenizer cursor. The fts3 module calls this - ** method exactly once for each successful call to xOpen(). - */ - int (*xClose)(sqlite3_tokenizer_cursor *pCursor); - - /* - ** Retrieve the next token from the tokenizer cursor pCursor. This - ** method should either return SQLITE_OK and set the values of the - ** "OUT" variables identified below, or SQLITE_DONE to indicate that - ** the end of the buffer has been reached, or an SQLite error code. - ** - ** *ppToken should be set to point at a buffer containing the - ** normalized version of the token (i.e. after any case-folding and/or - ** stemming has been performed). *pnBytes should be set to the length - ** of this buffer in bytes. The input text that generated the token is - ** identified by the byte offsets returned in *piStartOffset and - ** *piEndOffset. *piStartOffset should be set to the index of the first - ** byte of the token in the input buffer. *piEndOffset should be set - ** to the index of the first byte just past the end of the token in - ** the input buffer. - ** - ** The buffer *ppToken is set to point at is managed by the tokenizer - ** implementation. It is only required to be valid until the next call - ** to xNext() or xClose(). - */ - /* TODO(shess) current implementation requires pInput to be - ** nul-terminated. This should either be fixed, or pInput/nBytes - ** should be converted to zInput. - */ - int (*xNext)( - sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */ - const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */ - int *piStartOffset, /* OUT: Byte offset of token in input buffer */ - int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */ - int *piPosition /* OUT: Number of tokens returned before this one */ - ); - - /*********************************************************************** - ** Methods below this point are only available if iVersion>=1. - */ - - /* - ** Configure the language id of a tokenizer cursor. - */ - int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid); -}; - -struct sqlite3_tokenizer { - const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */ - /* Tokenizer implementations will typically add additional fields */ -}; - -struct sqlite3_tokenizer_cursor { - sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */ - /* Tokenizer implementations will typically add additional fields */ -}; \ No newline at end of file +/* +** 2001-09-15 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +*/ +/* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time. +** If tokenizers are to be allowed to call sqlite3_*() functions, then +** we will need a way to register the API consistently. +*/ +/* #include "sqlite3.h" */ + +/* +** Structures used by the tokenizer interface. When a new tokenizer +** implementation is registered, the caller provides a pointer to +** an sqlite3_tokenizer_module containing pointers to the callback +** functions that make up an implementation. +** +** When an fts3 table is created, it passes any arguments passed to +** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the +** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer +** implementation. The xCreate() function in turn returns an +** sqlite3_tokenizer structure representing the specific tokenizer to +** be used for the fts3 table (customized by the tokenizer clause arguments). +** +** To tokenize an input buffer, the sqlite3_tokenizer_module.xOpen() +** method is called. It returns an sqlite3_tokenizer_cursor object +** that may be used to tokenize a specific input buffer based on +** the tokenization rules supplied by a specific sqlite3_tokenizer +** object. +*/ +typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module; +typedef struct sqlite3_tokenizer sqlite3_tokenizer; +typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor; + +struct sqlite3_tokenizer_module { + + /* + ** Structure version. Should always be set to 0 or 1. + */ + int iVersion; + + /* + ** Create a new tokenizer. The values in the argv[] array are the + ** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL + ** TABLE statement that created the fts3 table. For example, if + ** the following SQL is executed: + ** + ** CREATE .. USING fts3( ... , tokenizer arg1 arg2) + ** + ** then argc is set to 2, and the argv[] array contains pointers + ** to the strings "arg1" and "arg2". + ** + ** This method should return either SQLITE_OK (0), or an SQLite error + ** code. If SQLITE_OK is returned, then *ppTokenizer should be set + ** to point at the newly created tokenizer structure. The generic + ** sqlite3_tokenizer.pModule variable should not be initialized by + ** this callback. The caller will do so. + */ + int (*xCreate)( + int argc, /* Size of argv array */ + const char *const*argv, /* Tokenizer argument strings */ + sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ + ); + + /* + ** Destroy an existing tokenizer. The fts3 module calls this method + ** exactly once for each successful call to xCreate(). + */ + int (*xDestroy)(sqlite3_tokenizer *pTokenizer); + + /* + ** Create a tokenizer cursor to tokenize an input buffer. The caller + ** is responsible for ensuring that the input buffer remains valid + ** until the cursor is closed (using the xClose() method). + */ + int (*xOpen)( + sqlite3_tokenizer *pTokenizer, /* Tokenizer object */ + const char *pInput, int nBytes, /* Input buffer */ + sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */ + ); + + /* + ** Destroy an existing tokenizer cursor. The fts3 module calls this + ** method exactly once for each successful call to xOpen(). + */ + int (*xClose)(sqlite3_tokenizer_cursor *pCursor); + + /* + ** Retrieve the next token from the tokenizer cursor pCursor. This + ** method should either return SQLITE_OK and set the values of the + ** "OUT" variables identified below, or SQLITE_DONE to indicate that + ** the end of the buffer has been reached, or an SQLite error code. + ** + ** *ppToken should be set to point at a buffer containing the + ** normalized version of the token (i.e. after any case-folding and/or + ** stemming has been performed). *pnBytes should be set to the length + ** of this buffer in bytes. The input text that generated the token is + ** identified by the byte offsets returned in *piStartOffset and + ** *piEndOffset. *piStartOffset should be set to the index of the first + ** byte of the token in the input buffer. *piEndOffset should be set + ** to the index of the first byte just past the end of the token in + ** the input buffer. + ** + ** The buffer *ppToken is set to point at is managed by the tokenizer + ** implementation. It is only required to be valid until the next call + ** to xNext() or xClose(). + */ + /* TODO(shess) current implementation requires pInput to be + ** nul-terminated. This should either be fixed, or pInput/nBytes + ** should be converted to zInput. + */ + int (*xNext)( + sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */ + const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */ + int *piStartOffset, /* OUT: Byte offset of token in input buffer */ + int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */ + int *piPosition /* OUT: Number of tokens returned before this one */ + ); + + /*********************************************************************** + ** Methods below this point are only available if iVersion>=1. + */ + + /* + ** Configure the language id of a tokenizer cursor. + */ + int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid); +}; + +struct sqlite3_tokenizer { + const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */ + /* Tokenizer implementations will typically add additional fields */ +}; + +struct sqlite3_tokenizer_cursor { + sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */ + /* Tokenizer implementations will typically add additional fields */ +}; \ No newline at end of file diff --git a/patch/0001-BaselineWithHistoryOH.patch b/patch/0001-BaselineWithHistoryOH.patch deleted file mode 100644 index ef9b8cf..0000000 --- a/patch/0001-BaselineWithHistoryOH.patch +++ /dev/null @@ -1,3639 +0,0 @@ -From f2e21aa63fb875f21e963ba046850e8f9dd4a86d Mon Sep 17 00:00:00 2001 -From: linzhuobin1 -Date: Mon, 24 Feb 2025 18:36:42 +0800 -Subject: [PATCH] IssueNo:#IBNXAW Description:Sqlite baseline update to 3.46.1 - with patch-1-1 Sig: SIG_DataManagement Feature or Bugfix:Feature Binary - Source:No/Yes TDD:Pass/Fail/NA XTS:Pass/Fail/NA Pretest:Pass/Fail/NA - -Signed-off-by: linzhuobin1 ---- - src/sqlite3.c | 2841 ++++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 2824 insertions(+), 17 deletions(-) - -diff --git a/src/sqlite3.c b/src/sqlite3.c -index 946815f..d2bfc23 100644 ---- a/src/sqlite3.c -+++ b/src/sqlite3.c -@@ -881,6 +881,7 @@ SQLITE_API int sqlite3_exec( - #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_WARNING_DUMP (SQLITE_WARNING | (2<<8)) - #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) - #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) - #define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */ -@@ -2845,6 +2846,11 @@ struct sqlite3_mem_methods { - #define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */ - #define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */ - -+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -+#define SQLITE_DBCONFIG_SET_SHAREDBLOCK 2004 -+#define SQLITE_DBCONFIG_USE_SHAREDBLOCK 2005 -+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ -+ - /* - ** CAPI3REF: Enable Or Disable Extended Result Codes - ** METHOD: sqlite3 -@@ -5316,6 +5322,10 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); - */ - SQLITE_API int sqlite3_step(sqlite3_stmt*); - -+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK -+SQLITE_API int sqlite3_set_droptable_handle(sqlite3*, void (*xFunc)(sqlite3*,const char*,const char*)); -+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ -+ - /* - ** CAPI3REF: Number of columns in a result set - ** METHOD: sqlite3_stmt -@@ -6716,6 +6726,44 @@ SQLITE_API int sqlite3_collation_needed16( - void(*)(void*,sqlite3*,int eTextRep,const void*) - ); - -+#ifdef SQLITE_HAS_CODEC -+/* -+** Specify the key for an encrypted database. This routine should be -+** called right after sqlite3_open(). -+** -+** The code to implement this API is not available in the public release -+** of SQLite. -+*/ -+SQLITE_API int sqlite3_key( -+ sqlite3 *db, /* Database to be rekeyed */ -+ const void *pKey, int nKey /* The key */ -+); -+SQLITE_API int sqlite3_key_v2( -+ sqlite3 *db, /* Database to be rekeyed */ -+ const char *zDbName, /* Name of the database */ -+ const void *pKey, int nKey /* The key */ -+); -+ -+/* -+** Change the key on an open database. If the current database is not -+** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the -+** database is decrypted. -+** -+** The code to implement this API is not available in the public release -+** of SQLite. -+*/ -+SQLITE_API int sqlite3_rekey( -+ sqlite3 *db, /* Database to be rekeyed */ -+ const void *pKey, int nKey /* The new key */ -+); -+SQLITE_API int sqlite3_rekey_v2( -+ sqlite3 *db, /* Database to be rekeyed */ -+ const char *zDbName, /* Name of the database */ -+ const void *pKey, int nKey /* The new key */ -+); -+ -+#endif /* SQLITE_HAS_CODEC */ -+ - #ifdef SQLITE_ENABLE_CEROD - /* - ** Specify the activation key for a CEROD database. Unless -@@ -10162,6 +10210,27 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); - */ - SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); - -+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -+typedef struct Sqlite3SharedBlockMethods Sqlite3SharedBlockMethods; -+struct Sqlite3SharedBlockMethods { -+ int iVersion; -+ void* pContext; -+ int countAllRows; -+ int startPos; -+ int requiredPos; -+ int (*xAddRow)(void* pCtx, int addedRows); -+ int (*xReset)(void* pCtx, int startPos); -+ int (*xFinish)(void* pCtx, int addedRows, int totalRows); -+ int (*xPutString)(void *pCtx, int addedRows, int column, const char* text, int len); -+ int (*xPutLong)(void *pCtx, int addedRows, int column, sqlite3_int64 value); -+ int (*xPutDouble)(void *pCtx, int addedRows, int column, double value); -+ int (*xPutBlob)(void *pCtx, int addedRows, int column, const void* blob, int len); -+ int (*xPutNull)(void *pCtx, int addedRows, int column); -+ int (*xPutOther)(void *pCtx, int addedRows, int column); -+ /* Additional methods may be added in future releases */ -+}; -+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ -+ - /* - ** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE - ** -@@ -10221,7 +10290,7 @@ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*); - **
  • Otherwise, "BINARY" is returned. - ** - */ --SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); -+SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int); - - /* - ** CAPI3REF: Determine if a virtual table query is DISTINCT -@@ -15896,6 +15965,9 @@ SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); - /* Functions used to configure a Pager object. */ - SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *); - SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int); -+#ifdef SQLITE_HAS_CODEC -+SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager*, Pager*); -+#endif /* SQLITE_HAS_CODEC */ - SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager*, Pgno); - SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int); - SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int); -@@ -15992,6 +16064,10 @@ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno); - - SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16); - -+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) -+SQLITE_PRIVATE void *sqlite3PagerCodec(DbPage *); -+#endif /* defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) */ -+ - /* Functions to support testing and debugging. */ - #if !defined(NDEBUG) || defined(SQLITE_TEST) - SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*); -@@ -17632,6 +17708,21 @@ SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**); - */ - #define SQLITE_MAX_DB (SQLITE_MAX_ATTACHED+2) - -+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK -+typedef void (*sqlite3_xDropTableHandle)(sqlite3*, const char*, const char*); -+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ -+ -+#if defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) -+typedef struct CodecParameter { -+ int kdfIter; -+ int pageSize; -+ u8 cipher; -+ u8 hmacAlgo; -+ u8 kdfAlgo; -+ u8 reserved; -+} CodecParameter; -+#endif /* defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) */ -+ - /* - ** Each database connection is an instance of the following structure. - */ -@@ -17776,6 +17867,15 @@ struct sqlite3 { - #ifdef SQLITE_USER_AUTHENTICATION - sqlite3_userauth auth; /* User authentication information */ - #endif -+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK -+ unsigned int isDropTable; -+ char *mDropTableName; -+ char *mDropSchemaName; -+ sqlite3_xDropTableHandle xDropTableHandle; /* User drop table callback */ -+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ -+#if defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) -+ CodecParameter codecParm; -+#endif /* defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) */ - }; - - /* -@@ -20889,7 +20989,14 @@ SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u32,Select*); - SQLITE_PRIVATE void sqlite3AddReturning(Parse*,ExprList*); - SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*, - sqlite3_vfs**,char**,char **); -+#ifndef SQLITE_HAS_CODEC - #define sqlite3CodecQueryParameters(A,B,C) 0 -+#else -+SQLITE_PRIVATE int sqlite3CodecQueryParameters(sqlite3*,const char*,const char*); -+#endif /* !SQLITE_HAS_CODEC */ -+#if defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) -+SQLITE_PRIVATE void sqlite3CodecResetParameters(CodecParameter *p); -+#endif /* defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) */ - SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*); - - #ifdef SQLITE_UNTESTABLE -@@ -21873,6 +21980,10 @@ SQLITE_API extern int sqlite3_open_file_count; - #define OpenCounter(X) - #endif /* defined(SQLITE_TEST) */ - -+#ifdef FDSAN_ENABLE -+#define SQLITE_FDSAN_TAG 5351 -+#endif /* FDSAN_ENABLE */ -+ - #endif /* !defined(_OS_COMMON_H_) */ - - /************** End of os_common.h *******************************************/ -@@ -22258,6 +22369,9 @@ static const char * const sqlite3azCompileOpt[] = { - #ifdef SQLITE_FTS5_NO_WITHOUT_ROWID - "FTS5_NO_WITHOUT_ROWID", - #endif -+#if SQLITE_HAS_CODEC -+ "HAS_CODEC", -+#endif - #if HAVE_ISNAN || SQLITE_HAVE_ISNAN - "HAVE_ISNAN", - #endif -@@ -22266,6 +22380,9 @@ static const char * const sqlite3azCompileOpt[] = { - "HOMEGROWN_RECURSIVE_MUTEX=" CTIMEOPT_VAL(SQLITE_HOMEGROWN_RECURSIVE_MUTEX), - # endif - #endif -+#if SQLITE_SHARED_BLOCK_OPTIMIZATION -+ "SHARED_BLOCK_OPTIMIZATION", -+#endif - #ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS - "IGNORE_AFP_LOCK_ERRORS", - #endif -@@ -22841,9 +22958,16 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { - ** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally - ** disabled. The default value may be changed by compiling with the - ** SQLITE_USE_URI symbol defined. -+** -+** URI filenames are enabled by default if SQLITE_HAS_CODEC is -+** enabled. - */ - #ifndef SQLITE_USE_URI --# define SQLITE_USE_URI 0 -+#ifndef SQLITE_HAS_CODEC -+#define SQLITE_USE_URI 0 -+#else -+#define SQLITE_USE_URI 1 -+#endif /* !SQLITE_HAS_CODEC */ - #endif - - /* EVIDENCE-OF: R-38720-18127 The default setting is determined by the -@@ -23615,6 +23739,13 @@ struct Vdbe { - int nScan; /* Entries in aScan[] */ - ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */ - #endif -+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -+ Sqlite3SharedBlockMethods *pSharedBlock; -+ int totalRows; -+ int blockFull; -+ int startPos; -+ int addedRows; -+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ - }; - - /* -@@ -32452,7 +32583,11 @@ SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ - */ - static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ - StrAccum acc; /* String accumulator */ -+#ifndef LOG_DUMP - char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ -+#else -+char zMsg[SQLITE_PRINT_BUF_SIZE*10]; /* Complete log message */ -+#endif /* !LOG_DUMP */ - - sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); - sqlite3_str_vappendf(&acc, zFormat, ap); -@@ -36425,7 +36560,7 @@ SQLITE_PRIVATE u8 sqlite3HexToInt(int h){ - return (u8)(h & 0xf); - } - --#if !defined(SQLITE_OMIT_BLOB_LITERAL) -+#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) - /* - ** Convert a BLOB literal of the form "x'hhhhhh'" into its binary - ** value. Return a pointer to its binary value. Space to hold the -@@ -36446,7 +36581,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){ - } - return zBlob; - } --#endif /* !SQLITE_OMIT_BLOB_LITERAL */ -+#endif /* !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) */ - - /* - ** Log an error that is an API call on a connection pointer that should -@@ -38754,6 +38889,29 @@ static pid_t randomnessPid = 0; - #define F2FS_FEATURE_ATOMIC_WRITE 0x0004 - #endif /* __linux__ */ - -+#ifdef HARMONY_OS -+#define HMFS_MONITOR_FL 0x00000002 -+#define HMFS_IOCTL_HW_GET_FLAGS _IOR(0xf5, 70, unsigned int) -+#define HMFS_IOCTL_HW_SET_FLAGS _IOR(0xf5, 71, unsigned int) -+ -+static void enableDbFileDelMonitor(int32_t fd) -+{ -+ unsigned int flags = 0; -+ int ret = ioctl(fd, HMFS_IOCTL_HW_GET_FLAGS, &flags); -+ if (ret < 0) { -+ return; -+ } -+ if (flags & HMFS_MONITOR_FL) { -+ return; -+ } -+ flags |= HMFS_MONITOR_FL; -+ ret = ioctl(fd, HMFS_IOCTL_HW_SET_FLAGS, &flags); -+ if (ret < 0) { -+ sqlite3_log(SQLITE_WARNING, "Fd %d enable del monitor go wrong, errno = %d", fd, errno); -+ } -+} -+ -+#endif /* HARMONY_OS */ - - /* - ** Different Unix systems declare open() in different ways. Same use -@@ -38764,7 +38922,29 @@ static pid_t randomnessPid = 0; - ** which always has the same well-defined interface. - */ - static int posixOpen(const char *zFile, int flags, int mode){ -- return open(zFile, flags, mode); -+ int fd = open(zFile, flags, mode); -+#ifdef FDSAN_ENABLE -+ if( fd >= 0 ){ -+ fdsan_exchange_owner_tag(fd, 0, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, SQLITE_FDSAN_TAG)); -+ } -+#endif /* FDSAN_ENABLE */ -+#ifdef HARMONY_OS -+ if( fd >= 0 ){ -+ enableDbFileDelMonitor(fd); -+ } -+#endif /* HARMONY_OS */ -+ return fd; -+} -+ -+/* -+** Change close to posixClose, use fdsan_close_with_tag when fdsan enable. -+*/ -+static int posixClose(int fd) { -+#ifdef FDSAN_ENABLE -+ return fdsan_close_with_tag(fd, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, SQLITE_FDSAN_TAG)); -+#else -+ return close(fd); -+#endif /* FDSAN_ENABLE */ - } - - /* Forward reference */ -@@ -38785,7 +38965,7 @@ static struct unix_syscall { - { "open", (sqlite3_syscall_ptr)posixOpen, 0 }, - #define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent) - -- { "close", (sqlite3_syscall_ptr)close, 0 }, -+ { "close", (sqlite3_syscall_ptr)posixClose, 0 }, - #define osClose ((int(*)(int))aSyscall[1].pCurrent) - - { "access", (sqlite3_syscall_ptr)access, 0 }, -@@ -39789,6 +39969,9 @@ static int findInodeInfo( - #if defined(EOVERFLOW) && defined(SQLITE_DISABLE_LFS) - if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS; - #endif -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_IOERR, "findInodeInfo-osFstat, fd[%d], errno[%d], osFstat[%d]", fd, errno, rc); -+#endif /* LOG_DUMP */ - return SQLITE_IOERR; - } - -@@ -39807,11 +39990,17 @@ static int findInodeInfo( - do{ rc = osWrite(fd, "S", 1); }while( rc<0 && errno==EINTR ); - if( rc!=1 ){ - storeLastErrno(pFile, errno); -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_IOERR, "findInodeInfo-osWrite, fd[%d], errno[%d], osFstat[%d]", fd, errno, rc); -+#endif /* LOG_DUMP */ - return SQLITE_IOERR; - } - rc = osFstat(fd, &statbuf); - if( rc!=0 ){ - storeLastErrno(pFile, errno); -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_IOERR, "findInodeInfo-msdos-osFstat, fd[%d], errno[%d], osFstat[%d]", fd, errno, rc); -+#endif /* LOG_DUMP */ - return SQLITE_IOERR; - } - } -@@ -40973,6 +41162,9 @@ static int flockUnlock(sqlite3_file *id, int eFileLock) { - #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS - return SQLITE_OK; - #endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_IOERR_UNLOCK, "IOERR_UNLOCK fd[%d], eFileLock[%d]", pFile->h, eFileLock); -+#endif /* LOG_DUMP */ - return SQLITE_IOERR_UNLOCK; - }else{ - pFile->eFileLock = NO_LOCK; -@@ -41785,8 +41977,14 @@ static int unixRead( - #ifdef EDEVERR - case EDEVERR: - #endif -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_IOERR_CORRUPTFS, "unixRead-EDEVERR, fd:[%d], amt[%d], got[%d], offset[%lld]", pFile->h, amt, got, offset); -+#endif /* LOG_DUMP */ - return SQLITE_IOERR_CORRUPTFS; - } -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_IOERR_READ, "unixRead-got<0, fd: [%d], amt[%d], got[%d], offset[%lld]", pFile->h, amt, got, offset); -+#endif /* LOG_DUMP */ - return SQLITE_IOERR_READ; - }else{ - storeLastErrno(pFile, 0); /* not a system error */ -@@ -41928,9 +42126,19 @@ static int unixWrite( - if( amt>wrote ){ - if( wrote<0 && pFile->lastErrno!=ENOSPC ){ - /* lastErrno set by seekAndWrite */ -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_IOERR_WRITE, -+ "unixWrite, lastErrno set by seekAndWrite, fd[%d], offset[%lld], wrote[%d], amt[%d], lastErrno[%d]", -+ pFile->h, offset, wrote, amt, pFile->lastErrno); -+#endif /* LOG_DUMP */ - return SQLITE_IOERR_WRITE; - }else{ - storeLastErrno(pFile, 0); /* not a system error */ -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_FULL, -+ "unixWrite, not a system error, fd[%d], offset[%lld], wrote[%d], amt[%d], lastErrno[%d]", -+ pFile->h, offset, wrote, amt, pFile->lastErrno); -+#endif /* LOG_DUMP */ - return SQLITE_FULL; - } - } -@@ -42284,7 +42492,14 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ - do{ - err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size); - }while( err==EINTR ); -- if( err && err!=EINVAL ) return SQLITE_IOERR_WRITE; -+ if( err && err!=EINVAL ) { -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_IOERR_WRITE, -+ "fcntlSizeHint-fallocate, fd[%d], bufSize[%lld], nSize[%lld] err[%d]", -+ pFile->h, buf.st_size, nSize, err); -+#endif /* LOG_DUMP */ -+ return SQLITE_IOERR_WRITE; -+ } - #else - /* If the OS does not have posix_fallocate(), fake it. Write a - ** single byte to the last byte in each block that falls entirely -@@ -42303,7 +42518,14 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ - for(/*no-op*/; iWrite=nSize ) iWrite = nSize - 1; - nWrite = seekAndWrite(pFile, iWrite, "", 1); -- if( nWrite!=1 ) return SQLITE_IOERR_WRITE; -+ if( nWrite!=1 ) { -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_IOERR_WRITE, -+ "fcntlSizeHint-seekAndWrite, fd[%d], nWrite[%d], nSize[%d], nBlk[%d], iWrite[%lld]", -+ pFile->h, nWrite, nSize, nBlk, iWrite); -+#endif /* LOG_DUMP */ -+ return SQLITE_IOERR_WRITE; -+ } - } - #endif - } -@@ -42358,14 +42580,29 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ - #if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) - case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: { - int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE); -+#ifdef LOG_DUMP -+ if( rc ){ -+ sqlite3_log(SQLITE_IOERR_BEGIN_ATOMIC, "unixFileControl-begin, fd[%d], op[%d]", pFile->h, op); -+ } -+#endif /* LOG_DUMP */ - return rc ? SQLITE_IOERR_BEGIN_ATOMIC : SQLITE_OK; - } - case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: { - int rc = osIoctl(pFile->h, F2FS_IOC_COMMIT_ATOMIC_WRITE); -+#ifdef LOG_DUMP -+ if( rc ){ -+ sqlite3_log(SQLITE_IOERR_COMMIT_ATOMIC, "unixFileControl-commit, fd[%d], op[%d]", pFile->h, op); -+ } -+#endif /* LOG_DUMP */ - return rc ? SQLITE_IOERR_COMMIT_ATOMIC : SQLITE_OK; - } - case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: { - int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE); -+#ifdef LOG_DUMP -+ if( rc ){ -+ sqlite3_log(SQLITE_IOERR_ROLLBACK_ATOMIC, "unixFileControl-rollback, fd[%d], op[%d]", pFile->h, op); -+ } -+#endif /* LOG_DUMP */ - return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK; - } - #endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ -@@ -43378,9 +43615,19 @@ static int unixShmLock( - int *aLock; - - p = pDbFd->pShm; -- if( p==0 ) return SQLITE_IOERR_SHMLOCK; -+ if( p==0 ) { -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_IOERR_SHMLOCK, "unixShmLock-pShm, fd[%d], ofst[%d], n[%d], flags[%d]", pDbFd->h, ofst, n, flags); -+#endif -+ return SQLITE_IOERR_SHMLOCK; -+ } - pShmNode = p->pShmNode; -- if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK; -+ if( NEVER(pShmNode==0) ) { -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_IOERR_SHMLOCK, "unixShmLock-pShmNode, fd[%d], ofst[%d], n[%d], flags[%d]", pDbFd->h, ofst, n, flags); -+#endif -+ return SQLITE_IOERR_SHMLOCK; -+ } - aLock = pShmNode->aLock; - - assert( pShmNode==pDbFd->pInode->pShmNode ); -@@ -44827,6 +45074,9 @@ static int unixOpen( - if( fstatfs(fd, &fsInfo) == -1 ){ - storeLastErrno(p, errno); - robust_close(p, fd, __LINE__); -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_IOERR_ACCESS, "unixOpen, fd[%d], flags[%d], errno[%d]", fd, errno, flags); -+#endif /* LOG_DUMP */ - return SQLITE_IOERR_ACCESS; - } - if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) { -@@ -44967,6 +45217,8 @@ static int unixAccess( - return SQLITE_OK; - } - -+#ifndef HARMONY_OS -+ - /* - ** A pathname under construction - */ -@@ -45097,6 +45349,187 @@ static int unixFullPathname( - return SQLITE_OK; - } - -+#else -+ -+/* -+** If the last component of the pathname in z[0]..z[j-1] is something -+** other than ".." then back it out and return true. If the last -+** component is empty or if it is ".." then return false. -+*/ -+static int unixBackupDir(const char *z, int *pJ){ -+ int j = *pJ; -+ int i; -+ if( j<=0 ) return 0; -+ for(i=j-1; i>0 && z[i-1]!='/'; i--){} -+ if( i==0 ) return 0; -+ if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0; -+ *pJ = i-1; -+ return 1; -+} -+ -+/* -+** Convert a relative pathname into a full pathname. Also -+** simplify the pathname as follows: -+** -+** Remove all instances of /./ -+** Remove all isntances of /X/../ for any X -+*/ -+static int mkFullPathname( -+ const char *zPath, /* Input path */ -+ char *zOut, /* Output buffer */ -+ int nOut /* Allocated size of buffer zOut */ -+){ -+ int nPath = sqlite3Strlen30(zPath); -+ int iOff = 0; -+ int i, j; -+ if( zPath[0]!='/' ){ -+ if( osGetcwd(zOut, nOut-2)==0 ){ -+ return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); -+ } -+ iOff = sqlite3Strlen30(zOut); -+ zOut[iOff++] = '/'; -+ } -+ if( (iOff+nPath+1)>nOut ){ -+ /* SQLite assumes that xFullPathname() nul-terminates the output buffer -+ ** even if it returns an error. */ -+ zOut[iOff] = '\0'; -+ return SQLITE_CANTOPEN_BKPT; -+ } -+ sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath); -+ -+ /* Remove duplicate '/' characters. Except, two // at the beginning -+ ** of a pathname is allowed since this is important on windows. */ -+ for(i=j=1; zOut[i]; i++){ -+ zOut[j++] = zOut[i]; -+ while( zOut[i]=='/' && zOut[i+1]=='/' ) i++; -+ } -+ zOut[j] = 0; -+ -+ assert( zOut[0]=='/' ); -+ for(i=j=0; zOut[i]; i++){ -+ if( zOut[i]=='/' ){ -+ /* Skip over internal "/." directory components */ -+ if( zOut[i+1]=='.' && zOut[i+2]=='/' ){ -+ i += 1; -+ continue; -+ } -+ -+ /* If this is a "/.." directory component then back out the -+ ** previous term of the directory if it is something other than "..". -+ */ -+ if( zOut[i+1]=='.' -+ && zOut[i+2]=='.' -+ && zOut[i+3]=='/' -+ && unixBackupDir(zOut, &j) -+ ){ -+ i += 2; -+ continue; -+ } -+ } -+ if( ALWAYS(j>=0) ) zOut[j] = zOut[i]; -+ j++; -+ } -+ if( NEVER(j==0) ) zOut[j++] = '/'; -+ zOut[j] = 0; -+ return SQLITE_OK; -+} -+ -+/* -+** Turn a relative pathname into a full pathname. The relative path -+** is stored as a nul-terminated string in the buffer pointed to by -+** zPath. -+** -+** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes -+** (in this case, MAX_PATHNAME bytes). The full-path is written to -+** this buffer before returning. -+*/ -+static int unixFullPathname( -+ sqlite3_vfs *pVfs, /* Pointer to vfs object */ -+ const char *zPath, /* Possibly relative input path */ -+ int nOut, /* Size of output buffer in bytes */ -+ char *zOut /* Output buffer */ -+){ -+#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT) -+ return mkFullPathname(zPath, zOut, nOut); -+#else -+ int rc = SQLITE_OK; -+ int nByte; -+ int nLink = 0; /* Number of symbolic links followed so far */ -+ const char *zIn = zPath; /* Input path for each iteration of loop */ -+ char *zDel = 0; -+ -+ assert( pVfs->mxPathname==MAX_PATHNAME ); -+ UNUSED_PARAMETER(pVfs); -+ -+ /* It's odd to simulate an io-error here, but really this is just -+ ** using the io-error infrastructure to test that SQLite handles this -+ ** function failing. This function could fail if, for example, the -+ ** current working directory has been unlinked. -+ */ -+ SimulateIOError( return SQLITE_ERROR ); -+ -+ do { -+ -+ /* Call stat() on path zIn. Set bLink to true if the path is a symbolic -+ ** link, or false otherwise. */ -+ int bLink = 0; -+ struct stat buf; -+ if( osLstat(zIn, &buf)!=0 ){ -+ if( errno!=ENOENT ){ -+ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn); -+ } -+ }else{ -+ bLink = S_ISLNK(buf.st_mode); -+ } -+ -+ if( bLink ){ -+ nLink++; -+ if( zDel==0 ){ -+ zDel = sqlite3_malloc(nOut); -+ if( zDel==0 ) rc = SQLITE_NOMEM_BKPT; -+ }else if( nLink>=SQLITE_MAX_SYMLINKS ){ -+ rc = SQLITE_CANTOPEN_BKPT; -+ } -+ -+ if( rc==SQLITE_OK ){ -+ nByte = osReadlink(zIn, zDel, nOut-1); -+ if( nByte<0 ){ -+ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn); -+ }else{ -+ if( zDel[0]!='/' ){ -+ int n; -+ for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--); -+ if( nByte+n+1>nOut ){ -+ rc = SQLITE_CANTOPEN_BKPT; -+ }else{ -+ memmove(&zDel[n], zDel, nByte+1); -+ memcpy(zDel, zIn, n); -+ nByte += n; -+ } -+ } -+ zDel[nByte] = '\0'; -+ } -+ } -+ -+ zIn = zDel; -+ } -+ -+ assert( rc!=SQLITE_OK || zIn!=zOut || zIn[0]=='/' ); -+ if( rc==SQLITE_OK && zIn!=zOut ){ -+ rc = mkFullPathname(zIn, zOut, nOut); -+ } -+ if( bLink==0 ) break; -+ zIn = zOut; -+ }while( rc==SQLITE_OK ); -+ -+ sqlite3_free(zDel); -+ if( rc==SQLITE_OK && nLink ) rc = SQLITE_OK_SYMLINK; -+ return rc; -+#endif /* HAVE_READLINK && HAVE_LSTAT */ -+} -+ -+#endif /* !HARMONY_OS */ -+ - #ifndef SQLITE_OMIT_LOAD_EXTENSION - /* - ** Interfaces for opening a shared library, finding entry points -@@ -45507,6 +45940,9 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){ - if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){ - OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n", - lPath, errno, osGetpid(0))); -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_IOERR_LOCK, "proxyGetLockPath len[%d], dbLen[%d], i[%d]", len, dbLen, i); -+#endif /* LOG_DUMP */ - return SQLITE_IOERR_LOCK; - } - len = strlcat(lPath, "sqliteplocks", maxLen); -@@ -45625,6 +46061,9 @@ static int proxyCreateUnixFile( - case EACCES: - return SQLITE_PERM; - case EIO: -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_IOERR_LOCK, "proxyCreateUnixFile-EIO, fd[%d]", fd); -+#endif /* LOG_DUMP */ - return SQLITE_IOERR_LOCK; /* even though it is the conch */ - default: - return SQLITE_CANTOPEN_BKPT; -@@ -45793,6 +46232,9 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ - struct stat buf; - if( osFstat(conchFile->h, &buf) ){ - storeLastErrno(pFile, errno); -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_IOERR_LOCK, "proxyConchLock pFile fd[%d], conchFile fd[%d], lastErrno[%d]", pFile->h, conchFile->h, errno); -+#endif /* LOG_DUMP */ - return SQLITE_IOERR_LOCK; - } - -@@ -45813,6 +46255,9 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ - int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0); - if( len<0 ){ - storeLastErrno(pFile, errno); -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_IOERR_LOCK, "proxyConchLock tries 2, pFile fd[%d], conchFile fd[%d], lastErrno[%d]", pFile->h, conchFile->h, errno); -+#endif /* LOG_DUMP */ - return SQLITE_IOERR_LOCK; - } - if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){ -@@ -45887,6 +46332,9 @@ static int proxyTakeConch(unixFile *pFile){ - if( readLen<0 ){ - /* I/O error: lastErrno set by seekAndRead */ - storeLastErrno(pFile, conchFile->lastErrno); -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_IOERR_READ, "proxyTakeConch pFile fd[%d], conchFile fd[%d], lastErrno[%d]", pFile->h, conchFile->h, conchFile->lastErrno); -+#endif /* LOG_DUMP */ - rc = SQLITE_IOERR_READ; - goto end_takeconch; - }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) || -@@ -57514,6 +57962,20 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ - */ - #define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1) - -+#ifdef SQLITE_HAS_CODEC -+/* -+** A macro used for invoking the codec if there is one -+*/ -+# define CODEC1(P,D,N,X,E) \ -+ if( P->xCodec && P->xCodec(P->pCodec,D,N,X)==0 ){ E; } -+# define CODEC2(P,D,N,X,E,O) \ -+ if( P->xCodec==0 ){ O=(char*)D; }else \ -+ if( (O=(char*)(P->xCodec(P->pCodec,D,N,X)))==0 ){ E; } -+#else -+# define CODEC1(P,D,N,X,E) /* NO-OP */ -+# define CODEC2(P,D,N,X,E,O) O=(char*)D -+#endif /* SQLITE_HAS_CODEC */ -+ - /* - ** The maximum allowed sector size. 64KiB. If the xSectorsize() method - ** returns a value larger than this, then MAX_SECTOR_SIZE is used instead. -@@ -57802,6 +58264,12 @@ struct Pager { - #endif - void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */ - int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */ -+#ifdef SQLITE_HAS_CODEC -+ void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ -+ void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */ -+ void (*xCodecFree)(void*); /* Destructor for the codec */ -+ void *pCodec; /* First argument to xCodec... methods */ -+#endif /* SQLITE_HAS_CODEC */ - char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ - PCache *pPCache; /* Pointer to page cache object */ - #ifndef SQLITE_OMIT_WAL -@@ -57923,6 +58391,9 @@ static const unsigned char aJournalMagic[] = { - SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){ - if( pPager->fd->pMethods==0 ) return 0; - if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; -+#ifdef SQLITE_HAS_CODEC -+ if( pPager->xCodec!=0 ) return 0; -+#endif /* SQLITE_HAS_CODEC */ - #ifndef SQLITE_OMIT_WAL - if( pPager->pWal ){ - u32 iRead = 0; -@@ -58155,7 +58626,11 @@ 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) -+#ifdef SQLITE_HAS_CODEC -+ && pPager->xCodec==0 -+#endif /* SQLITE_HAS_CODEC */ -+ ){ - pPager->xGet = getPageMMap; - #endif /* SQLITE_MAX_MMAP_SIZE>0 */ - }else{ -@@ -59347,6 +59822,32 @@ static u32 pager_cksum(Pager *pPager, const u8 *aData){ - return cksum; - } - -+#ifdef SQLITE_HAS_CODEC -+/* -+** Report the current page size and number of reserved bytes back -+** to the codec. -+*/ -+static void pagerReportSize(Pager *pPager){ -+ if( pPager->xCodecSizeChng ){ -+ pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize, -+ (int)pPager->nReserve); -+ } -+} -+/* -+** Make sure the number of reserved bits is the same in the destination -+** pager as it is in the source. This comes up when a VACUUM changes the -+** number of reserved bits to the "optimal" amount. -+*/ -+SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager *pDest, Pager *pSrc){ -+ if( pDest->nReserve!=pSrc->nReserve ){ -+ pDest->nReserve = pSrc->nReserve; -+ pagerReportSize(pDest); -+ } -+} -+#else -+# define pagerReportSize(X) /* No-op if we do not support a codec */ -+#endif -+ - /* - ** Read a single page from either the journal file (if isMainJrnl==1) or - ** from the sub-journal (if isMainJrnl==0) and playback that page. -@@ -59398,6 +59899,11 @@ static int pager_playback_one_page( - char *aData; /* Temporary storage for the page */ - sqlite3_file *jfd; /* The file descriptor for the journal file */ - int isSynced; /* True if journal page is synced */ -+#ifdef SQLITE_HAS_CODEC -+ /* The jrnlEnc flag is true if Journal pages should be passed through -+ ** the codec. It is false for pure in-memory journals. */ -+ const int jrnlEnc = (isMainJrnl || pPager->subjInMemory==0); -+#endif /* SQLITE_HAS_CODEC */ - - assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */ - assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */ -@@ -59527,12 +60033,26 @@ static int pager_playback_one_page( - ** is if the data was just read from an in-memory sub-journal. In that - ** case it must be encrypted here before it is copied into the database - ** file. */ -+#ifdef SQLITE_HAS_CODEC -+ if( !jrnlEnc ){ -+ CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData); -+ rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); -+ CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT); -+ }else -+#endif /* SQLITE_HAS_CODEC */ - rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); - - if( pgno>pPager->dbFileSize ){ - pPager->dbFileSize = pgno; - } - if( pPager->pBackup ){ -+#ifdef SQLITE_HAS_CODEC -+ if( jrnlEnc ){ -+ CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT); -+ sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); -+ CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT,aData); -+ }else -+#endif /* SQLITE_HAS_CODEC */ - sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); - } - }else if( !isMainJrnl && pPg==0 ){ -@@ -59583,6 +60103,10 @@ static int pager_playback_one_page( - if( pgno==1 ){ - memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers)); - } -+#if SQLITE_HAS_CODEC -+ /* Decode the page just read from disk */ -+ if( jrnlEnc ){ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT); } -+#endif /* SQLITE_HAS_CODEC */ - sqlite3PcacheRelease(pPg); - } - return rc; -@@ -60161,6 +60685,8 @@ static int readDbPage(PgHdr *pPg){ - memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers)); - } - } -+ CODEC1(pPager, pPg->pData, pPg->pgno, 3, rc = SQLITE_NOMEM_BKPT); -+ - PAGER_INCR(sqlite3_pager_readdb_count); - PAGER_INCR(pPager->nRead); - IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno)); -@@ -61306,6 +61832,10 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ - sqlite3OsClose(pPager->fd); - sqlite3PageFree(pTmp); - sqlite3PcacheClose(pPager->pPCache); -+#ifdef SQLITE_HAS_CODEC -+ if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec); -+#endif /* SQLITE_HAS_CODEC */ -+ - assert( !pPager->aSavepoint && !pPager->pInJournal ); - assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) ); - -@@ -61556,7 +62086,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ - assert( (pList->flags&PGHDR_NEED_SYNC)==0 ); - if( pList->pgno==1 ) pager_write_changecounter(pList); - -- pData = pList->pData; -+ CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM_BKPT, pData); - - /* Write out the page data. */ - rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset); -@@ -61645,6 +62175,11 @@ static int subjournalPage(PgHdr *pPg){ - void *pData = pPg->pData; - i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize); - char *pData2; -+#if SQLITE_HAS_CODEC -+ if( !pPager->subjInMemory ){ -+ CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2); -+ }else -+#endif /* SQLITE_HAS_CODEC */ - pData2 = pData; - PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno)); - rc = write32bits(pPager->sjfd, offset, pPg->pgno); -@@ -62737,6 +63272,9 @@ static int getPageMMap( - ); - - assert( USEFETCH(pPager) ); -+#ifdef SQLITE_HAS_CODEC -+ assert( pPager->xCodec==0 ); -+#endif /* SQLITE_HAS_CODEC */ - - /* Optimization note: Adding the "pgno<=1" term before "pgno==0" here - ** allows the compiler optimizer to reuse the results of the "pgno>1" -@@ -63081,7 +63619,7 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){ - assert( pPg->pgno!=PAGER_SJ_PGNO(pPager) ); - - assert( pPager->journalHdr<=pPager->journalOff ); -- pData2 = pPg->pData; -+ CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2); - cksum = pager_cksum(pPager, (u8*)pData2); - - /* Even if an IO or diskfull error occurs while journalling the -@@ -63446,7 +63984,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){ - if( DIRECT_MODE ){ - const void *zBuf; - assert( pPager->dbFileSize>0 ); -- zBuf = pPgHdr->pData; -+ CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM_BKPT, zBuf); - if( rc==SQLITE_OK ){ - rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0); - pPager->aStat[PAGER_STAT_WRITE]++; -@@ -64209,6 +64747,48 @@ SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){ - return pPager->zJournal; - } - -+#ifdef SQLITE_HAS_CODEC -+/* -+** Set or retrieve the codec for this pager -+*/ -+SQLITE_PRIVATE void sqlite3PagerSetCodec( -+ Pager *pPager, -+ void *(*xCodec)(void*,void*,Pgno,int), -+ void (*xCodecSizeChng)(void*,int,int), -+ void (*xCodecFree)(void*), -+ void *pCodec -+){ -+ if( pPager->xCodecFree ){ -+ pPager->xCodecFree(pPager->pCodec); -+ }else{ -+ pager_reset(pPager); -+ } -+ pPager->xCodec = pPager->memDb ? 0 : xCodec; -+ pPager->xCodecSizeChng = xCodecSizeChng; -+ pPager->xCodecFree = xCodecFree; -+ pPager->pCodec = pCodec; -+ setGetterMethod(pPager); -+ pagerReportSize(pPager); -+} -+SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){ -+ return pPager->pCodec; -+} -+ -+/* -+** This function is called by the wal module when writing page content -+** into the log file. -+** -+** This function returns a pointer to a buffer containing the encrypted -+** page content. If a malloc fails, this function may return NULL. -+*/ -+SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){ -+ void *aData = 0; -+ CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData); -+ return aData; -+} -+ -+#endif /* SQLITE_HAS_CODEC */ -+ - #ifndef SQLITE_OMIT_AUTOVACUUM - /* - ** Move the page pPg to location pgno in the file. -@@ -67063,6 +67643,11 @@ static void walRestartHdr(Wal *pWal, u32 salt1){ - assert( pInfo->aReadMark[0]==0 ); - } - -+#ifdef SQLITE_HDR_CHECK -+static int checkHeaderValid(Pager *pager, u8 *zBuf, const char *logStr); -+static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf); -+#endif /* SQLITE_HDR_CHECK */ -+ - /* - ** Copy as much content as we can from the WAL back into the database file - ** in response to an sqlite3_wal_checkpoint() request or the equivalent. -@@ -67203,6 +67788,10 @@ static int walCheckpoint( - if( rc!=SQLITE_OK ) break; - iOffset = (iDbpage-1)*(i64)szPage; - testcase( IS_BIG_INT(iOffset) ); -+#ifdef SQLITE_HDR_CHECK -+ rc = checkDbHeaderValid(db, iDbpage, zBuf); -+ if( rc!=SQLITE_OK ) break; -+#endif /* SQLITE_HDR_CHECK */ - rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); - if( rc!=SQLITE_OK ) break; - } -@@ -68833,7 +69422,18 @@ static int walWriteOneFrame( - int rc; /* Result code from subfunctions */ - void *pData; /* Data actually written */ - u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */ -+#ifdef SQLITE_HDR_CHECK -+ if( pPage->pgno==1 ){ -+ rc = checkHeaderValid(pPage->pPager, pPage->pData, "walWrite"); -+ if( rc!=SQLITE_OK ) return rc; -+ } -+#endif /* SQLITE_HDR_CHECK */ -+ -+#ifdef SQLITE_HAS_CODEC -+ if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT; -+#else - pData = pPage->pData; -+#endif /* SQLITE_HAS_CODEC */ - walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame); - rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset); - if( rc ) return rc; -@@ -69018,7 +69618,11 @@ static int walFrames( - if( pWal->iReCksum==0 || iWriteiReCksum ){ - pWal->iReCksum = iWrite; - } -+#ifdef SQLITE_HAS_CODEC -+ if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM; -+#else - pData = p->pData; -+#endif /* SQLITE_HAS_CODEC */ - rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff); - if( rc ) return rc; - p->flags &= ~PGHDR_WAL_APPEND; -@@ -69129,6 +69733,10 @@ static int walFrames( - return rc; - } - -+#ifdef LOG_DUMP -+static sqlite3_int64 g_lastCkptTime = 0; -+#endif /* LOG_DUMP */ -+ - /* - ** Write a set of frames to the log. The caller must hold the write-lock - ** on the log file (obtained using sqlite3WalBeginWriteTransaction()). -@@ -69282,6 +69890,12 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( - walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1); - pWal->ckptLock = 0; - } -+#ifdef LOG_DUMP -+ if( rc ){ -+ sqlite3_log(SQLITE_NOTICE, "ckpt rc[%d]", rc); -+ } -+ sqlite3OsCurrentTimeInt64(db->pVfs, &g_lastCkptTime); -+#endif /* LOG_DUMP */ - WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok")); - #ifdef SQLITE_ENABLE_SETLK_TIMEOUT - if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY; -@@ -70666,6 +71280,32 @@ SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){ - } - #endif - -+#ifdef SQLITE_HDR_CHECK -+static int checkHeaderValid(Pager *pager, u8 *zBuf, const char *logStr){ -+#ifdef SQLITE_HAS_CODEC -+ if( pager==NULL || pager->pCodec ){ -+ return SQLITE_OK; -+ } -+#endif /* SQLITE_HAS_CODEC */ -+ if( zBuf && strncmp((const char *)zBuf, zMagicHeader, 16)!=0 ){ -+ sqlite3_log(SQLITE_NOTADB, "[%s]wrong header format, memory might be overwritten!", logStr); -+ return SQLITE_NOTADB; -+ } -+ return SQLITE_OK; -+} -+ -+static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf){ -+ if( iDbpage==1 && db->aDb ){ -+ Btree *p = db->aDb[0].pBt; -+ if( p && p->pBt ){ -+ Pager *pager = sqlite3BtreePager(p); -+ return checkHeaderValid(pager, zBuf, "ckpt"); -+ } -+ } -+ return SQLITE_OK; -+} -+#endif /* SQLITE_HDR_CHECK */ -+ - /* - ** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single - ** (MemPage*) as an argument. The (MemPage*) must not be NULL. -@@ -72591,6 +73231,13 @@ static int decodeFlags(MemPage *pPage, int flagByte){ - pPage->intKeyLeaf = 0; - pPage->xCellSize = cellSizePtrIdxLeaf; - pPage->xParseCell = btreeParseCellPtrIndex; -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_CORRUPT, -+ "database corruption at page[%u], flagByte[%x], isInit[%u], intKey[%u], intKeyLeaf[%u], leaf[%u], " -+ "childPtrSize[%u], cellOffset[%u], nCell[%u], hdrOffset[%u], minLocal[%u], maxLocal[%u], last ckpt time[%lld]", -+ pPage->pgno, flagByte, pPage->isInit, pPage->intKey, pPage->intKeyLeaf, pPage->leaf, -+ pPage->childPtrSize, pPage->cellOffset, pPage->nCell, pPage->hdrOffset, pPage->minLocal, pPage->maxLocal, g_lastCkptTime); -+#endif /* LOG_DUMP */ - return SQLITE_CORRUPT_PAGE(pPage); - } - }else{ -@@ -72615,6 +73262,13 @@ static int decodeFlags(MemPage *pPage, int flagByte){ - pPage->intKeyLeaf = 0; - pPage->xCellSize = cellSizePtr; - pPage->xParseCell = btreeParseCellPtrIndex; -+#ifdef LOG_DUMP -+ sqlite3_log(SQLITE_CORRUPT, -+ "database corruption at page[%u], flagByte[%x], isInit[%u], intKey[%u], intKeyLeaf[%u], leaf[%u], " -+ "childPtrSize[%u], cellOffset[%u], nCell[%u], hdrOffset[%u], minLocal[%u], maxLocal[%u], last ckpt time[%lld]", -+ pPage->pgno, flagByte, pPage->isInit, pPage->intKey, pPage->intKeyLeaf, pPage->leaf, -+ pPage->childPtrSize, pPage->cellOffset, pPage->nCell, pPage->hdrOffset, pPage->minLocal, pPage->maxLocal, g_lastCkptTime); -+#endif /* LOG_DUMP */ - return SQLITE_CORRUPT_PAGE(pPage); - } - } -@@ -82246,6 +82900,13 @@ static int backupOnePage( - int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); - const int nCopy = MIN(nSrcPgsz, nDestPgsz); - const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; -+#ifdef SQLITE_HAS_CODEC -+ /* Use BtreeGetReserveNoMutex() for the source b-tree, as although it is -+ ** guaranteed that the shared-mutex is held by this thread, handle -+ ** p->pSrc may not actually be the owner. */ -+ int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc); -+ int nDestReserve = sqlite3BtreeGetRequestedReserve(p->pDest); -+#endif /* SQLITE_HAS_CODEC */ - int rc = SQLITE_OK; - i64 iOff; - -@@ -82256,6 +82917,26 @@ static int backupOnePage( - assert( zSrcData ); - assert( nSrcPgsz==nDestPgsz || sqlite3PagerIsMemdb(pDestPager)==0 ); - -+#ifdef SQLITE_HAS_CODEC -+ /* Backup is not possible if the page size of the destination is changing -+ ** and a codec is in use. -+ */ -+ if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){ -+ rc = SQLITE_READONLY; -+ } -+ -+ /* Backup is not possible if the number of bytes of reserve space differ -+ ** between source and destination. If there is a difference, try to -+ ** fix the destination to agree with the source. If that is not possible, -+ ** then the backup cannot proceed. -+ */ -+ if( nSrcReserve!=nDestReserve ){ -+ u32 newPgsz = nSrcPgsz; -+ rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve); -+ if( rc==SQLITE_OK && newPgsz!=(u32)nSrcPgsz ) rc = SQLITE_READONLY; -+ } -+#endif /* SQLITE_HAS_CODEC */ -+ - /* This loop runs once for each destination page spanned by the source - ** page. For each iteration, variable iOff is set to the byte offset - ** of the destination page. -@@ -82754,6 +83435,10 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ - b.pDest = pTo; - b.iNext = 1; - -+#ifdef SQLITE_HAS_CODEC -+ sqlite3PagerAlignReserve(sqlite3BtreePager(pTo), sqlite3BtreePager(pFrom)); -+#endif /* SQLITE_HAS_CODEC */ -+ - /* 0x7FFFFFFF is the hard limit for the number of pages in a database - ** file. By passing this as the number of pages to copy to - ** sqlite3_backup_step(), we can guarantee that the copy finishes -@@ -91264,6 +91949,15 @@ end_of_step: - return (rc&db->errMask); - } - -+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK -+SQLITE_API int sqlite3_set_droptable_handle(sqlite3 *db, void (*xFunc)(sqlite3*, const char*, const char*)){ -+ sqlite3_mutex_enter(db->mutex); -+ db->xDropTableHandle = xFunc; -+ sqlite3_mutex_leave(db->mutex); -+ return 0; -+} -+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ -+ - /* - ** This is the top-level implementation of sqlite3_step(). Call - ** sqlite3Step() to do most of the work. If a schema error occurs, -@@ -91283,6 +91977,13 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ - while( (rc = sqlite3Step(v))==SQLITE_SCHEMA - && cnt++ < SQLITE_MAX_SCHEMA_RETRY ){ - int savedPc = v->pc; -+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -+ Sqlite3SharedBlockMethods *pSharedBlock = v->pSharedBlock; -+ int totalRows = v->totalRows; -+ int blockFull = v->blockFull; -+ int startPos = v->startPos; -+ int addedRows = v->addedRows; -+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ - rc = sqlite3Reprepare(v); - if( rc!=SQLITE_OK ){ - /* This case occurs after failing to recompile an sql statement. -@@ -91304,6 +92005,15 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ - } - break; - } -+ -+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -+ v->pSharedBlock = pSharedBlock; -+ v->totalRows = totalRows; -+ v->blockFull = blockFull; -+ v->startPos = startPos; -+ v->addedRows = addedRows; -+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ -+ - sqlite3_reset(pStmt); - if( savedPc>=0 ){ - /* Setting minWriteFileFormat to 254 is a signal to the OP_Init and -@@ -91314,6 +92024,20 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ - } - assert( v->expired==0 ); - } -+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK -+ if( rc==SQLITE_DONE && db->xDropTableHandle!=NULL && db->isDropTable==1 ){ -+ db->isDropTable = 0; -+ db->xDropTableHandle(db, db->mDropTableName, db->mDropSchemaName); -+ } -+ if( db->mDropTableName!=NULL ){ -+ sqlite3_free(db->mDropTableName); -+ db->mDropTableName = NULL; -+ } -+ if( db->mDropSchemaName!=NULL ){ -+ sqlite3_free(db->mDropSchemaName); -+ db->mDropSchemaName = NULL; -+ } -+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ - sqlite3_mutex_leave(db->mutex); - return rc; - } -@@ -93761,6 +94485,61 @@ static int checkSavepointCount(sqlite3 *db){ - } - #endif - -+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -+static int copySharedBlockRow( -+ Vdbe *p, /* The VDBE */ -+ Op *pOp, /* Current operation */ -+ Mem *pMem, -+ void *pCtx -+){ -+ int i = 0; -+ -+ int rc = p->pSharedBlock->xAddRow(pCtx, p->addedRows); -+ if( rc!=SQLITE_OK ){ -+ return rc; -+ } -+ -+ for(i=0; ip2; i++){ -+ switch (sqlite3_value_type(&pMem[i])) { -+ case SQLITE_INTEGER:{ -+ rc = p->pSharedBlock->xPutLong(pCtx, p->addedRows, i, (sqlite3_int64)pMem[i].u.i); -+ break; -+ } -+ case SQLITE_FLOAT: { -+ rc = p->pSharedBlock->xPutDouble(pCtx, p->addedRows, i, pMem[i].u.r); -+ break; -+ } -+ case SQLITE_TEXT: { -+ Deephemeralize(&pMem[i]); -+ sqlite3VdbeMemNulTerminate(&pMem[i]); -+ sqlite3VdbeChangeEncoding(&pMem[i],SQLITE_UTF8); -+ rc = p->pSharedBlock->xPutString(pCtx, p->addedRows, i, pMem[i].z, pMem[i].n+1); -+ break; -+ } -+ case SQLITE_BLOB: { -+ rc = p->pSharedBlock->xPutBlob(pCtx, p->addedRows, i, pMem[i].z, pMem[i].n); -+ break; -+ } -+ case SQLITE_NULL: { -+ rc = p->pSharedBlock->xPutNull(pCtx, p->addedRows, i); -+ break; -+ } -+ default: -+ rc = p->pSharedBlock->xPutOther(pCtx, p->addedRows, i); -+ break; -+ } -+ if( rc!=SQLITE_OK ){ -+ return rc; -+ } -+ } -+ -+ return rc; -+no_mem: -+ rc = SQLITE_NOMEM; -+ return rc; -+} -+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ -+ - /* - ** Return the register of pOp->p2 after first preparing it to be - ** overwritten with an integer value. -@@ -94361,6 +95140,12 @@ case OP_Halt: { - VdbeFrame *pFrame; - int pcx; - -+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -+ if( p->pSharedBlock!=NULL ){ -+ p->pSharedBlock->xFinish(p->pSharedBlock->pContext, p->addedRows, p->totalRows); -+ } -+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ -+ - #ifdef SQLITE_DEBUG - if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); } - #endif -@@ -94806,6 +95591,43 @@ case OP_ResultRow: { - assert( pOp->p1>0 || CORRUPT_DB ); - assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); - -+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -+ if( p->pSharedBlock!=NULL ){ -+ void *pCtx = p->pSharedBlock->pContext; -+ p->totalRows++; -+ if( p->totalRows<=p->startPos || p->blockFull ){ -+ break; -+ } -+ Mem *pMem = &aMem[pOp->p1]; -+ rc = copySharedBlockRow(p, pOp, pMem, pCtx); -+ if( rc==SQLITE_FULL && p->addedRows && (p->startPos + p->addedRows) <= p->pSharedBlock->requiredPos ){ -+ p->startPos += p->addedRows; -+ p->addedRows = 0; -+ p->pSharedBlock->xReset(pCtx,p->startPos); -+ p->blockFull = 0; -+ rc = copySharedBlockRow(p, pOp, pMem, pCtx); -+ } -+ -+ if( rc==SQLITE_OK ){ -+ p->addedRows++; -+ }else if( rc==SQLITE_FULL ){ -+ p->blockFull = 1; -+ }else{ -+ //SQLITE_NOMEM -+ goto no_mem; -+ } -+ -+ if( p->blockFull && p->pSharedBlock->countAllRows==0 ){ -+ p->pSharedBlock->xFinish(pCtx, p->addedRows, p->totalRows); -+ rc = SQLITE_DONE; -+ goto vdbe_return; -+ }else if( p->blockFull && p->pSharedBlock->countAllRows==1 ){ -+ rc = SQLITE_OK; -+ } -+ break; -+ } -+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ -+ - p->cacheCtr = (p->cacheCtr + 2)|1; - p->pResultRow = &aMem[pOp->p1]; - #ifdef SQLITE_DEBUG -@@ -95612,6 +96434,17 @@ case OP_Compare: { - ** This opcode must immediately follow an OP_Compare opcode. - */ - case OP_Jump: { /* jump */ -+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -+ if( pOp->p5&0x80 ){ -+ if( p->pSharedBlock!=NULL ){ -+ if( p->totalRows < p->startPos || p->blockFull ){ -+ p->totalRows++; -+ pOp = &aOp[pOp->p2 - 1]; -+ } -+ } -+ break; -+ } -+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ - assert( pOp>aOp && pOp[-1].opcode==OP_Compare ); - assert( iCompareIsInit ); - if( iCompare<0 ){ -@@ -100719,6 +101552,20 @@ case OP_IfNotZero: { /* jump, in1 */ - ** and jump to P2 if the new value is exactly zero. - */ - case OP_DecrJumpZero: { /* jump, in1 */ -+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -+ if( pOp->p5&0x80 ){ -+ if( p->pSharedBlock!=NULL ){ -+ if( p->totalRows < p->startPos || p->blockFull ){ -+ pIn1 = &aMem[pOp->p1]; -+ assert( pIn1->flags&MEM_Int ); -+ if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--; -+ VdbeBranchTaken(pIn1->u.i==-1, 2); -+ if( pIn1->u.i==-1 ) goto jump_to_p2; -+ } -+ } -+ break; -+ } -+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ - pIn1 = &aMem[pOp->p1]; - assert( pIn1->flags&MEM_Int ); - if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--; -@@ -120686,6 +121533,40 @@ static void attachFunc( - if( rc==SQLITE_OK && pNew->zDbSName==0 ){ - rc = SQLITE_NOMEM_BKPT; - } -+#ifdef SQLITE_HAS_CODEC -+ if( rc==SQLITE_OK ){ -+ extern int sqlite3CodecAttach(sqlite3*, int, const void*, int); -+ extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); -+ int nKey; -+ char *zKey; -+ int t = sqlite3_value_type(argv[2]); -+ switch( t ){ -+ case SQLITE_INTEGER: -+ case SQLITE_FLOAT: -+ zErrDyn = sqlite3DbStrDup(db, "Invalid key value"); -+ rc = SQLITE_ERROR; -+ break; -+ -+ case SQLITE_TEXT: -+ case SQLITE_BLOB: -+ nKey = sqlite3_value_bytes(argv[2]); -+ zKey = (char *)sqlite3_value_blob(argv[2]); -+ rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); -+ break; -+ -+ case SQLITE_NULL: -+ /* No key specified. Use the key from URI filename, or if none, -+ ** use the key from the main database. */ -+ if( sqlite3CodecQueryParameters(db, zName, zPath)==0 ){ -+ sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); -+ if( nKey || sqlite3BtreeGetRequestedReserve(db->aDb[0].pBt)>0 ){ -+ rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); -+ } -+ } -+ break; -+ } -+ } -+#endif /* SQLITE_HAS_CODEC */ - sqlite3_free_filename( zPath ); - - /* If the file was opened successfully, read the schema for the new database. -@@ -122260,8 +123141,24 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char - testcase( zTabName[0]==0 ); /* Zero-length table names are allowed */ - pDb = &db->aDb[iDb]; - p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0); -+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK -+ u8 tableType = p->eTabType; -+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ - sqlite3DeleteTable(db, p); - db->mDbFlags |= DBFLAG_SchemaChange; -+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK -+ if( tableType!=TABTYP_VIEW ){ -+ db->isDropTable = 1; -+ db->mDropTableName = sqlite3_malloc(strlen(zTabName) + 1); -+ if( db->mDropTableName!=NULL ){ -+ memcpy(db->mDropTableName, zTabName, strlen(zTabName) + 1); -+ } -+ db->mDropSchemaName = sqlite3_malloc(strlen(db->aDb[iDb].zDbSName) + 1); -+ if( db->mDropSchemaName!=NULL ){ -+ memcpy(db->mDropSchemaName, db->aDb[iDb].zDbSName, strlen(db->aDb[iDb].zDbSName) + 1); -+ } -+ } -+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ - } - - /* -@@ -130873,10 +131770,16 @@ static void groupConcatValue(sqlite3_context *context){ - */ - SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){ - int rc = sqlite3_overload_function(db, "MATCH", 2); -+#ifdef SQLITE_HAS_CODEC -+ extern void sqlite3CodecExportData(sqlite3_context *, int, sqlite3_value **); -+#endif /* SQLITE_HAS_CODEC */ - assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); - if( rc==SQLITE_NOMEM ){ - sqlite3OomFault(db); - } -+#ifdef SQLITE_HAS_CODEC -+ sqlite3CreateFunc(db, "export_database", 1, SQLITE_TEXT, 0, sqlite3CodecExportData, 0, 0, 0, 0, 0); -+#endif /* SQLITE_HAS_CODEC */ - } - - /* -@@ -136799,6 +137702,10 @@ struct sqlite3_api_routines { - /* Version 3.44.0 and later */ - void *(*get_clientdata)(sqlite3*,const char*); - int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*)); -+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK -+ /* handle after drop table done */ -+ int (*set_droptable_handle)(sqlite3*,void(*)(sqlite3*,const char*,const char*)); -+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ - }; - - /* -@@ -137132,6 +138039,10 @@ typedef int (*sqlite3_loadext_entry)( - /* Version 3.44.0 and later */ - #define sqlite3_get_clientdata sqlite3_api->get_clientdata - #define sqlite3_set_clientdata sqlite3_api->set_clientdata -+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK -+/* handle after drop table done */ -+#define sqlite3_set_droptable_handle sqlite3_api->set_droptable_handle -+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ - #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ - - #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) -@@ -137155,7 +138066,7 @@ typedef int (*sqlite3_loadext_entry)( - /************** Continuing where we left off in loadext.c ********************/ - /* #include "sqliteInt.h" */ - --#ifndef SQLITE_OMIT_LOAD_EXTENSION -+#if !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS) - /* - ** Some API routines are omitted when various features are - ** excluded from a build of SQLite. Substitute a NULL pointer -@@ -137169,7 +138080,9 @@ typedef int (*sqlite3_loadext_entry)( - # define sqlite3_column_origin_name 0 - # define sqlite3_column_origin_name16 0 - #endif -+#endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS) */ - -+#ifndef SQLITE_OMIT_LOAD_EXTENSION - #ifdef SQLITE_OMIT_AUTHORIZATION - # define sqlite3_set_authorizer 0 - #endif -@@ -137250,6 +138163,7 @@ typedef int (*sqlite3_loadext_entry)( - #if defined(SQLITE_OMIT_TRACE) - # define sqlite3_trace_v2 0 - #endif -+#endif /* !SQLITE_OMIT_LOAD_EXTENSION */ - - /* - ** The following structure contains pointers to all SQLite API routines. -@@ -137266,6 +138180,7 @@ typedef int (*sqlite3_loadext_entry)( - ** also check to make sure that the pointer to the function is - ** not NULL before calling it. - */ -+#if !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS) - static const sqlite3_api_routines sqlite3Apis = { - sqlite3_aggregate_context, - #ifndef SQLITE_OMIT_DEPRECATED -@@ -137535,7 +138450,11 @@ static const sqlite3_api_routines sqlite3Apis = { - sqlite3_bind_blob64, - sqlite3_bind_text64, - sqlite3_cancel_auto_extension, -+#ifndef SQLITE_OMIT_LOAD_EXTENSION - sqlite3_load_extension, -+#else -+ 0, -+#endif /* !SQLITE_OMIT_LOAD_EXTENSION */ - sqlite3_malloc64, - sqlite3_msize, - sqlite3_realloc64, -@@ -137653,7 +138572,12 @@ static const sqlite3_api_routines sqlite3Apis = { - sqlite3_stmt_explain, - /* Version 3.44.0 and later */ - sqlite3_get_clientdata, -- sqlite3_set_clientdata -+ sqlite3_set_clientdata, -+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK -+ sqlite3_set_droptable_handle -+#else -+ 0 -+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ - }; - - /* True if x is the directory separator character -@@ -137664,6 +138588,9 @@ static const sqlite3_api_routines sqlite3Apis = { - # define DirSep(X) ((X)=='/') - #endif - -+#endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS) */ -+ -+#ifndef SQLITE_OMIT_LOAD_EXTENSION - /* - ** Attempt to load an SQLite extension library contained in the file - ** zFile. The entry point is zProc. zProc may be 0 in which case a -@@ -138143,6 +139070,9 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ - #define PragTyp_WAL_CHECKPOINT 43 - #define PragTyp_LOCK_STATUS 44 - #define PragTyp_STATS 45 -+#ifdef SQLITE_HAS_CODEC -+#define PragTyp_KEY 255 -+#endif /* SQLITE_HAS_CODEC */ - - /* Property flags associated with various pragma. */ - #define PragFlg_NeedSchema 0x01 /* Force schema load before running */ -@@ -138433,6 +139363,18 @@ static const PragmaName aPragmaName[] = { - /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 0, 0, - /* iArg: */ 0 }, -+#if defined(SQLITE_HAS_CODEC) -+ {/* zName: */ "hexkey", -+ /* ePragTyp: */ PragTyp_KEY, -+ /* ePragFlg: */ 0, -+ /* ColNames: */ 0, 0, -+ /* iArg: */ 2 }, -+ {/* zName: */ "hexrekey", -+ /* ePragTyp: */ PragTyp_KEY, -+ /* ePragFlg: */ 0, -+ /* ColNames: */ 0, 0, -+ /* iArg: */ 3 }, -+#endif - #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - #if !defined(SQLITE_OMIT_CHECK) - {/* zName: */ "ignore_check_constraints", -@@ -138485,6 +139427,13 @@ static const PragmaName aPragmaName[] = { - /* ColNames: */ 0, 0, - /* iArg: */ 0 }, - #endif -+#if defined(SQLITE_HAS_CODEC) -+ {/* zName: */ "key", -+ /* ePragTyp: */ PragTyp_KEY, -+ /* ePragFlg: */ 0, -+ /* ColNames: */ 0, 0, -+ /* iArg: */ 0 }, -+#endif - #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - {/* zName: */ "legacy_alter_table", - /* ePragTyp: */ PragTyp_FLAG, -@@ -138592,6 +139541,15 @@ static const PragmaName aPragmaName[] = { - /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, - /* ColNames: */ 0, 0, - /* iArg: */ SQLITE_RecTriggers }, -+#endif -+#if defined(SQLITE_HAS_CODEC) -+ {/* zName: */ "rekey", -+ /* ePragTyp: */ PragTyp_KEY, -+ /* ePragFlg: */ 0, -+ /* ColNames: */ 0, 0, -+ /* iArg: */ 1 }, -+#endif -+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - {/* zName: */ "reverse_unordered_selects", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, -@@ -138680,6 +139638,18 @@ static const PragmaName aPragmaName[] = { - /* ePragFlg: */ PragFlg_NoColumns1, - /* ColNames: */ 0, 0, - /* iArg: */ 0 }, -+#endif -+#if defined(SQLITE_HAS_CODEC) -+ {/* zName: */ "textkey", -+ /* ePragTyp: */ PragTyp_KEY, -+ /* ePragFlg: */ 0, -+ /* ColNames: */ 0, 0, -+ /* iArg: */ 4 }, -+ {/* zName: */ "textrekey", -+ /* ePragTyp: */ PragTyp_KEY, -+ /* ePragFlg: */ 0, -+ /* ColNames: */ 0, 0, -+ /* iArg: */ 5 }, - #endif - {/* zName: */ "threads", - /* ePragTyp: */ PragTyp_THREADS, -@@ -139149,6 +140119,10 @@ SQLITE_PRIVATE void sqlite3Pragma( - Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */ - const PragmaName *pPragma; /* The pragma */ - -+#ifdef SQLITE_HAS_CODEC -+ extern int sqlite3CodecPragma(sqlite3*, int, Parse *, const char *, const char *); -+#endif /* SQLITE_HAS_CODEC */ -+ - if( v==0 ) return; - sqlite3VdbeRunOnlyOnce(v); - pParse->nMem = 2; -@@ -139218,6 +140192,13 @@ SQLITE_PRIVATE void sqlite3Pragma( - goto pragma_out; - } - -+#ifdef SQLITE_HAS_CODEC -+ if(sqlite3CodecPragma(db, iDb, pParse, zLeft, zRight)) { -+ /* sqlite3CodecPragma executes internal */ -+ goto pragma_out; -+ } -+#endif /* SQLITE_HAS_CODEC */ -+ - /* Locate the pragma in the lookup table */ - pPragma = pragmaLocate(zLeft); - if( pPragma==0 ){ -@@ -141459,6 +142440,48 @@ SQLITE_PRIVATE void sqlite3Pragma( - } - #endif - -+#ifdef SQLITE_HAS_CODEC -+ /* Pragma iArg -+ ** ---------- ------ -+ ** key 0 -+ ** rekey 1 -+ ** hexkey 2 -+ ** hexrekey 3 -+ ** textkey 4 -+ ** textrekey 5 -+ */ -+ case PragTyp_KEY: { -+ if( zRight ){ -+ char zBuf[40]; -+ const char *zKey = zRight; -+ int n; -+ if( pPragma->iArg==2 || pPragma->iArg==3 ){ -+ u8 iByte; -+ int i; -+ for(i=0, iByte=0; i<(int)(sizeof(zBuf)*2) && sqlite3Isxdigit(zRight[i]); i++){ -+ iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]); -+ if( (i&1)!=0 ) zBuf[i/2] = iByte; -+ } -+ zKey = zBuf; -+ n = i/2; -+ }else{ -+ n = pPragma->iArg<4 ? sqlite3Strlen30(zRight) : -1; -+ } -+ if( (pPragma->iArg & 1)==0 ){ -+ rc = sqlite3_key_v2(db, zDb, zKey, n); -+ }else{ -+ rc = sqlite3_rekey_v2(db, zDb, zKey, n); -+ } -+ if( rc==SQLITE_OK && n!=0 ){ -+ sqlite3VdbeSetNumCols(v, 1); -+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "ok", SQLITE_STATIC); -+ returnSingleText(v, "ok"); -+ } -+ } -+ break; -+ } -+#endif /* SQLITE_HAS_CODEC */ -+ - #if defined(SQLITE_ENABLE_CEROD) - case PragTyp_ACTIVATE_EXTENSIONS: if( zRight ){ - if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){ -@@ -144023,9 +145046,25 @@ static void selectInnerLoop( - assert( p->pEList!=0 ); - hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP; - if( pSort && pSort->pOrderBy==0 ) pSort = 0; -+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -+ if( hasDistinct && (pDistinct->eTnctType==WHERE_DISTINCT_UNIQUE) ){ -+ hasDistinct = WHERE_DISTINCT_NOOP; -+ sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct); -+ } -+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ - if( pSort==0 && !hasDistinct ){ - assert( iContinue!=0 ); - codeOffset(v, p->iOffset, iContinue); -+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -+ if( eDest==SRT_Output ){ -+ if( p->iLimit ){ -+ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); -+ sqlite3VdbeChangeP5(v, 128); -+ } -+ sqlite3VdbeAddOp2(v, OP_Jump, 0, iContinue); -+ sqlite3VdbeChangeP5(v, 128); -+ } -+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ - } - - /* Pull the requested columns. -@@ -144154,6 +145193,16 @@ static void selectInnerLoop( - fixDistinctOpenEph(pParse, eType, iTab, pDistinct->addrTnct); - if( pSort==0 ){ - codeOffset(v, p->iOffset, iContinue); -+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -+ if( eDest==SRT_Output ){ -+ if( p->iLimit ){ -+ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); -+ sqlite3VdbeChangeP5(v, 128); -+ } -+ sqlite3VdbeAddOp2(v, OP_Jump, 0, iContinue); -+ sqlite3VdbeChangeP5(v, 128); -+ } -+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ - } - } - -@@ -144623,11 +145672,23 @@ static void generateSortTail( - addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); - VdbeCoverage(v); - assert( p->iLimit==0 && p->iOffset==0 ); -+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -+ if( eDest==SRT_Output ){ -+ sqlite3VdbeAddOp2(v, OP_Jump, 0, addrContinue); -+ sqlite3VdbeChangeP5(v, 128); -+ } -+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ - sqlite3VdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab); - bSeq = 0; - }else{ - addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v); - codeOffset(v, p->iOffset, addrContinue); -+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -+ if( eDest==SRT_Output ){ -+ sqlite3VdbeAddOp2(v, OP_Jump, 0, addrContinue); -+ sqlite3VdbeChangeP5(v, 128); -+ } -+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ - iSortTab = iTab; - bSeq = 1; - if( p->iOffset>0 ){ -@@ -155217,6 +156278,17 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( - } - nRes = sqlite3BtreeGetRequestedReserve(pMain); - -+#ifdef SQLITE_HAS_CODEC -+ /* A VACUUM cannot change the pagesize of an encrypted database. */ -+ if( db->nextPagesize ){ -+ extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); -+ int nKey; -+ char *zKey; -+ sqlite3CodecGetKey(db, iDb, (void**)&zKey, &nKey); -+ if( nKey ) db->nextPagesize = 0; -+ } -+#endif /* SQLITE_HAS_CODEC */ -+ - sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); - sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); - sqlite3BtreeSetPagerFlags(pTemp, pgflags|PAGER_CACHESPILL); -@@ -180744,6 +181816,29 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ - rc = setupLookaside(db, pBuf, sz, cnt); - break; - } -+#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -+ case SQLITE_DBCONFIG_SET_SHAREDBLOCK: { -+ Vdbe *pVdbe = (Vdbe *)va_arg(ap, sqlite3_stmt*); -+ Sqlite3SharedBlockMethods *pSharedBlock = va_arg(ap, Sqlite3SharedBlockMethods*); -+ if( pVdbe==NULL ){ -+ rc = SQLITE_MISUSE; -+ break; -+ } -+ pVdbe->pSharedBlock = pSharedBlock; -+ if( pSharedBlock!=NULL ){ -+ pVdbe->startPos = pSharedBlock->startPos; -+ } -+ pVdbe->totalRows = 0; -+ pVdbe->blockFull = 0; -+ pVdbe->addedRows = 0; -+ rc = SQLITE_OK; -+ break; -+ } -+ case SQLITE_DBCONFIG_USE_SHAREDBLOCK: { -+ rc = SQLITE_OK; -+ break; -+ } -+#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ - default: { - static const struct { - int op; /* The opcode */ -@@ -182998,7 +184093,41 @@ static const char *uriParameter(const char *zFilename, const char *zParam){ - return 0; - } - -- -+#ifdef SQLITE_HAS_CODEC -+/* -+** Process URI filename query parameters relevant to the SQLite Encryption -+** Extension. Return true if any of the relevant query parameters are -+** seen and return false if not. -+*/ -+SQLITE_PRIVATE int sqlite3CodecQueryParameters( -+ sqlite3 *db, /* Database connection */ -+ const char *zDb, /* Which schema is being created/attached */ -+ const char *zUri /* URI filename */ -+){ -+ const char *zKey; -+ if( zUri==0 ){ -+ return 0; -+ }else if( (zKey = uriParameter(zUri, "hexkey"))!=0 && zKey[0] ){ -+ u8 iByte; -+ int i; -+ char zDecoded[40]; -+ for(i=0, iByte=0; i<(int)(sizeof(zDecoded)*2) && sqlite3Isxdigit(zKey[i]); i++){ -+ iByte = (iByte<<4) + sqlite3HexToInt(zKey[i]); -+ if( (i&1)!=0 ) zDecoded[i/2] = iByte; -+ } -+ sqlite3_key_v2(db, zDb, zDecoded, i/2); -+ return 1; -+ }else if( (zKey = uriParameter(zUri, "key"))!=0 ){ -+ sqlite3_key_v2(db, zDb, zKey, sqlite3Strlen30(zKey)); -+ return 1; -+ }else if( (zKey = uriParameter(zUri, "textkey"))!=0 ){ -+ sqlite3_key_v2(db, zDb, zKey, -1); -+ return 1; -+ }else{ -+ return 0; -+ } -+} -+#endif /* SQLITE_HAS_CODEC */ - - /* - ** This routine does the work of opening a database on behalf of -@@ -183346,6 +184475,12 @@ opendb_out: - }else if( rc!=SQLITE_OK ){ - db->eOpenState = SQLITE_STATE_SICK; - } -+#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK -+ db->isDropTable = 0; -+ db->mDropTableName = NULL; -+ db->mDropSchemaName = NULL; -+ db->xDropTableHandle = NULL; -+#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ - *ppDb = db; - #ifdef SQLITE_ENABLE_SQLLOG - if( sqlite3GlobalConfig.xSqllog ){ -@@ -183354,6 +184489,14 @@ opendb_out: - sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0); - } - #endif -+#ifdef SQLITE_HAS_CODEC -+ if( rc==SQLITE_OK ) { -+#ifdef SQLITE_CODEC_ATTACH_CHANGED -+ sqlite3CodecResetParameters(&db->codecParm); -+#endif /* SQLITE_CODEC_ATTACH_CHANGED */ -+ sqlite3CodecQueryParameters(db, 0, zOpen); -+ } -+#endif /* SQLITE_HAS_CODEC */ - sqlite3_free_filename(zOpen); - return rc; - } -@@ -257677,3 +258820,1667 @@ SQLITE_API int sqlite3_stmt_init( - /* Return the source-id for this library */ - SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } - /************************** End of sqlite3.c ******************************/ -+ -+#ifdef SQLITE_HAS_CODEC -+/************** Begin file hw_codec_openssl.h *******************************/ -+#ifndef EXPOSE_INTERNAL_FUNC -+#define CODEC_STATIC static -+#else -+#define CODEC_STATIC -+#endif -+ -+#define DEFAULT_CIPHER "aes-256-gcm" -+ -+typedef struct{ -+ unsigned char *buffer; -+ int bufferSize; -+}Buffer; -+/************** End file hw_codec_openssl.h *********************************/ -+/************** Begin file hw_codec.h ***************************************/ -+#define DEFAULT_PAGE_SIZE 1024 -+#define DEFAULT_ITER 10000 -+#define FILE_HEADER_SIZE 16 -+#define SALT_SIZE FILE_HEADER_SIZE -+#define HMAC_SALT_MASK 0x3a -+#define HMAC_ITER 2 -+#define MAX_HMAC_SIZE 64 -+#define MAX_INIT_VECTOR_SIZE 16 -+#define MIN_BLOCK_SIZE 16 -+ -+#define CODEC_OPERATION_ENCRYPT 1 -+#define CODEC_OPERATION_DECRYPT 0 -+ -+#define KEY_CONTEXT_HEAD_SIZE (sizeof(CodecConstant) + 3 * sizeof(int)) -+ -+typedef struct{ -+ void *cipher; -+ int keySize; -+ int keyInfoSize; -+ int cipherPageSize; -+ int initVectorSize; -+ int hmacSize; -+ int reserveSize; -+ int hmacAlgo; -+ int kdfAlgo; -+ int rekeyHmacAlgo; -+}CodecConstant; -+ -+typedef struct{ -+ CodecConstant codecConst; -+ int deriveFlag; -+ int iter; -+ int passwordSize; -+ unsigned char *password; -+ unsigned char *key; -+ unsigned char *hmacKey; -+ unsigned char *keyInfo; -+}KeyContext; -+ -+typedef struct{ -+ Btree *pBt; -+ int savePassword; -+ unsigned char salt[SALT_SIZE]; -+ unsigned char hmacSalt[SALT_SIZE]; -+ unsigned char *buffer; -+ KeyContext *readCtx; -+ KeyContext *writeCtx; -+}CodecContext; -+ -+/************** End file hw_codec.h *****************************************/ -+/************** Begin file hw_codec_openssl.c *******************************/ -+#include -+#include -+#include -+#include -+ -+unsigned int openssl_init_count = 0; -+unsigned int openssl_external_init_flag = 0; -+sqlite3_mutex *openssl_random_mutex = NULL; -+ -+CODEC_STATIC void opensslActive(){ -+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ -+ if(openssl_init_count == 0){ -+ if(EVP_get_cipherbyname(DEFAULT_CIPHER) == NULL){ -+ OpenSSL_add_all_algorithms(); -+ }else{ -+ openssl_external_init_flag = 1; -+ } -+ } -+ -+ if(openssl_random_mutex == NULL){ -+ openssl_random_mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); -+ } -+ openssl_init_count++; -+ -+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ return; -+} -+ -+CODEC_STATIC void opensslDeactive(){ -+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ -+ openssl_init_count--; -+ if(openssl_init_count == 0){ -+ if(openssl_external_init_flag){ -+ openssl_external_init_flag = 0; -+ }else{ -+ EVP_cleanup(); -+ } -+ } -+ -+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ return; -+} -+ -+CODEC_STATIC int opensslGetRandom(Buffer *buffer){ -+ sqlite3_mutex_enter(openssl_random_mutex); -+ int rc = RAND_bytes(buffer->buffer, buffer->bufferSize); -+ sqlite3_mutex_leave(openssl_random_mutex); -+ if(rc != 1){ -+ return SQLITE_ERROR; -+ } -+ return SQLITE_OK; -+} -+ -+CODEC_STATIC void *opensslGetCipher(const char *cipherName){ -+ return (void *)EVP_get_cipherbyname(cipherName); -+} -+ -+CODEC_STATIC int opensslFreeCipher(void *cipher){ -+ return SQLITE_OK; -+} -+ -+CODEC_STATIC const char *opensslGetCipherName(void *cipher){ -+ return EVP_CIPHER_name((EVP_CIPHER *)cipher); -+} -+ -+CODEC_STATIC int opensslGetKeySize(void *cipher){ -+ return EVP_CIPHER_key_length((EVP_CIPHER *)cipher); -+} -+ -+CODEC_STATIC int opensslGetInitVectorSize(void *cipher){ -+ return EVP_CIPHER_iv_length((EVP_CIPHER *)cipher); -+} -+ -+#define CIPHER_HMAC_ALGORITHM_SHA1 1 -+#define CIPHER_HMAC_ALGORITHM_SHA256 2 -+#define CIPHER_HMAC_ALGORITHM_SHA512 3 -+ -+#define DEFAULT_HMAC_ALGORITHM CIPHER_HMAC_ALGORITHM_SHA1 -+ -+#define CIPHER_HMAC_ALGORITHM_NAME_SHA1 "SHA1" -+#define CIPHER_HMAC_ALGORITHM_NAME_SHA256 "SHA256" -+#define CIPHER_HMAC_ALGORITHM_NAME_SHA512 "SHA512" -+ -+#define CIPHER_KDF_ALGORITHM_SHA1 1 -+#define CIPHER_KDF_ALGORITHM_SHA256 2 -+#define CIPHER_KDF_ALGORITHM_SHA512 3 -+ -+#define DEFAULT_KDF_ALGORITHM CIPHER_KDF_ALGORITHM_SHA1 -+ -+#define CIPHER_KDF_ALGORITHM_NAME_SHA1 "KDF_SHA1" -+#define CIPHER_KDF_ALGORITHM_NAME_SHA256 "KDF_SHA256" -+#define CIPHER_KDF_ALGORITHM_NAME_SHA512 "KDF_SHA512" -+ -+ -+CODEC_STATIC int opensslGetHmacSize(KeyContext *keyCtx){ -+ if( keyCtx==NULL ){ -+ return 0; -+ } -+ if( keyCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){ -+ return EVP_MD_size(EVP_sha1()); -+ }else if( keyCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){ -+ return EVP_MD_size(EVP_sha256()); -+ }else if( keyCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){ -+ return EVP_MD_size(EVP_sha512()); -+ } -+ return 0; -+} -+ -+CODEC_STATIC int opensslGetBlockSize(void *cipher){ -+ return EVP_CIPHER_block_size((EVP_CIPHER *)cipher); -+} -+ -+CODEC_STATIC void *opensslGetCtx(void *cipher, int mode, unsigned char *key, unsigned char *initVector){ -+ EVP_CIPHER_CTX *tmpCtx = EVP_CIPHER_CTX_new(); -+ if(tmpCtx == NULL){ -+ return (void *)tmpCtx; -+ } -+ EVP_CipherInit_ex(tmpCtx, (EVP_CIPHER *)cipher, NULL, NULL, NULL, mode); -+ EVP_CIPHER_CTX_set_padding(tmpCtx, 0); -+ EVP_CipherInit_ex(tmpCtx, NULL, NULL, key, initVector, mode); -+ return (void *)tmpCtx; -+} -+ -+CODEC_STATIC int opensslCipher(void *iCtx, Buffer *input, unsigned char *output){ -+ int outputLength = 0; -+ int cipherLength; -+ EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)iCtx; -+ EVP_CipherUpdate(ctx, output, &cipherLength, input->buffer, input->bufferSize); -+ outputLength += cipherLength; -+ output += cipherLength; -+ EVP_CipherFinal_ex(ctx, output, &cipherLength); -+ outputLength += cipherLength; -+ if(outputLength != input->bufferSize){ -+ return SQLITE_ERROR; -+ } -+ return SQLITE_OK; -+} -+ -+CODEC_STATIC void opensslFreeCtx(void *ctx){ -+ EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)ctx); -+} -+ -+CODEC_STATIC int opensslHmac(Buffer *key, Buffer *input1, Buffer *input2, Buffer *output, int hmacAlgo){ -+ HMAC_CTX *ctx = HMAC_CTX_new(); -+ if(ctx == NULL){ -+ return SQLITE_ERROR; -+ } -+ if( hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){ -+ HMAC_Init_ex(ctx, key->buffer, key->bufferSize, EVP_sha1(), NULL); -+ }else if( hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){ -+ HMAC_Init_ex(ctx, key->buffer, key->bufferSize, EVP_sha256(), NULL); -+ }else if( hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){ -+ HMAC_Init_ex(ctx, key->buffer, key->bufferSize, EVP_sha512(), NULL); -+ } -+ HMAC_Update(ctx, input1->buffer, input1->bufferSize); -+ HMAC_Update(ctx, input2->buffer, input2->bufferSize); -+ HMAC_Final(ctx, output->buffer, (unsigned int *)(&output->bufferSize)); -+ -+ HMAC_CTX_free(ctx); -+ return SQLITE_OK; -+} -+ -+CODEC_STATIC void opensslKdf(Buffer *password, Buffer *salt, int workfactor, Buffer *key, int kdfAlgo){ -+ if( kdfAlgo==CIPHER_KDF_ALGORITHM_SHA1 ){ -+ PKCS5_PBKDF2_HMAC((const char *)(password->buffer), password->bufferSize, salt->buffer, salt->bufferSize, -+ workfactor, EVP_sha1(), key->bufferSize, key->buffer); -+ }else if( kdfAlgo==CIPHER_KDF_ALGORITHM_SHA256 ){ -+ PKCS5_PBKDF2_HMAC((const char *)(password->buffer), password->bufferSize, salt->buffer, salt->bufferSize, -+ workfactor, EVP_sha256(), key->bufferSize, key->buffer); -+ }else if( kdfAlgo==CIPHER_KDF_ALGORITHM_SHA512 ){ -+ PKCS5_PBKDF2_HMAC((const char *)(password->buffer), password->bufferSize, salt->buffer, salt->bufferSize, -+ workfactor, EVP_sha512(), key->bufferSize, key->buffer); -+ } -+} -+ -+/************** End file hw_codec_openssl.c *********************************/ -+/************** Begin file hw_codec.c ***************************************/ -+ -+#include "securec.h" -+ -+typedef enum{ -+ OPERATE_CONTEXT_READ = 0, -+ OPERATE_CONTEXT_WRITE, -+ OPERATE_CONTEXT_BOTH -+}OperateContext; -+ -+CODEC_STATIC int sqlite3CodecIsHex(const unsigned char *buffer, int bufferSize){ -+ int i; -+ for(i = 0; i < bufferSize; i++){ -+ if((buffer[i] < '0' || buffer[i] > '9') && -+ (buffer[i] < 'a' || buffer[i] > 'f') && -+ (buffer[i] < 'A' || buffer[i] > 'F')){ -+ return 0; -+ } -+ } -+ return 1; -+} -+ -+CODEC_STATIC int sqlite3CodecHex2int(char input){ -+ if(input >= '0' && input <= '9'){ -+ return (int)(input - '0'); -+ }else if(input >= 'a' && input <= 'f'){ -+ return (int)(input - 'a') + 10; -+ }else if(input >= 'A' && input <= 'F'){ -+ return (int)(input - 'A') + 10; -+ }else{ -+ return 0; -+ } -+} -+ -+CODEC_STATIC void sqlite3CodecHex2Bin(unsigned char *inputBuffer, int inputBuffersize, unsigned char *outputBuffer){ -+ int i; -+ for(i = 0; i < inputBuffersize - 1; i += 2){ -+ outputBuffer[i / 2] = sqlite3CodecHex2int(inputBuffer[i]) << 4 | sqlite3CodecHex2int(inputBuffer[i + 1]); -+ } -+ return; -+} -+ -+CODEC_STATIC void sqlite3CodecBin2Hex(unsigned char *inputBuffer, int inputBuffersize, unsigned char *outputBuffer){ -+ char *buffer = NULL; -+ int i; -+ for(i = 0; i < inputBuffersize; i++){ -+ buffer = (char *)(outputBuffer + i * 2); -+ sqlite3_snprintf(3, buffer, "%02x ", inputBuffer[i]); -+ } -+ return; -+} -+ -+CODEC_STATIC int sqlite3CodecIfMemset(unsigned char *input, unsigned char val, int len){ -+ int i; -+ for(i = 0; i < len; i++){ -+ if(input[i] != val){ -+ return 0; -+ } -+ } -+ return 1; -+} -+ -+CODEC_STATIC int sqlite3CodecIsKeyInfoFormat(const unsigned char *input, int inputSize){ -+ return (input[0] == 'x') && (input[1] == '\'') && (input[inputSize - 1] == '\'') && (sqlite3CodecIsHex(input + 2, inputSize - 3)) ? 1 : 0; -+} -+ -+CODEC_STATIC void sqlite3CodecSetError(CodecContext *ctx, int error){ -+ if(ctx->pBt){ -+ ctx->pBt->pBt->pPager->errCode = error; -+ ctx->pBt->pBt->db->errCode = error; -+ } -+ return; -+} -+ -+CODEC_STATIC void sqlite3CodecClearDeriveKey(KeyContext *keyCtx){ -+ if(keyCtx->key != NULL){ -+ (void)memset_s(keyCtx->key, keyCtx->codecConst.keySize, 0, keyCtx->codecConst.keySize); -+ sqlite3_free(keyCtx->key); -+ keyCtx->key = NULL; -+ } -+ if(keyCtx->hmacKey != NULL){ -+ (void)memset_s(keyCtx->hmacKey, keyCtx->codecConst.keySize, 0, keyCtx->codecConst.keySize); -+ sqlite3_free(keyCtx->hmacKey); -+ keyCtx->hmacKey = NULL; -+ } -+ if(keyCtx->keyInfo != NULL){ -+ (void)memset_s(keyCtx->keyInfo, keyCtx->codecConst.keyInfoSize, 0, keyCtx->codecConst.keyInfoSize); -+ sqlite3_free(keyCtx->keyInfo); -+ keyCtx->keyInfo = NULL; -+ } -+ keyCtx->deriveFlag = 0; -+} -+ -+CODEC_STATIC void sqlite3CodecClearPassword(KeyContext *keyCtx){ -+ if(keyCtx->password != NULL){ -+ (void)memset_s(keyCtx->password, keyCtx->passwordSize, 0, keyCtx->passwordSize); -+ sqlite3_free(keyCtx->password); -+ keyCtx->password = NULL; -+ } -+ keyCtx->passwordSize = 0; -+} -+ -+CODEC_STATIC void sqlite3CodecInitDeriveKeyMemory(KeyContext *keyCtx){ -+ keyCtx->key = (unsigned char *)sqlite3Malloc(keyCtx->codecConst.keySize); -+ keyCtx->hmacKey = (unsigned char *)sqlite3Malloc(keyCtx->codecConst.keySize); -+ keyCtx->keyInfo = (unsigned char *)sqlite3Malloc(keyCtx->codecConst.keyInfoSize); -+ return; -+} -+ -+CODEC_STATIC int sqlite3CodecKeyCtxCmp(KeyContext *first, KeyContext *second){ -+ if(memcmp((unsigned char *)first, (unsigned char *)second, sizeof(CodecConstant))){ -+ return 0; -+ } -+ if(first->iter != second->iter){ -+ return 0; -+ } -+ if(first->passwordSize != second->passwordSize){ -+ return 0; -+ } -+ if((first->password != second->password) && memcmp(first->password, second->password, first->passwordSize)){ -+ return 0; -+ } -+ return 1; -+} -+ -+// This function will free all resources of key context, except it self. -+CODEC_STATIC void sqlite3CodecFreeKeyContext(KeyContext *keyCtx){ -+ sqlite3CodecClearDeriveKey(keyCtx); -+ sqlite3CodecClearPassword(keyCtx); -+ (void)opensslFreeCipher(keyCtx->codecConst.cipher); -+ (void)memset_s(keyCtx, sizeof(KeyContext), 0, KEY_CONTEXT_HEAD_SIZE); -+} -+ -+// You should clear key derive result of output before you call this function -+CODEC_STATIC int sqlite3CodecCopyDeriveKey(KeyContext *input, KeyContext *output){ -+ errno_t rc = EOK; -+ if(input->key != NULL && input->codecConst.keySize > 0){ -+ output->key = (unsigned char *)sqlite3Malloc(output->codecConst.keySize); -+ if(output->key == NULL){ -+ sqlite3CodecFreeKeyContext(output); -+ return SQLITE_NOMEM; -+ } -+ rc = memcpy_s(output->key, output->codecConst.keySize, input->key, input->codecConst.keySize); -+ if(rc != EOK){ -+ sqlite3CodecFreeKeyContext(output); -+ return SQLITE_ERROR; -+ } -+ } -+ if(input->hmacKey != NULL && input->codecConst.keySize > 0){ -+ output->hmacKey = (unsigned char *)sqlite3Malloc(output->codecConst.keySize); -+ if(output->hmacKey == NULL){ -+ sqlite3CodecFreeKeyContext(output); -+ return SQLITE_NOMEM; -+ } -+ rc = memcpy_s(output->hmacKey, output->codecConst.keySize, input->hmacKey, input->codecConst.keySize); -+ if(rc != EOK){ -+ sqlite3CodecFreeKeyContext(output); -+ return SQLITE_ERROR; -+ } -+ } -+ if(input->keyInfo != NULL && input->codecConst.keyInfoSize > 0){ -+ output->keyInfo = (unsigned char *)sqlite3Malloc(output->codecConst.keyInfoSize); -+ if(output->keyInfo == NULL){ -+ sqlite3CodecFreeKeyContext(output); -+ return SQLITE_NOMEM; -+ } -+ rc = memcpy_s(output->keyInfo, output->codecConst.keyInfoSize, input->keyInfo, input->codecConst.keyInfoSize); -+ if(rc != EOK){ -+ sqlite3CodecFreeKeyContext(output); -+ return SQLITE_ERROR; -+ } -+ } -+ return SQLITE_OK; -+} -+ -+// You should set all key infos including salt before you call this function -+CODEC_STATIC int sqlite3CodecDeriveKey(CodecContext *ctx, OperateContext whichKey){ -+ KeyContext *keyCtx = NULL; -+ KeyContext *secondKeyCtx = NULL; -+ switch(whichKey){ -+ case OPERATE_CONTEXT_READ: -+ keyCtx = ctx->readCtx; -+ secondKeyCtx = ctx->writeCtx; -+ break; -+ case OPERATE_CONTEXT_WRITE: -+ keyCtx = ctx->writeCtx; -+ secondKeyCtx = ctx->readCtx; -+ break; -+ default: -+ return SQLITE_ERROR; -+ } -+ if(keyCtx->password == NULL || keyCtx->passwordSize <= 0){ -+ return SQLITE_ERROR; -+ } -+ if(keyCtx->deriveFlag){ -+ return SQLITE_OK; -+ } -+ errno_t memcpyRc = EOK; -+ unsigned char salt[SALT_SIZE]; -+ if (ctx->pBt != NULL && sqlite3OsRead(ctx->pBt->pBt->pPager->fd, salt, SALT_SIZE, 0) == SQLITE_OK) { -+ assert(SALT_SIZE == FILE_HEADER_SIZE); -+ if (memcmp(SQLITE_FILE_HEADER, salt, SALT_SIZE) != 0 && memcmp(ctx->salt, salt, SALT_SIZE) != 0) { -+ memcpyRc = memcpy_s(ctx->salt, FILE_HEADER_SIZE, salt, SALT_SIZE); -+ if(memcpyRc != EOK){ -+ return SQLITE_ERROR; -+ } -+ } -+ } -+ sqlite3CodecInitDeriveKeyMemory(keyCtx); -+ if(keyCtx->key == NULL || keyCtx->hmacKey == NULL || keyCtx->keyInfo == NULL){ -+ sqlite3CodecClearDeriveKey(keyCtx); -+ return SQLITE_NOMEM; -+ } -+ if((keyCtx->passwordSize == keyCtx->codecConst.keyInfoSize) && -+ (sqlite3CodecIsKeyInfoFormat(keyCtx->password, keyCtx->passwordSize))){ -+ sqlite3CodecHex2Bin(keyCtx->password + 2, keyCtx->codecConst.keySize * 2, keyCtx->key); -+ sqlite3CodecHex2Bin(keyCtx->password + 2 + keyCtx->codecConst.keySize * 2, SALT_SIZE * 2, ctx->salt); -+ memcpyRc = memcpy_s(keyCtx->keyInfo, keyCtx->codecConst.keyInfoSize, keyCtx->password, keyCtx->passwordSize); -+ if(memcpyRc != EOK){ -+ return SQLITE_ERROR; -+ } -+ }else if((keyCtx->passwordSize == keyCtx->codecConst.keyInfoSize - SALT_SIZE * 2) && -+ (sqlite3CodecIsKeyInfoFormat(keyCtx->password, keyCtx->passwordSize))){ -+ sqlite3CodecHex2Bin(keyCtx->password + 2, keyCtx->codecConst.keySize * 2, keyCtx->key); -+ memcpyRc = memcpy_s(keyCtx->keyInfo, keyCtx->codecConst.keyInfoSize, keyCtx->password, keyCtx->passwordSize); -+ if(memcpyRc != EOK){ -+ return SQLITE_ERROR; -+ } -+ sqlite3CodecBin2Hex(ctx->salt, SALT_SIZE, keyCtx->keyInfo + 2 + keyCtx->codecConst.keySize * 2); -+ keyCtx->keyInfo[keyCtx->codecConst.keyInfoSize - 1] = '\''; -+ }else{ -+ Buffer password; -+ Buffer salt; -+ Buffer key; -+ password.buffer = keyCtx->password; -+ password.bufferSize = keyCtx->passwordSize; -+ salt.buffer = ctx->salt; -+ salt.bufferSize = SALT_SIZE; -+ key.buffer = keyCtx->key; -+ key.bufferSize = keyCtx->codecConst.keySize; -+ opensslKdf(&password, &salt, keyCtx->iter, &key, keyCtx->codecConst.kdfAlgo); -+ keyCtx->keyInfo[0] = 'x'; -+ keyCtx->keyInfo[1] = '\''; -+ sqlite3CodecBin2Hex(keyCtx->key, keyCtx->codecConst.keySize, keyCtx->keyInfo + 2); -+ sqlite3CodecBin2Hex(ctx->salt, SALT_SIZE, keyCtx->keyInfo + 2 + keyCtx->codecConst.keySize * 2); -+ keyCtx->keyInfo[keyCtx->codecConst.keyInfoSize - 1] = '\''; -+ } -+ int i; -+ for(i = 0; i < SALT_SIZE; i++){ -+ ctx->hmacSalt[i] = ctx->salt[i] ^ HMAC_SALT_MASK; -+ } -+ Buffer hmacPassword; -+ Buffer hmacSalt; -+ Buffer hmacKey; -+ hmacPassword.buffer = keyCtx->key; -+ hmacPassword.bufferSize = keyCtx->codecConst.keySize; -+ hmacSalt.buffer = ctx->hmacSalt; -+ hmacSalt.bufferSize = SALT_SIZE; -+ hmacKey.buffer = keyCtx->hmacKey; -+ hmacKey.bufferSize = keyCtx->codecConst.keySize; -+ opensslKdf(&hmacPassword, &hmacSalt, HMAC_ITER, &hmacKey, keyCtx->codecConst.kdfAlgo); -+ keyCtx->deriveFlag = 1; -+ if(sqlite3CodecKeyCtxCmp(keyCtx, secondKeyCtx)){ -+ sqlite3CodecClearDeriveKey(secondKeyCtx); -+ int rc = sqlite3CodecCopyDeriveKey(keyCtx, secondKeyCtx); -+ if(rc == SQLITE_OK){ -+ secondKeyCtx->deriveFlag = 1; -+ // clear password -+ if(!(ctx->savePassword)){ -+ sqlite3CodecClearPassword(secondKeyCtx); -+ } -+ } -+ } -+ // clear password -+ if(!(ctx->savePassword)){ -+ sqlite3CodecClearPassword(keyCtx); -+ } -+ return SQLITE_OK; -+} -+ -+// This function may clear key derive infos -+CODEC_STATIC int sqlite3CodecSetCodecConstant(KeyContext *keyCtx, const char *cipherName){ -+ if(keyCtx->codecConst.cipher){ -+ if(sqlite3StrICmp(cipherName, opensslGetCipherName(keyCtx->codecConst.cipher)) == 0){ -+ return SQLITE_OK; -+ } -+ } -+ sqlite3CodecClearDeriveKey(keyCtx); -+ void *cipher = opensslGetCipher(cipherName); -+ if(cipher != NULL){ -+ keyCtx->codecConst.cipher = cipher; -+ } else { -+ return SQLITE_ERROR; -+ } -+ keyCtx->codecConst.keySize = opensslGetKeySize(keyCtx->codecConst.cipher); -+ keyCtx->codecConst.keyInfoSize = (keyCtx->codecConst.keySize + SALT_SIZE) * 2 + 3; -+ keyCtx->codecConst.initVectorSize = opensslGetInitVectorSize(keyCtx->codecConst.cipher); -+ return SQLITE_OK; -+} -+ -+// You should clear key derive infos before you call this function -+CODEC_STATIC int sqlite3CodecSetIter(KeyContext *keyCtx, int iter){ -+ keyCtx->iter = iter; -+ return SQLITE_OK; -+} -+ -+#ifdef SQLITE_CODEC_ATTACH_CHANGED -+#define CIPHER_ID_AES_256_CBC 0 -+#define CIPHER_ID_AES_256_GCM 1 -+ -+#define CIPHER_TOTAL_NUM 2 -+ -+#define CIPHER_NAME_AES_256_CBC "aes-256-cbc" -+#define CIPHER_NAME_AES_256_GCM "aes-256-gcm" -+ -+struct CodecCipherNameId { -+ int cipherId; -+ const char *cipherName; -+}; -+ -+static const struct CodecCipherNameId g_cipherNameIdMap[CIPHER_TOTAL_NUM] = { -+ { CIPHER_ID_AES_256_CBC, CIPHER_NAME_AES_256_CBC }, -+ { CIPHER_ID_AES_256_GCM, CIPHER_NAME_AES_256_GCM } -+}; -+ -+SQLITE_PRIVATE void sqlite3CodecResetParameters(CodecParameter *p) -+{ -+ p->kdfIter = DEFAULT_ITER; -+ p->pageSize = DEFAULT_PAGE_SIZE; -+ p->cipher = CIPHER_ID_AES_256_GCM; -+ p->hmacAlgo = DEFAULT_HMAC_ALGORITHM; -+ p->kdfAlgo = DEFAULT_KDF_ALGORITHM; -+} -+ -+CODEC_STATIC void sqlite3CodecSetDefaultAttachCipher(CodecParameter *parm, const char *cipherName){ -+ int i; -+ for( i=0; icipher = g_cipherNameIdMap[i].cipherId; -+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ return; -+ } -+ } -+ sqlite3_log(SQLITE_WARNING, "invalid attach cipher algorithm"); -+} -+ -+CODEC_STATIC const char *sqlite3CodecGetDefaultAttachCipher(CodecParameter *parm){ -+ const char *attachedCipher = CIPHER_NAME_AES_256_GCM; -+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ if( (parm->cipher>=0) && (parm->ciphercipher].cipherName; -+ } -+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ return attachedCipher; -+} -+ -+CODEC_STATIC void sqlite3CodecSetDefaultAttachKdfIter(CodecParameter *parm, int iter){ -+ if( iter<=0 ){ -+ return; -+ } -+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ parm->kdfIter = iter; -+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+} -+ -+CODEC_STATIC int sqlite3CodecGetDefaultAttachKdfIter(CodecParameter *parm){ -+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ int iterNum = parm->kdfIter; -+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ return iterNum; -+} -+ -+CODEC_STATIC void sqlite3CodecSetDefaultAttachHmacAlgo(CodecParameter *parm, int hmacAlgo){ -+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ parm->hmacAlgo = hmacAlgo; -+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+} -+ -+CODEC_STATIC int sqlite3CodecGetDefaultAttachHmacAlgo(CodecParameter *parm){ -+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ int hmacAlgo = parm->hmacAlgo; -+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ return hmacAlgo; -+} -+ -+CODEC_STATIC void sqlite3CodecSetDefaultAttachKdfAlgo(CodecParameter *parm, int kdfAlgo){ -+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ parm->kdfAlgo = kdfAlgo; -+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+} -+ -+CODEC_STATIC int sqlite3CodecGetDefaultAttachKdfAlgo(CodecParameter *parm){ -+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ int kdfAlgo = parm->kdfAlgo; -+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ return kdfAlgo; -+} -+ -+CODEC_STATIC void sqlite3CodecSetDefaultAttachPageSize(CodecParameter *parm, int pageSize){ -+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ parm->pageSize = pageSize; -+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+} -+ -+CODEC_STATIC int sqlite3CodecGetDefaultAttachPageSize(CodecParameter *parm){ -+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ int pageSize = parm->pageSize; -+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -+ return pageSize; -+} -+ -+#endif /* SQLITE_CODEC_ATTACH_CHANGED */ -+ -+// You should clear key derive infos and password infos before you call this function -+CODEC_STATIC int sqlite3CodecSetPassword(KeyContext *keyCtx, const void *zKey, int nKey){ -+ keyCtx->passwordSize = nKey; -+ keyCtx->password = (unsigned char *)sqlite3Malloc(keyCtx->passwordSize); -+ if(keyCtx->password == NULL){ -+ return SQLITE_NOMEM; -+ } -+ errno_t rc = memcpy_s(keyCtx->password, keyCtx->passwordSize, zKey, nKey); -+ if(rc != EOK){ -+ sqlite3CodecClearPassword(keyCtx); -+ return SQLITE_ERROR; -+ } -+ return SQLITE_OK; -+} -+ -+// You should clear key derive infos and password infos before you call this function -+CODEC_STATIC int sqlite3CodecSetHmacAlgorithm(KeyContext *keyCtx, int hmacAlgo){ -+ keyCtx->codecConst.hmacAlgo = hmacAlgo; -+ keyCtx->codecConst.hmacSize = opensslGetHmacSize(keyCtx); -+ int cipherBlockSize = opensslGetBlockSize(keyCtx->codecConst.cipher); -+ int blockSize = cipherBlockSize; -+ while(blockSize < MIN_BLOCK_SIZE){ -+ blockSize += cipherBlockSize; -+ } -+ int reserveSize = MAX_INIT_VECTOR_SIZE + keyCtx->codecConst.hmacSize; -+ if(reserveSize % blockSize == 0){ -+ keyCtx->codecConst.reserveSize = reserveSize; -+ }else{ -+ keyCtx->codecConst.reserveSize = (reserveSize / blockSize + 1) * blockSize; -+ } -+ return SQLITE_OK; -+} -+ -+CODEC_STATIC int sqlite3CodecSetKdfAlgorithm(KeyContext *keyCtx, int kdfAlgo){ -+ keyCtx->codecConst.kdfAlgo = kdfAlgo; -+ return SQLITE_OK; -+} -+ -+CODEC_STATIC int sqlite3CodecSetCipherPageSize(CodecContext *ctx, int size){ -+ if(!((size != 0) && ((size & (size - 1)) == 0)) || size < 512 || size > 65536) { -+ sqlite3_log(SQLITE_ERROR, "codec: cipher_page_size not a power of 2 and between 512 and 65536 inclusive(%d).", size); -+ return SQLITE_ERROR; -+ } -+ int cipherPageSize = ctx->readCtx->codecConst.cipherPageSize; -+ (void)memset_s(ctx->buffer, cipherPageSize, 0, cipherPageSize); -+ sqlite3_free(ctx->buffer); -+ ctx->readCtx->codecConst.cipherPageSize = size; -+ ctx->writeCtx->codecConst.cipherPageSize = size; -+ -+ ctx->buffer = (unsigned char *)sqlite3Malloc(size); -+ if (ctx->buffer == NULL) { -+ sqlite3_log(SQLITE_NOMEM, "codec: alloc mem failed when set cipher page size(%d).", size); -+ return SQLITE_NOMEM; -+ } -+ return SQLITE_OK; -+} -+ -+// You should clear output before you call this function -+CODEC_STATIC int sqlite3CodecCopyKeyContext(KeyContext *input, KeyContext *output){ -+ errno_t rc = memcpy_s(output, sizeof(KeyContext), input, KEY_CONTEXT_HEAD_SIZE); -+ if(rc != EOK){ -+ return SQLITE_ERROR; -+ } -+ if(input->password != NULL && input->passwordSize > 0){ -+ output->password = (unsigned char *)sqlite3Malloc(output->passwordSize); -+ if(output->password == NULL){ -+ sqlite3CodecFreeKeyContext(output); -+ return SQLITE_NOMEM; -+ } -+ rc = memcpy_s(output->password, output->passwordSize, input->password, input->passwordSize); -+ if(rc != EOK){ -+ sqlite3CodecFreeKeyContext(output); -+ return SQLITE_ERROR; -+ } -+ } -+ return sqlite3CodecCopyDeriveKey(input, output); -+} -+ -+// You should clear key context before you call this function -+#ifdef SQLITE_CODEC_ATTACH_CHANGED -+CODEC_STATIC int sqlite3CodecInitKeyContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey, int attachFlag){ -+#else -+CODEC_STATIC int sqlite3CodecInitKeyContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey){ -+#endif /* SQLITE_CODEC_ATTACH_CHANGED */ -+ int rc = SQLITE_OK; -+ KeyContext *keyCtx = ctx->readCtx; -+#ifdef SQLITE_CODEC_ATTACH_CHANGED -+ if( attachFlag!=0 ){ -+ CodecParameter *parm = &p->db->codecParm; -+ int hmacAlgo = sqlite3CodecGetDefaultAttachHmacAlgo(parm); -+ rc = sqlite3CodecSetCodecConstant(keyCtx, sqlite3CodecGetDefaultAttachCipher(parm)); -+ rc += sqlite3CodecSetIter(keyCtx, sqlite3CodecGetDefaultAttachKdfIter(parm)); -+ if( hmacAlgo!=0 ){ -+ rc += sqlite3CodecSetHmacAlgorithm(keyCtx, hmacAlgo); -+ } -+ int attachKdfAlgo = sqlite3CodecGetDefaultAttachKdfAlgo(parm); -+ if( attachKdfAlgo!=0 ){ -+ rc += sqlite3CodecSetKdfAlgorithm(keyCtx, attachKdfAlgo); -+ } -+ int cipherPageSize = sqlite3CodecGetDefaultAttachPageSize(parm); -+ if( cipherPageSize!=0 ){ -+ rc += sqlite3CodecSetCipherPageSize(ctx, cipherPageSize); -+ if ( rc != SQLITE_OK ) { -+ sqlite3CodecFreeKeyContext(keyCtx); -+ return SQLITE_ERROR; -+ } -+ rc += sqlite3BtreeSetPageSize(p, cipherPageSize, keyCtx->codecConst.reserveSize, 0); -+ } -+ }else{ -+ rc = sqlite3CodecSetCodecConstant(keyCtx, DEFAULT_CIPHER); -+ rc += sqlite3CodecSetIter(keyCtx, DEFAULT_ITER); -+ rc += sqlite3CodecSetHmacAlgorithm(keyCtx, DEFAULT_HMAC_ALGORITHM); -+ rc += sqlite3CodecSetKdfAlgorithm(keyCtx, DEFAULT_KDF_ALGORITHM); -+ } -+#else -+ rc = sqlite3CodecSetCodecConstant(keyCtx, DEFAULT_CIPHER); -+ rc += sqlite3CodecSetIter(keyCtx, DEFAULT_ITER); -+ rc += sqlite3CodecSetHmacAlgorithm(keyCtx, DEFAULT_HMAC_ALGORITHM); -+ rc += sqlite3CodecSetKdfAlgorithm(keyCtx, DEFAULT_KDF_ALGORITHM); -+#endif /* SQLITE_CODEC_ATTACH_CHANGED */ -+ keyCtx->codecConst.rekeyHmacAlgo = DEFAULT_HMAC_ALGORITHM; -+ rc += sqlite3CodecSetPassword(keyCtx, zKey, nKey); -+ if(rc != SQLITE_OK){ -+ sqlite3CodecFreeKeyContext(keyCtx); -+ return SQLITE_ERROR; -+ } -+ return SQLITE_OK; -+} -+ -+// This function will free all resources of codec context, except it self. -+CODEC_STATIC void sqlite3CodecFreeContext(CodecContext *ctx){ -+ if(ctx->buffer){ -+ int cipherPageSize = ctx->readCtx->codecConst.cipherPageSize; -+ (void)memset_s(ctx->buffer, cipherPageSize, 0, cipherPageSize); -+ sqlite3_free(ctx->buffer); -+ ctx->buffer = NULL; -+ } -+ if(ctx->readCtx){ -+ sqlite3CodecFreeKeyContext(ctx->readCtx); -+ sqlite3_free(ctx->readCtx); -+ ctx->readCtx = NULL; -+ } -+ if(ctx->writeCtx){ -+ sqlite3CodecFreeKeyContext(ctx->writeCtx); -+ sqlite3_free(ctx->writeCtx); -+ ctx->writeCtx = NULL; -+ } -+ (void)memset_s(ctx, sizeof(CodecContext), 0, sizeof(CodecContext)); -+ return; -+} -+#ifdef SQLITE_CODEC_ATTACH_CHANGED -+CODEC_STATIC int sqlite3CodecInitContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey, int nDb){ -+ int attachFlag = (nDb > 1) ? 1 : 0; -+ int defaultPageSz = attachFlag ? p->db->codecParm.pageSize : DEFAULT_PAGE_SIZE; -+#else -+CODEC_STATIC int sqlite3CodecInitContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey){ -+ int defaultPageSz = DEFAULT_PAGE_SIZE; -+#endif /* SQLITE_CODEC_ATTACH_CHANGED */ -+ sqlite3_file *fd = p->pBt->pPager->fd; -+ ctx->pBt = p; -+ ctx->savePassword = 0; -+ ctx->buffer = (unsigned char *)sqlite3Malloc(defaultPageSz); -+ ctx->readCtx = (KeyContext *)sqlite3Malloc(sizeof(KeyContext)); -+ ctx->writeCtx = (KeyContext *)sqlite3Malloc(sizeof(KeyContext)); -+ if(ctx->buffer == NULL || ctx->readCtx == NULL || ctx->writeCtx == NULL){ -+ sqlite3CodecFreeContext(ctx); -+ return SQLITE_NOMEM; -+ } -+ errno_t memsetRc = memset_s(ctx->buffer, defaultPageSz, 0, defaultPageSz); -+ memsetRc += memset_s(ctx->readCtx, sizeof(KeyContext), 0, sizeof(KeyContext)); -+ memsetRc += memset_s(ctx->writeCtx, sizeof(KeyContext), 0, sizeof(KeyContext)); -+ if(memsetRc != EOK){ -+ sqlite3CodecFreeContext(ctx); -+ return SQLITE_ERROR; -+ } -+ ctx->readCtx->codecConst.cipherPageSize = defaultPageSz; -+ ctx->writeCtx->codecConst.cipherPageSize = defaultPageSz; -+#ifdef SQLITE_CODEC_ATTACH_CHANGED -+ int rc = sqlite3CodecInitKeyContext(ctx, p, zKey, nKey, attachFlag); -+#else -+ int rc = sqlite3CodecInitKeyContext(ctx, p, zKey, nKey); -+#endif /* SQLITE_CODEC_ATTACH_CHANGED */ -+ if(rc != SQLITE_OK){ -+ sqlite3CodecFreeContext(ctx); -+ return SQLITE_ERROR; -+ } -+ rc = sqlite3CodecCopyKeyContext(ctx->readCtx, ctx->writeCtx); -+ if(rc != SQLITE_OK){ -+ sqlite3CodecFreeContext(ctx); -+ return SQLITE_ERROR; -+ } -+ if(fd == NULL || !(isOpen(fd)) || sqlite3OsRead(fd, ctx->salt, SALT_SIZE, 0) != SQLITE_OK){ -+ Buffer salt; -+ salt.buffer = ctx->salt; -+ salt.bufferSize = SALT_SIZE; -+ rc = opensslGetRandom(&salt); -+ if(rc != SQLITE_OK){ -+ sqlite3CodecFreeContext(ctx); -+ return rc; -+ } -+ } -+ return SQLITE_OK; -+} -+ -+CODEC_STATIC int sqlite3CodecGetDbIndex(sqlite3 *db, const char *zDb){ -+ int nDbIndex; -+ if(zDb == NULL){ -+ return 0; -+ } -+ for(nDbIndex = 0; nDbIndex < db->nDb; nDbIndex++){ -+ const char *zDbSName = db->aDb[nDbIndex].zDbSName; -+ if(strcmp(zDbSName, zDb) == 0){ -+ return nDbIndex; -+ } -+ } -+ return 0; -+} -+ -+CODEC_STATIC void sqlite3CodecTransPgno(Pgno input, unsigned char *output){ -+#ifdef CIPHER_BIG_ENDAIN -+ sqlite3Put4byte(output, input); -+#else -+ output[0] = (u8)input; -+ output[1] = (u8)(input>>8); -+ output[2] = (u8)(input>>16); -+ output[3] = (u8)(input>>24); -+#endif -+} -+ -+CODEC_STATIC int sqlite3CodecHmac(KeyContext *ctx, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *output){ -+ Buffer key; -+ key.buffer = ctx->hmacKey; -+ key.bufferSize = ctx->codecConst.keySize; -+ Buffer input1; -+ input1.buffer = input; -+ input1.bufferSize = bufferSize; -+ Buffer input2; -+ unsigned char pgnoBuffer[sizeof(Pgno)]; -+ sqlite3CodecTransPgno(pgno, pgnoBuffer); -+ input2.buffer = pgnoBuffer; -+ input2.bufferSize = sizeof(Pgno); -+ Buffer outputBuffer; -+ outputBuffer.buffer = output; -+ outputBuffer.bufferSize = 0; -+ int rc = opensslHmac(&key, &input1, &input2, &outputBuffer, ctx->codecConst.hmacAlgo); -+ if(rc != SQLITE_OK || outputBuffer.bufferSize != ctx->codecConst.hmacSize){ -+ return SQLITE_ERROR; -+ } -+ return SQLITE_OK; -+} -+ -+CODEC_STATIC int sqlite3CodecCheckHmac(KeyContext *ctx, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *expectResult){ -+ if (ctx->codecConst.hmacSize <= 0) { -+ return 1; -+ } -+ int rc = SQLITE_OK; -+ if (ctx->codecConst.hmacSize <= MAX_HMAC_SIZE) { -+ unsigned char buffer[MAX_HMAC_SIZE]; -+ rc = sqlite3CodecHmac(ctx, pgno, bufferSize, input, buffer); -+ if(rc != SQLITE_OK){ -+ return 1; -+ } -+ return memcmp(buffer, expectResult, ctx->codecConst.hmacSize); -+ } else { -+ unsigned char *output = (unsigned char *)malloc(ctx->codecConst.hmacSize); -+ if (output == NULL) { -+ return 1; -+ } -+ rc = sqlite3CodecHmac(ctx, pgno, bufferSize, input, output); -+ if(rc != SQLITE_OK){ -+ free(output); -+ return 1; -+ } -+ rc = memcmp(output, expectResult, ctx->codecConst.hmacSize); -+ free(output); -+ return rc; -+ } -+} -+ -+CODEC_STATIC int sqlite3CodecEncryptData(CodecContext *ctx, OperateContext whichKey, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *output){ -+ KeyContext *keyCtx = NULL; -+ switch(whichKey){ -+ case OPERATE_CONTEXT_READ: -+ keyCtx = ctx->readCtx; -+ break; -+ case OPERATE_CONTEXT_WRITE: -+ keyCtx = ctx->writeCtx; -+ break; -+ default: -+ return SQLITE_ERROR; -+ } -+ int rc = SQLITE_OK; -+ if(!(keyCtx->deriveFlag)){ -+ rc = sqlite3CodecDeriveKey(ctx, whichKey); -+ if(rc != SQLITE_OK){ -+ return rc; -+ } -+ } -+ if(keyCtx->codecConst.keySize == 0){ -+ return SQLITE_ERROR; -+ } -+ Buffer inputBuffer; -+ inputBuffer.buffer = input; -+ inputBuffer.bufferSize = bufferSize - keyCtx->codecConst.reserveSize; -+ Buffer initVector; -+ initVector.buffer = output + inputBuffer.bufferSize; -+ initVector.bufferSize = keyCtx->codecConst.initVectorSize; -+ rc = opensslGetRandom(&initVector); -+ if(rc != SQLITE_OK){ -+ return rc; -+ } -+ void *cipherCtx = opensslGetCtx(keyCtx->codecConst.cipher, CODEC_OPERATION_ENCRYPT, keyCtx->key, initVector.buffer); -+ if(cipherCtx == NULL){ -+ return SQLITE_ERROR; -+ } -+ rc = opensslCipher(cipherCtx, &inputBuffer, output); -+ opensslFreeCtx(cipherCtx); -+ if(rc != SQLITE_OK){ -+ return rc; -+ } -+ rc = sqlite3CodecHmac(keyCtx, pgno, inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize, output, output + inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize); -+ if(rc != SQLITE_OK){ -+ return rc; -+ } -+ return SQLITE_OK; -+} -+ -+CODEC_STATIC int sqlite3CodecDecryptData(CodecContext *ctx, OperateContext whichKey, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *output){ -+ KeyContext *keyCtx = NULL; -+ switch(whichKey){ -+ case OPERATE_CONTEXT_READ: -+ keyCtx = ctx->readCtx; -+ break; -+ case OPERATE_CONTEXT_WRITE: -+ keyCtx = ctx->writeCtx; -+ break; -+ default: -+ return SQLITE_ERROR; -+ } -+ int rc = SQLITE_OK; -+ if(!(keyCtx->deriveFlag)){ -+ rc = sqlite3CodecDeriveKey(ctx, whichKey); -+ if(rc != SQLITE_OK){ -+ return rc; -+ } -+ } -+ if(keyCtx->codecConst.keySize == 0){ -+ return SQLITE_ERROR; -+ } -+ if(sqlite3CodecIfMemset(input, 0, bufferSize)){ -+ errno_t memsetRc = memset_s(output, bufferSize, 0, bufferSize); -+ if(memsetRc != EOK){ -+ return SQLITE_ERROR; -+ } -+ return SQLITE_OK; -+ }else{ -+ Buffer inputBuffer; -+ inputBuffer.buffer = input; -+ inputBuffer.bufferSize = bufferSize - keyCtx->codecConst.reserveSize; -+ if(sqlite3CodecCheckHmac(keyCtx, pgno, inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize, input, input + inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize)){ -+ sqlite3_log(SQLITE_ERROR, "codec: check hmac error at page %d, hmac %d, kdf %d, pageSize %d, iter %d.", -+ pgno, keyCtx->codecConst.hmacAlgo, keyCtx->codecConst.kdfAlgo, keyCtx->codecConst.cipherPageSize, keyCtx->iter); -+ return SQLITE_ERROR; -+ } -+ unsigned char *initVector = input + inputBuffer.bufferSize; -+ void *cipherCtx = opensslGetCtx(keyCtx->codecConst.cipher, CODEC_OPERATION_DECRYPT, keyCtx->key, initVector); -+ if(cipherCtx == NULL){ -+ return SQLITE_ERROR; -+ } -+ rc = opensslCipher(cipherCtx, &inputBuffer, output); -+ opensslFreeCtx(cipherCtx); -+ if(rc != SQLITE_OK){ -+ return rc; -+ } -+ } -+ return SQLITE_OK; -+} -+ -+void* sqlite3Codec(void *ctx, void *data, Pgno pgno, int mode){ -+ CodecContext *pCtx = (CodecContext *)ctx; -+ unsigned char *pData = (unsigned char *)data; -+ int offset = 0; -+ int rc = SQLITE_OK; -+ errno_t memcpyRc = EOK; -+ if(ctx == NULL || data == NULL){ -+ return pData; -+ } -+ if(pgno == 1){ -+ offset = FILE_HEADER_SIZE; -+ } -+ int cipherPageSize = pCtx->readCtx->codecConst.cipherPageSize; -+ switch(mode){ -+ case 0: -+ case 2: -+ case 3: -+ if(pgno == 1){ -+ memcpyRc = memcpy_s(pCtx->buffer, cipherPageSize, SQLITE_FILE_HEADER, FILE_HEADER_SIZE); -+ if(memcpyRc != EOK){ -+ sqlite3CodecSetError(pCtx, SQLITE_ERROR); -+ return pData; -+ } -+ } -+ rc = sqlite3CodecDecryptData(pCtx, OPERATE_CONTEXT_READ, pgno, cipherPageSize - offset, (unsigned char *)(pData + offset), pCtx->buffer + offset); -+ if(rc != SQLITE_OK){ -+ sqlite3CodecSetError(pCtx, rc); -+ } -+ (void)memcpy_s(pData, cipherPageSize, pCtx->buffer, cipherPageSize); -+ return pData; -+ break; -+ case 6: -+ if(pgno == 1){ -+ memcpyRc = memcpy_s(pCtx->buffer, cipherPageSize, pCtx->salt, FILE_HEADER_SIZE); -+ if(memcpyRc != EOK){ -+ sqlite3CodecSetError(pCtx, SQLITE_ERROR); -+ return pData; -+ } -+ } -+ rc = sqlite3CodecEncryptData(pCtx, OPERATE_CONTEXT_WRITE, pgno, cipherPageSize - offset, (unsigned char *)(pData + offset), pCtx->buffer + offset); -+ if(rc != SQLITE_OK){ -+ sqlite3CodecSetError(pCtx, rc); -+ return pData; -+ } -+ return pCtx->buffer; -+ break; -+ case 7: -+ if(pgno == 1){ -+ memcpyRc = memcpy_s(pCtx->buffer, cipherPageSize, pCtx->salt, FILE_HEADER_SIZE); -+ if(memcpyRc != EOK){ -+ sqlite3CodecSetError(pCtx, SQLITE_ERROR); -+ return pData; -+ } -+ } -+ rc = sqlite3CodecEncryptData(pCtx, OPERATE_CONTEXT_READ, pgno, cipherPageSize - offset, (unsigned char *)(pData + offset), pCtx->buffer + offset); -+ if(rc != SQLITE_OK){ -+ sqlite3CodecSetError(pCtx, rc); -+ return pData; -+ } -+ return pCtx->buffer; -+ break; -+ default: -+ return pData; -+ break; -+ } -+} -+ -+void sqlite3CodecDetach(void *ctx){ -+ if(ctx != NULL){ -+ sqlite3CodecFreeContext((CodecContext *)ctx); -+ sqlite3_free(ctx); -+ opensslDeactive(); -+ } -+ return; -+} -+ -+int sqlite3CodecAttach(sqlite3* db, int nDb, const void *pKey, int nKey){ -+ if(db == NULL){ -+ return SQLITE_ERROR; -+ } -+ Btree *p = db->aDb[nDb].pBt; -+ if(p == NULL || pKey == NULL || nKey <= 0){ -+ return SQLITE_OK; -+ } -+ opensslActive(); -+ CodecContext *ctx = (CodecContext *)sqlite3Malloc(sizeof(CodecContext)); -+ if(ctx == NULL){ -+ return SQLITE_NOMEM; -+ } -+ errno_t memsetRc = memset_s(ctx, sizeof(CodecContext), 0, sizeof(CodecContext)); -+ if(memsetRc != EOK){ -+ sqlite3_free(ctx); -+ return SQLITE_ERROR; -+ } -+ sqlite3_mutex_enter(db->mutex); -+#ifdef SQLITE_CODEC_ATTACH_CHANGED -+ int rc = sqlite3CodecInitContext(ctx, p, pKey, nKey, nDb); -+#else -+ int rc = sqlite3CodecInitContext(ctx, p, pKey, nKey); -+#endif /* SQLITE_CODEC_ATTACH_CHANGED */ -+ if(rc != SQLITE_OK){ -+ sqlite3_free(ctx); -+ return rc; -+ } -+ sqlite3PagerSetCodec(sqlite3BtreePager(p), sqlite3Codec, NULL, sqlite3CodecDetach, (void *)ctx); -+ -+ db->nextPagesize = ctx->readCtx->codecConst.cipherPageSize; -+ p->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED; -+ sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); -+ sqlite3BtreeSecureDelete(p, 1); -+ if(isOpen(p->pBt->pPager->fd)){ -+ sqlite3BtreeSetAutoVacuum(p, SQLITE_DEFAULT_AUTOVACUUM); -+ } -+ -+ sqlite3_mutex_leave(db->mutex); -+ -+ return SQLITE_OK; -+} -+ -+void sqlite3CodecGetKey(sqlite3* db, int nDb, void **pKey, int *nKey) -+{ -+ Btree *p = db->aDb[nDb].pBt; -+ if(p == NULL){ -+ return; -+ } -+ CodecContext *ctx = (CodecContext *)(p->pBt->pPager->pCodec); -+ if(ctx){ -+ if(ctx->savePassword){ -+ *pKey = ctx->readCtx->password; -+ *nKey = ctx->readCtx->passwordSize; -+ }else{ -+ *pKey = ctx->readCtx->keyInfo; -+ *nKey = ctx->readCtx->codecConst.keyInfoSize; -+ } -+ }else{ -+ *pKey = NULL; -+ *nKey = 0; -+ } -+ return; -+} -+ -+int sqlite3_key(sqlite3 *db, const void *pKey, int nKey){ -+ return sqlite3_key_v2(db, "main", pKey, nKey); -+} -+ -+int sqlite3_key_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey){ -+ if(db == NULL || pKey == NULL || nKey <= 0){ -+ return SQLITE_ERROR; -+ } -+ int iDb = sqlite3CodecGetDbIndex(db, zDb); -+ return sqlite3CodecAttach(db, iDb, pKey, nKey); -+} -+ -+int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey){ -+ return sqlite3_rekey_v2(db, "main", pKey, nKey); -+} -+ -+int sqlite3_rekey_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey){ -+ if(db == NULL || pKey == NULL || nKey == 0){ -+ return SQLITE_ERROR; -+ } -+ int iDb = sqlite3CodecGetDbIndex(db, zDb); -+ Btree *p = db->aDb[iDb].pBt; -+ if(p == NULL){ -+ return SQLITE_OK; -+ } -+ int pageCount; -+ Pgno pgno; -+ PgHdr *page = NULL; -+ Pager *pPager = p->pBt->pPager; -+ CodecContext *ctx = (CodecContext *)(p->pBt->pPager->pCodec); -+ if(ctx == NULL){ -+ return SQLITE_OK; -+ } -+ sqlite3CodecClearDeriveKey(ctx->writeCtx); -+ sqlite3CodecClearPassword(ctx->writeCtx); -+ int rc = sqlite3CodecSetPassword(ctx->writeCtx, pKey, nKey); -+ if(rc != SQLITE_OK){ -+ return rc; -+ } -+ sqlite3_mutex_enter(db->mutex); -+ (void)sqlite3BtreeBeginTrans(p, 1, 0); -+ sqlite3PagerPagecount(pPager, &pageCount); -+ // support hmac algo changed by using rekey operation -+ int oldHmacAlgo = ctx->writeCtx->codecConst.hmacAlgo; -+ if( ctx->writeCtx->codecConst.rekeyHmacAlgo!=ctx->writeCtx->codecConst.hmacAlgo ){ -+ sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, ctx->writeCtx->codecConst.rekeyHmacAlgo); -+ sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, ctx->writeCtx->codecConst.rekeyHmacAlgo); -+ } -+ -+ for(pgno = 1; pgno <= (unsigned int)pageCount; pgno++){ -+ if(PAGER_SJ_PGNO(pPager) != pgno){ -+ rc = sqlite3PagerGet(pPager, pgno, &page, 0); -+ if(rc == SQLITE_OK){ -+ rc = sqlite3PagerWrite(page); -+ if(rc == SQLITE_OK){ -+ sqlite3PagerUnref(page); -+ }else{ -+ sqlite3_log(SQLITE_WARNING, "sqlite3_rekey_v2: error when writing page %d: errno = %d.", pgno, rc); -+ } -+ }else{ -+ sqlite3_log(SQLITE_WARNING, "sqlite3_rekey_v2: error when reading page %d: errno = %d.", pgno, rc); -+ } -+ } -+ } -+ if(rc == SQLITE_OK){ -+ (void)sqlite3BtreeCommit(p); -+ sqlite3CodecFreeKeyContext(ctx->readCtx); -+ (void)sqlite3CodecCopyKeyContext(ctx->writeCtx, ctx->readCtx); -+ }else{ -+ if( ctx->writeCtx->codecConst.rekeyHmacAlgo!=oldHmacAlgo ){ -+ sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, oldHmacAlgo); -+ sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, oldHmacAlgo); -+ } -+ (void)sqlite3BtreeRollback(p, SQLITE_ABORT_ROLLBACK, 0); -+ } -+ sqlite3_mutex_leave(db->mutex); -+ -+ return rc; -+} -+ -+void sqlite3_activate_see(const char* zPassPhrase){ -+ return; -+} -+ -+CODEC_STATIC void sqlite3CodecReturnPragmaResult(Parse *parse, const char *label, const char *value){ -+ Vdbe *v = sqlite3GetVdbe(parse); -+ sqlite3VdbeSetNumCols(v, 1); -+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, label, SQLITE_STATIC); -+ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, value, 0); -+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); -+ return; -+} -+ -+// Each configuration setting operation should be done before read/write DB file or there might be some error. -+int sqlite3CodecPragma(sqlite3 *db, int iDb, Parse *parse, const char *zLeft, const char *zRight){ -+ Btree *p = db->aDb[iDb].pBt; -+ if(p == NULL){ -+ return 0; -+ } -+ CodecContext *ctx = (CodecContext *)(p->pBt->pPager->pCodec); -+#ifdef SQLITE_CODEC_ATTACH_CHANGED -+ CodecParameter *parm = &db->codecParm; -+ if(sqlite3StrICmp(zLeft, "cipher_default_attach_cipher") == 0 && zRight != NULL){ -+ (void)sqlite3CodecSetDefaultAttachCipher(parm, zRight); -+ return 1; -+ }else if(sqlite3StrICmp(zLeft, "cipher_default_attach_kdf_iter") == 0 && zRight != NULL){ -+ (void)sqlite3CodecSetDefaultAttachKdfIter(parm, atoi(zRight)); -+ return 1; -+ }else if( sqlite3StrICmp(zLeft, "cipher_default_attach_hmac_algo")==0 && zRight!=NULL ){ -+ /* -+ ** Make sure to set the Kdf algorithm after setting the Hmac algorithm, or it will not take effect. -+ ** This behavior is to ensure backward compatible. -+ */ -+ if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA1)==0 ){ -+ sqlite3CodecSetDefaultAttachHmacAlgo(parm, CIPHER_HMAC_ALGORITHM_SHA1); -+ sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA1); -+ }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA256)==0 ){ -+ sqlite3CodecSetDefaultAttachHmacAlgo(parm, CIPHER_HMAC_ALGORITHM_SHA256); -+ sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA256); -+ }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA512)==0 ){ -+ sqlite3CodecSetDefaultAttachHmacAlgo(parm, CIPHER_HMAC_ALGORITHM_SHA512); -+ sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA512); -+ }else{ -+ return 0; -+ } -+ return 1; -+ }else if( sqlite3StrICmp(zLeft, "cipher_default_attach_kdf_algo")==0 && zRight!=NULL ){ -+ if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA1)==0 ){ -+ sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA1); -+ }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA256)==0 ){ -+ sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA256); -+ }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA512)==0 ){ -+ sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA512); -+ }else{ -+ return 0; -+ } -+ return 1; -+ }else if( sqlite3StrICmp(zLeft, "cipher_default_attach_page_size")==0 && zRight!=NULL ){ -+ (void)sqlite3CodecSetDefaultAttachPageSize(parm, atoi(zRight)); -+ return 1; -+ } -+#endif /* SQLITE_CODEC_ATTACH_CHANGED */ -+ if(ctx == NULL){ -+ return 0; -+ } -+ if(sqlite3StrICmp(zLeft, "codec_cipher") == 0){ -+ if(zRight){ -+ sqlite3_mutex_enter(db->mutex); -+ (void)sqlite3CodecSetCodecConstant(ctx->readCtx, zRight); -+ (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, ctx->readCtx->codecConst.hmacAlgo); -+ (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, ctx->readCtx->codecConst.hmacAlgo); -+ sqlite3CodecFreeKeyContext(ctx->writeCtx); -+ (void)sqlite3CodecCopyKeyContext(ctx->readCtx, ctx->writeCtx); -+ sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); -+ sqlite3_mutex_leave(db->mutex); -+ }else{ -+ sqlite3CodecReturnPragmaResult(parse, "codec_cipher", opensslGetCipherName(ctx->writeCtx->codecConst.cipher)); -+ } -+ }else if(sqlite3StrICmp(zLeft, "codec_kdf_iter") == 0){ -+ if(zRight){ -+ (void)sqlite3CodecSetIter(ctx->readCtx, atoi(zRight)); -+ (void)sqlite3CodecSetIter(ctx->writeCtx, atoi(zRight)); -+ }else{ -+ char *iter = sqlite3_mprintf("%d", ctx->writeCtx->iter); -+ if(iter != NULL){ -+ sqlite3CodecReturnPragmaResult(parse, "codec_kdf_iter", iter); -+ sqlite3_free(iter); -+ } -+ } -+ }else if( sqlite3StrICmp(zLeft, "codec_hmac_algo")==0 ){ -+ /* -+ ** Make sure to set the Kdf algorithm after setting the Hmac algorithm, or it will not take effect. -+ ** This behavior is to ensure backward compatible. -+ */ -+ if(zRight){ -+ sqlite3_mutex_enter(db->mutex); -+ if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA1)==0 ){ -+ (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, CIPHER_HMAC_ALGORITHM_SHA1); -+ (void)sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, CIPHER_HMAC_ALGORITHM_SHA1); -+ (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA1); -+ (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA1); -+ }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA256)==0 ){ -+ (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, CIPHER_HMAC_ALGORITHM_SHA256); -+ (void)sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, CIPHER_HMAC_ALGORITHM_SHA256); -+ (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA256); -+ (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA256); -+ }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA512)==0 ){ -+ (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, CIPHER_HMAC_ALGORITHM_SHA512); -+ (void)sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, CIPHER_HMAC_ALGORITHM_SHA512); -+ (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA512); -+ (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA512); -+ }else{ -+ sqlite3_mutex_leave(db->mutex); -+ return 0; -+ } -+ sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); -+ sqlite3_mutex_leave(db->mutex); -+ }else{ -+ if( ctx->writeCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){ -+ sqlite3CodecReturnPragmaResult(parse, "codec_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA1); -+ }else if( ctx->writeCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){ -+ sqlite3CodecReturnPragmaResult(parse, "codec_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA256); -+ }else if( ctx->writeCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){ -+ sqlite3CodecReturnPragmaResult(parse, "codec_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA512); -+ } -+ } -+ }else if( sqlite3StrICmp(zLeft, "codec_kdf_algo")==0 ){ -+ if(zRight){ -+ sqlite3_mutex_enter(db->mutex); -+ if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA1)==0 ){ -+ (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA1); -+ (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA1); -+ }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA256)==0 ){ -+ (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA256); -+ (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA256); -+ }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA512)==0 ){ -+ (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA512); -+ (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA512); -+ }else{ -+ sqlite3_mutex_leave(db->mutex); -+ return 0; -+ } -+ sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); -+ sqlite3_mutex_leave(db->mutex); -+ }else{ -+ if( ctx->writeCtx->codecConst.kdfAlgo==CIPHER_KDF_ALGORITHM_SHA1 ){ -+ sqlite3CodecReturnPragmaResult(parse, "codec_kdf_algo", CIPHER_KDF_ALGORITHM_NAME_SHA1); -+ }else if( ctx->writeCtx->codecConst.kdfAlgo==CIPHER_KDF_ALGORITHM_SHA256 ){ -+ sqlite3CodecReturnPragmaResult(parse, "codec_kdf_algo", CIPHER_KDF_ALGORITHM_NAME_SHA256); -+ }else if( ctx->writeCtx->codecConst.kdfAlgo==CIPHER_KDF_ALGORITHM_SHA512 ){ -+ sqlite3CodecReturnPragmaResult(parse, "codec_kdf_algo", CIPHER_KDF_ALGORITHM_NAME_SHA512); -+ } -+ } -+ }else if( sqlite3StrICmp(zLeft, "codec_page_size")==0 ){ -+ if(zRight){ -+ sqlite3_mutex_enter(db->mutex); -+ int rc = sqlite3CodecSetCipherPageSize(ctx, atoi(zRight)); -+ if (rc != SQLITE_OK){ -+ sqlite3_mutex_leave(db->mutex); -+ return 0; -+ } -+ sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); -+ sqlite3_mutex_leave(db->mutex); -+ } else { -+ char *pageSize = sqlite3_mprintf("%d", ctx->readCtx->codecConst.cipherPageSize); -+ if (pageSize != NULL) { -+ sqlite3CodecReturnPragmaResult(parse, "codec_page_size", pageSize); -+ sqlite3_free(pageSize); -+ } -+ } -+ }else if(sqlite3StrICmp(zLeft, "codec_rekey_hmac_algo") == 0){ -+ if(zRight){ -+ sqlite3_mutex_enter(db->mutex); -+ if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA1)==0 ){ -+ ctx->writeCtx->codecConst.rekeyHmacAlgo = CIPHER_HMAC_ALGORITHM_SHA1; -+ }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA256)==0 ){ -+ ctx->writeCtx->codecConst.rekeyHmacAlgo = CIPHER_HMAC_ALGORITHM_SHA256; -+ }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA512)==0 ){ -+ ctx->writeCtx->codecConst.rekeyHmacAlgo = CIPHER_HMAC_ALGORITHM_SHA512; -+ }else{ -+ sqlite3_mutex_leave(db->mutex); -+ return 0; -+ } -+ sqlite3_mutex_leave(db->mutex); -+ }else{ -+ if( ctx->writeCtx->codecConst.rekeyHmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){ -+ sqlite3CodecReturnPragmaResult(parse, "codec_rekey_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA1); -+ }else if( ctx->writeCtx->codecConst.rekeyHmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){ -+ sqlite3CodecReturnPragmaResult(parse, "codec_rekey_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA256); -+ }else if( ctx->writeCtx->codecConst.rekeyHmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){ -+ sqlite3CodecReturnPragmaResult(parse, "codec_rekey_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA512); -+ } -+ } -+ }else{ -+ return 0; -+ } -+ return 1; -+} -+ -+CODEC_STATIC int sqlite3CodecExportMetadata(sqlite3 *db, const char *dbName, const char *metaName){ -+ char *sql = sqlite3_mprintf("PRAGMA %s;", metaName); -+ if(sql == NULL){ -+ return SQLITE_NOMEM; -+ } -+ sqlite3_stmt *statement = NULL; -+ int rc = sqlite3_prepare_v2(db, sql, -1, &statement, NULL); -+ sqlite3_free(sql); -+ if(rc != SQLITE_OK){ -+ return rc; -+ } -+ rc = sqlite3_step(statement); -+ if(rc != SQLITE_ROW){ -+ sqlite3_finalize(statement); -+ return rc; -+ } -+ int metadata = sqlite3_column_int(statement, 0); -+ sqlite3_finalize(statement); -+ -+ sql = sqlite3_mprintf("PRAGMA %s.%s=%d;", dbName, metaName, metadata); -+ if(sql == NULL){ -+ return SQLITE_NOMEM; -+ } -+ rc = sqlite3_exec(db, sql, NULL, NULL, NULL); -+ sqlite3_free(sql); -+ return rc; -+} -+ -+CODEC_STATIC int sqlite3CodecBatchExportSql(sqlite3 *db, const char *sql, char **errMsg){ -+ sqlite3_stmt *statement = NULL; -+ int rc = sqlite3_prepare_v2(db, sql, -1, &statement, NULL); -+ if(rc != SQLITE_OK){ -+ return rc; -+ } -+ while(sqlite3_step(statement) == SQLITE_ROW){ -+ rc = sqlite3_exec(db, (char*)sqlite3_column_text(statement, 0), NULL, NULL, errMsg); -+ if(rc != SQLITE_OK){ -+ sqlite3_finalize(statement); -+ return rc; -+ } -+ } -+ sqlite3_finalize(statement); -+ return rc; -+} -+ -+void sqlite3CodecExportData(sqlite3_context *context, int argc, sqlite3_value **argv){ -+ sqlite3 *db = sqlite3_context_db_handle(context); -+ const char *dbName = (const char*) sqlite3_value_text(argv[0]); -+ -+ int rc = SQLITE_OK; -+ char *sql = NULL; -+ char *errMsg = NULL; -+ -+ u64 flagsBackup = db->flags; -+ u32 mDbFlagsBackup = db->mDbFlags; -+ int nChangeBackup = db->nChange; -+ int nTotalChangeBackup = db->nTotalChange; -+ int (*xTraceBackup)(u32,void*,void*,void*) = db->trace.xV2; -+ -+ db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; -+ db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder); -+ db->mDbFlags |= DBFLAG_PreferBuiltin; -+ db->trace.xV2 = 0; -+ -+ rc = sqlite3CodecExportMetadata(db, dbName, "schema_version"); -+ if(rc != SQLITE_OK){ -+ goto export_finish; -+ } -+ rc = sqlite3CodecExportMetadata(db, dbName, "user_version"); -+ if(rc != SQLITE_OK){ -+ goto export_finish; -+ } -+ rc = sqlite3CodecExportMetadata(db, dbName, "application_id"); -+ if(rc != SQLITE_OK){ -+ goto export_finish; -+ } -+ sql = sqlite3_mprintf("SELECT 'CREATE TABLE %s.' || substr(sql,14) FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence' AND rootpage>0;", dbName); -+ if(sql == NULL){ -+ rc = SQLITE_NOMEM; -+ goto export_finish; -+ } -+ rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); -+ sqlite3_free(sql); -+ if(rc != SQLITE_OK){ -+ goto export_finish; -+ } -+ sql = sqlite3_mprintf("SELECT 'CREATE INDEX %s.' || substr(sql,14) FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %%';", dbName); -+ if(sql == NULL){ -+ rc = SQLITE_NOMEM; -+ goto export_finish; -+ } -+ rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); -+ sqlite3_free(sql); -+ if(rc != SQLITE_OK){ -+ goto export_finish; -+ } -+ sql = sqlite3_mprintf("SELECT 'CREATE UNIQUE INDEX %s.' || substr(sql,21) FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%';", dbName); -+ if(sql == NULL){ -+ rc = SQLITE_NOMEM; -+ goto export_finish; -+ } -+ rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); -+ sqlite3_free(sql); -+ if(rc != SQLITE_OK){ -+ goto export_finish; -+ } -+ sql = sqlite3_mprintf("SELECT 'INSERT INTO %s.' || quote(name) || ' SELECT * FROM main.' || quote(name) || ';' FROM main.sqlite_master WHERE type = 'table' AND name!='sqlite_sequence' AND rootpage>0;", dbName); -+ if(sql == NULL){ -+ rc = SQLITE_NOMEM; -+ goto export_finish; -+ } -+ rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); -+ sqlite3_free(sql); -+ if(rc != SQLITE_OK){ -+ goto export_finish; -+ } -+ sql = sqlite3_mprintf("SELECT 'DELETE FROM %s.' || quote(name) || ';' FROM %s.sqlite_master WHERE name='sqlite_sequence';", dbName, dbName); -+ if(sql == NULL){ -+ rc = SQLITE_NOMEM; -+ goto export_finish; -+ } -+ rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); -+ sqlite3_free(sql); -+ if(rc != SQLITE_OK){ -+ goto export_finish; -+ } -+ sql = sqlite3_mprintf("SELECT 'INSERT INTO %s.' || quote(name) || ' SELECT * FROM main.' || quote(name) || ';' FROM %s.sqlite_master WHERE name=='sqlite_sequence';", dbName, dbName); -+ if(sql == NULL){ -+ rc = SQLITE_NOMEM; -+ goto export_finish; -+ } -+ rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); -+ sqlite3_free(sql); -+ if(rc != SQLITE_OK){ -+ goto export_finish; -+ } -+ sql = sqlite3_mprintf("INSERT INTO %s.sqlite_master SELECT type, name, tbl_name, rootpage, sql FROM main.sqlite_master WHERE type='view' OR type='trigger' OR (type='table' AND rootpage=0);", dbName, dbName); -+ if(sql == NULL){ -+ rc = SQLITE_NOMEM; -+ goto export_finish; -+ } -+ rc = sqlite3_exec(db, sql, NULL, NULL, &errMsg); -+ sqlite3_free(sql); -+ if(rc != SQLITE_OK){ -+ goto export_finish; -+ } -+export_finish: -+ db->flags = flagsBackup; -+ db->mDbFlags = mDbFlagsBackup; -+ db->nChange = nChangeBackup; -+ db->nTotalChange = nTotalChangeBackup; -+ db->trace.xV2 = xTraceBackup; -+ if(rc != SQLITE_OK){ -+ if(errMsg != NULL) { -+ sqlite3_result_error(context, errMsg, -1); -+ sqlite3DbFree(db, errMsg); -+ } else { -+ sqlite3_result_error(context, sqlite3ErrStr(rc), -1); -+ } -+ } -+ return; -+} -+/************** End file hw_codec.c *****************************************/ -+#endif /* SQLITE_HAS_CODEC */ -+ -+ -+#ifdef SQLITE_EXPORT_SYMBOLS -+/************** Begin hw export the symbols *****************************************/ -+#if defined(__GNUC__) -+# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) -+#elif defined(_MSC_VER) -+# define EXPORT_SYMBOLS __declspec(dllexport) -+#else -+# define EXPORT_SYMBOLS -+#endif -+ -+struct sqlite3_api_routines_hw { -+ int (*initialize)(); -+ int (*config)(int,...); -+ int (*key)(sqlite3*,const void*,int); -+ int (*key_v2)(sqlite3*,const char*,const void*,int); -+ int (*rekey)(sqlite3*,const void*,int); -+ int (*rekey_v2)(sqlite3*,const char*,const void*,int); -+}; -+ -+typedef struct sqlite3_api_routines_hw sqlite3_api_routines_hw; -+static const sqlite3_api_routines_hw sqlite3HwApis = { -+ sqlite3_initialize, -+ sqlite3_config, -+#ifdef SQLITE_HAS_CODEC -+ sqlite3_key, -+ sqlite3_key_v2, -+ sqlite3_rekey, -+ sqlite3_rekey_v2 -+#else -+ 0, -+ 0, -+ 0, -+ 0 -+#endif /* SQLITE_HAS_CODEC */ -+}; -+ -+EXPORT_SYMBOLS const sqlite3_api_routines *sqlite3_export_symbols = &sqlite3Apis; -+EXPORT_SYMBOLS const sqlite3_api_routines_hw *sqlite3_export_hw_symbols = &sqlite3HwApis; -+/************** End hw export the symbols *****************************************/ -+#endif /* SQLITE_EXPORT_SYMBOLS */ --- -2.46.0.windows.1 - diff --git a/patch/0002-busy-debug.patch b/patch/0002-busy-debug.patch deleted file mode 100644 index 8fd1663..0000000 --- a/patch/0002-busy-debug.patch +++ /dev/null @@ -1,813 +0,0 @@ -From 4a29b0e98e03fea216795394ac340104e2e1bbfa Mon Sep 17 00:00:00 2001 -From: ryne3366 -Date: Tue, 25 Feb 2025 11:25:32 +0800 -Subject: [PATCH] suport busy debug - -Signed-off-by: ryne3366 ---- - src/sqlite3.c | 368 ++++++++++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 355 insertions(+), 13 deletions(-) - -diff --git a/src/sqlite3.c b/src/sqlite3.c -index d2bfc23..1ec1ae9 100644 ---- a/src/sqlite3.c -+++ b/src/sqlite3.c -@@ -38490,6 +38490,45 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){ - #endif - - /************** End of os_kv.c ***********************************************/ -+/************** Define dump function *****************************************/ -+#if SQLITE_OS_UNIX -+#define DB_LOCK_NUM 3 -+#define WAL_LOCK_NUM 9 -+// 8 wal lock, 1 SHM_DMS lock, 1 TRX lock -+#define MAX_LOCK_NUM (WAL_LOCK_NUM + 1) -+#define SHM_DMS_IDX (WAL_LOCK_NUM - 1) -+#define TRX_LOCK_IDX WAL_LOCK_NUM -+#define LOCK_BY_PROCESS 1 -+#define LOCK_BY_THREAD 0 -+#define DUMP_BUF_MAX_LEN 180 -+#define DUMP_MAX_STR_LEN 21 -+ -+typedef struct LocalLockStatus { -+ u8 busyLockIdx; -+ u8 busyLockType; -+ u8 lockByProcess; -+ u8 reserved; -+ u32 lockLen; -+ u32 busyLine; -+ int curTid; -+ u8 lockStatus[MAX_LOCK_NUM]; // last index is trx lock -+} LocalLockStatus; -+__thread LocalLockStatus g_lockStatus = {0}; -+ -+#define MARK_LAST_BUSY_LINE(rc) {if ((rc)==SQLITE_BUSY || (rc) == SQLITE_LOCKED) g_lockStatus.busyLine = __LINE__;} -+static void ResetLockStatus(void); -+static void TryRecordTid(int *tidBuf, int ofs, int lockLen); -+static void TryClearTid(int *tidBuf, int ofs, int lockLen); -+static void MarkLockBusy(u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess); -+static void MarkLockStatus(u32 lockIdx, u32 lockLen, u8 lockType); -+static void MarkLockStatusByRc(int rc, u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess); -+#else -+#define MARK_LAST_BUSY_LINE(rc) -+#define ResetLockStatus(void) -+#define MarkLockBusy(A, B, C, D) -+#define MarkLockStatusByRc(A, B, C, D, E) -+#endif -+/************** End define dump function *************************************/ - /************** Begin file os_unix.c *****************************************/ - /* - ** 2004 May 22 -@@ -40313,6 +40352,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ - if( pFile->eFileLock>=eFileLock ){ - OSTRACE(("LOCK %d %s ok (already held) (unix)\n", pFile->h, - azFileLock(eFileLock))); -+ MarkLockStatus(TRX_LOCK_IDX, 1, eFileLock); - return SQLITE_OK; - } - -@@ -40337,6 +40377,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ - (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK)) - ){ - rc = SQLITE_BUSY; -+ MarkLockBusy(TRX_LOCK_IDX, 1, eFileLock, LOCK_BY_THREAD); - goto end_lock; - } - -@@ -40352,6 +40393,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ - pFile->eFileLock = SHARED_LOCK; - pInode->nShared++; - pInode->nLock++; -+ MarkLockStatus(TRX_LOCK_IDX, 1, eFileLock); - goto end_lock; - } - -@@ -40373,6 +40415,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ - if( rc!=SQLITE_BUSY ){ - storeLastErrno(pFile, tErrno); - } -+ MarkLockStatusByRc(rc, TRX_LOCK_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS); - goto end_lock; - }else if( eFileLock==EXCLUSIVE_LOCK ){ - pFile->eFileLock = PENDING_LOCK; -@@ -40380,7 +40423,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){ - } - } - -- - /* If control gets to this point, then actually go ahead and make - ** operating system calls for the specified lock. - */ -@@ -40396,7 +40438,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ - tErrno = errno; - rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); - } -- -+ MarkLockStatusByRc(rc, TRX_LOCK_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS); - /* Drop the temporary PENDING lock */ - lock.l_start = PENDING_BYTE; - lock.l_len = 1L; -@@ -40421,6 +40463,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ - /* We are trying for an exclusive lock but another thread in this - ** same process is still holding a shared lock. */ - rc = SQLITE_BUSY; -+ MarkLockBusy(TRX_LOCK_IDX, 1, eFileLock, LOCK_BY_THREAD); - }else{ - /* The request was for a RESERVED or EXCLUSIVE lock. It is - ** assumed that there is a SHARED or greater lock on the file -@@ -40445,6 +40488,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ - storeLastErrno(pFile, tErrno); - } - } -+ MarkLockStatusByRc(rc, TRX_LOCK_IDX, 1, eFileLock, LOCK_BY_PROCESS); - } - - -@@ -40638,7 +40682,6 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ - pFile->eFileLock = NO_LOCK; - } - } -- - /* Decrement the count of locks against this same file. When the - ** count reaches zero, close any other file descriptors whose close - ** was deferred because of outstanding locks. -@@ -42948,6 +42991,7 @@ struct unixShmNode { - sqlite3_mutex *aMutex[SQLITE_SHM_NLOCK]; - #endif - int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */ -+ int aLockTid[SQLITE_SHM_NLOCK]; - #ifdef SQLITE_DEBUG - u8 nextShmId; /* Next available unixShm.id value */ - #endif -@@ -43214,6 +43258,8 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ - #ifdef SQLITE_ENABLE_SETLK_TIMEOUT - pDbFd->iBusyTimeout = iSaveTimeout; - #endif -+ MarkLockStatusByRc(rc, SHM_DMS_IDX, 1, EXCLUSIVE_LOCK, LOCK_BY_PROCESS); -+ MARK_LAST_BUSY_LINE(rc); - /* 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 -@@ -43225,11 +43271,15 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ - } - }else if( lock.l_type==F_WRLCK ){ - rc = SQLITE_BUSY; -+ MarkLockStatusByRc(rc, SHM_DMS_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS); -+ MARK_LAST_BUSY_LINE(rc); - } - - if( rc==SQLITE_OK ){ - assert( lock.l_type==F_UNLCK || lock.l_type==F_RDLCK ); - rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1); -+ MarkLockStatusByRc(rc, SHM_DMS_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS); -+ MARK_LAST_BUSY_LINE(rc); - } - return rc; - } -@@ -43629,7 +43679,7 @@ static int unixShmLock( - return SQLITE_IOERR_SHMLOCK; - } - aLock = pShmNode->aLock; -- -+ int *aLockTid = pShmNode->aLockTid; - assert( pShmNode==pDbFd->pInode->pShmNode ); - assert( pShmNode->pInode==pDbFd->pInode ); - assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK ); -@@ -43679,6 +43729,7 @@ static int unixShmLock( - assert( flags!=(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK) - || 0==(p->exclMask & mask) - ); -+ u8 useProcessLock = LOCK_BY_THREAD; - 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)) -@@ -43734,7 +43785,7 @@ static int unixShmLock( - p->sharedMask &= ~mask; - } - } -- -+ MarkLockStatusByRc(rc, ofst, n, NO_LOCK, useProcessLock); - if( bUnlock ){ - rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n); - if( rc==SQLITE_OK ){ -@@ -43742,6 +43793,8 @@ static int unixShmLock( - p->sharedMask &= ~mask; - p->exclMask &= ~mask; - } -+ useProcessLock = LOCK_BY_PROCESS; -+ TryClearTid(aLockTid, ofst, n); - } - }else if( flags & SQLITE_SHM_SHARED ){ - /* Case (b) - a shared lock. */ -@@ -43751,12 +43804,14 @@ static int unixShmLock( - rc = SQLITE_BUSY; - }else if( aLock[ofst]==0 ){ - rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n); -+ useProcessLock = LOCK_BY_PROCESS; - } -- -+ MarkLockStatusByRc(rc, ofst, n, SHARED_LOCK, useProcessLock); - /* Get the local shared locks */ - if( rc==SQLITE_OK ){ - p->sharedMask |= mask; - aLock[ofst]++; -+ TryRecordTid(aLockTid, ofst, n); - } - }else{ - /* Case (c) - an exclusive lock. */ -@@ -43774,7 +43829,7 @@ static int unixShmLock( - break; - } - } -- -+ useProcessLock = LOCK_BY_PROCESS; - /* Get the exclusive locks at the system level. Then if successful - ** also update the in-memory values. */ - if( rc==SQLITE_OK ){ -@@ -43784,8 +43839,10 @@ static int unixShmLock( - for(ii=ofst; iinoSync ){ -@@ -62796,6 +62854,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){ - sqlite3OsDelete(pVfs, pPager->zJournal, 0); - if( !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK); - } -+ MARK_LAST_BUSY_LINE(rc); - sqlite3EndBenignMalloc(); - }else{ - /* The journal file exists and no other connection has a reserved -@@ -62885,6 +62944,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ - assert( pPager->tempFile==0 || pPager->eLock==EXCLUSIVE_LOCK ); - - rc = pager_wait_on_lock(pPager, SHARED_LOCK); -+ MARK_LAST_BUSY_LINE(rc); - if( rc!=SQLITE_OK ){ - assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK ); - goto failed; -@@ -62921,6 +62981,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ - ** downgraded to SHARED_LOCK before this function returns. - */ - rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); -+ MARK_LAST_BUSY_LINE(rc); - if( rc!=SQLITE_OK ){ - goto failed; - } -@@ -63553,6 +63614,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory - */ - if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){ - rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); -+ MARK_LAST_BUSY_LINE(rc); - if( rc!=SQLITE_OK ){ - return rc; - } -@@ -63565,6 +63627,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory - ** holds the write-lock. If possible, the upper layer will call it. - */ - rc = sqlite3WalBeginWriteTransaction(pPager->pWal); -+ MARK_LAST_BUSY_LINE(rc); - }else{ - /* Obtain a RESERVED lock on the database file. If the exFlag parameter - ** is true, then immediately upgrade this to an EXCLUSIVE lock. The -@@ -63572,8 +63635,10 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory - ** lock, but not when obtaining the RESERVED lock. - */ - rc = pagerLockDb(pPager, RESERVED_LOCK); -+ MARK_LAST_BUSY_LINE(rc); - if( rc==SQLITE_OK && exFlag ){ - rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); -+ MARK_LAST_BUSY_LINE(rc); - } - } - -@@ -65085,6 +65150,7 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ - if( pPager->eState==PAGER_READER ){ - assert( rc==SQLITE_OK ); - rc = pagerLockDb(pPager, RESERVED_LOCK); -+ MARK_LAST_BUSY_LINE(rc); - } - if( rc==SQLITE_OK ){ - sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); -@@ -65251,6 +65317,7 @@ static int pagerOpenWal(Pager *pPager){ - */ - if( pPager->exclusiveMode ){ - rc = pagerExclusiveLock(pPager); -+ MARK_LAST_BUSY_LINE(rc); - } - - /* Open the connection to the log file. If this operation fails, -@@ -65334,6 +65401,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){ - if( !pPager->pWal ){ - int logexists = 0; - rc = pagerLockDb(pPager, SHARED_LOCK); -+ MARK_LAST_BUSY_LINE(rc); - if( rc==SQLITE_OK ){ - rc = sqlite3OsAccess( - pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &logexists -@@ -65349,6 +65417,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){ - */ - if( rc==SQLITE_OK && pPager->pWal ){ - rc = pagerExclusiveLock(pPager); -+ MARK_LAST_BUSY_LINE(rc); - if( rc==SQLITE_OK ){ - rc = sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, - pPager->pageSize, (u8*)pPager->pTmpSpace); -@@ -66883,6 +66952,7 @@ static int walIndexRecover(Wal *pWal){ - iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock; - rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock); - if( rc ){ -+ MARK_LAST_BUSY_LINE(rc); - return rc; - } - -@@ -67720,6 +67790,7 @@ static int walCheckpoint( - if( mxSafeFrame>y ){ - assert( y<=pWal->hdr.mxFrame ); - rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1); -+ MARK_LAST_BUSY_LINE(rc); - if( rc==SQLITE_OK ){ - u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED); - AtomicStore(pInfo->aReadMark+i, iMark); SEH_INJECT_FAULT; -@@ -67814,6 +67885,8 @@ static int walCheckpoint( - - /* Release the reader lock held while backfilling */ - walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1); -+ } else { -+ MARK_LAST_BUSY_LINE(rc); - } - - if( rc==SQLITE_BUSY ){ -@@ -67833,11 +67906,13 @@ static int walCheckpoint( - SEH_INJECT_FAULT; - if( pInfo->nBackfillhdr.mxFrame ){ - rc = SQLITE_BUSY; -+ MARK_LAST_BUSY_LINE(rc); - }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){ - u32 salt1; - sqlite3_randomness(4, &salt1); - assert( pInfo->nBackfill==pWal->hdr.mxFrame ); - rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1); -+ MARK_LAST_BUSY_LINE(rc); - if( rc==SQLITE_OK ){ - if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){ - /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as -@@ -68025,8 +68100,9 @@ SQLITE_PRIVATE int sqlite3WalClose( - walLimitSize(pWal, 0); - } - } -+ } else { -+ MARK_LAST_BUSY_LINE(rc); - } -- - walIndexClose(pWal, isDelete); - sqlite3OsClose(pWal->pWalFd); - if( isDelete ){ -@@ -68179,6 +68255,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ - walUnlockShared(pWal, WAL_WRITE_LOCK); - rc = SQLITE_READONLY_RECOVERY; - } -+ MARK_LAST_BUSY_LINE(rc); - }else{ - int bWriteLock = pWal->writeLock; - if( bWriteLock -@@ -68202,6 +68279,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ - walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); - } - } -+ MARK_LAST_BUSY_LINE(rc); - } - } - -@@ -68221,6 +68299,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ - ** writer truncated the WAL out from under it. If that happens, it - ** indicates that a writer has fixed the SHM file for us, so retry */ - if( rc==SQLITE_IOERR_SHORT_READ ) rc = WAL_RETRY; -+ MARK_LAST_BUSY_LINE(rc); - } - pWal->exclusiveMode = WAL_NORMAL_MODE; - } -@@ -68483,6 +68562,7 @@ 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 void DumpLocksByWal(Wal *pWal); - static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ - volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */ - u32 mxReadMark; /* Largest aReadMark[] value */ -@@ -68525,6 +68605,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ - return SQLITE_PROTOCOL; - } - if( *pCnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39; -+#if SQLITE_OS_UNIX -+ if( cnt>=15 ) DumpLocksByWal(pWal); -+#endif /* SQLITE_OS_UNIX */ - #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 -@@ -68576,11 +68659,14 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ - ** must be zeroed before the requested page is returned. - */ - rc = WAL_RETRY; -+ MARK_LAST_BUSY_LINE(SQLITE_BUSY); - }else if( SQLITE_OK==(rc = walLockShared(pWal, WAL_RECOVER_LOCK)) ){ - walUnlockShared(pWal, WAL_RECOVER_LOCK); - rc = WAL_RETRY; -+ MARK_LAST_BUSY_LINE(SQLITE_BUSY); - }else if( rc==SQLITE_BUSY ){ - rc = SQLITE_BUSY_RECOVERY; -+ MARK_LAST_BUSY_LINE(SQLITE_BUSY); - } - } - if( rc!=SQLITE_OK ){ -@@ -68604,6 +68690,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ - ** and can be safely ignored. - */ - rc = walLockShared(pWal, WAL_READ_LOCK(0)); -+ MARK_LAST_BUSY_LINE(SQLITE_BUSY); - walShmBarrier(pWal); - if( rc==SQLITE_OK ){ - if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){ -@@ -68621,6 +68708,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ - ** it finished. Leaving a corrupt image in the database file. - */ - walUnlockShared(pWal, WAL_READ_LOCK(0)); -+ MARK_LAST_BUSY_LINE(SQLITE_BUSY); - return WAL_RETRY; - } - pWal->readLock = 0; -@@ -68665,6 +68753,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ - }else if( rc!=SQLITE_BUSY ){ - return rc; - } -+ MARK_LAST_BUSY_LINE(rc); - } - } - if( mxI==0 ){ -@@ -68684,6 +68773,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ - assert( rc!=SQLITE_BUSY_TIMEOUT ); - #endif - assert( (rc&0xFF)!=SQLITE_BUSY||rc==SQLITE_BUSY||rc==SQLITE_BUSY_TIMEOUT ); -+ MARK_LAST_BUSY_LINE(rc); - return (rc&0xFF)==SQLITE_BUSY ? WAL_RETRY : rc; - } - /* Now that the read-lock has been obtained, check that neither the -@@ -68726,6 +68816,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ - || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) - ){ - walUnlockShared(pWal, WAL_READ_LOCK(mxI)); -+ MARK_LAST_BUSY_LINE(rc); - return WAL_RETRY; - }else{ - assert( mxReadMark<=pWal->hdr.mxFrame ); -@@ -68863,7 +68954,7 @@ static int walBeginReadTransaction(Wal *pWal, int *pChanged){ - (void)walEnableBlocking(pWal); - rc = walLockShared(pWal, WAL_CKPT_LOCK); - walDisableBlocking(pWal); -- -+ MARK_LAST_BUSY_LINE(rc); - if( rc!=SQLITE_OK ){ - return rc; - } -@@ -69810,6 +69901,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( - ** it will not be invoked in this case. - */ - rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); -+ MARK_LAST_BUSY_LINE(rc); - testcase( rc==SQLITE_BUSY ); - testcase( rc!=SQLITE_OK && xBusy2!=0 ); - if( rc==SQLITE_OK ){ -@@ -69826,6 +69918,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( - */ - if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){ - rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1); -+ MARK_LAST_BUSY_LINE(rc); - if( rc==SQLITE_OK ){ - pWal->writeLock = 1; - }else if( rc==SQLITE_BUSY ){ -@@ -73685,6 +73778,7 @@ static void pageReinit(DbPage *pData){ - } - } - -+static void DumpLocksByPager(Pager *pPager); - /* - ** Invoke the busy handler for a btree. - */ -@@ -73692,7 +73786,13 @@ static int btreeInvokeBusyHandler(void *pArg){ - BtShared *pBt = (BtShared*)pArg; - assert( pBt->db ); - assert( sqlite3_mutex_held(pBt->db->mutex) ); -- return sqlite3InvokeBusyHandler(&pBt->db->busyHandler); -+ int rc = sqlite3InvokeBusyHandler(&pBt->db->busyHandler); -+#if SQLITE_OS_UNIX -+ if (rc == 0) { -+ DumpLocksByPager(pBt->pPager); -+ } -+#endif /* SQLITE_OS_UNIX */ -+ return rc; - } - - /* -@@ -74123,7 +74223,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){ - } - } - #endif -- -+ ResetLockStatus(); - /* Rollback any active transaction and free the handle structure. - ** The call to sqlite3BtreeRollback() drops any table-locks held by - ** this handle. -@@ -74788,7 +74888,7 @@ static SQLITE_NOINLINE int btreeBeginTrans( - - sqlite3BtreeEnter(p); - btreeIntegrity(p); -- -+ ResetLockStatus(); - /* If the btree is already in a write-transaction, or it - ** is already in a read-transaction and a read-transaction - ** is requested, this is a no-op. -@@ -82419,8 +82519,10 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int * - if( p ){ - BtShared *pBt = p->pBt; - sqlite3BtreeEnter(p); -+ ResetLockStatus(); - if( pBt->inTransaction!=TRANS_NONE ){ - rc = SQLITE_LOCKED; -+ MARK_LAST_BUSY_LINE(rc); - }else{ - rc = sqlite3PagerCheckpoint(pBt->pPager, p->db, eMode, pnLog, pnCkpt); - } -@@ -88466,6 +88568,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ - nTrans++; - } - rc = sqlite3PagerExclusiveLock(pPager); -+ MARK_LAST_BUSY_LINE(rc); - sqlite3BtreeLeave(pBt); - } - } -@@ -260441,9 +260544,248 @@ export_finish: - return; - } - /************** End file hw_codec.c *****************************************/ --#endif /* SQLITE_HAS_CODEC */ -+#endif - -+#if SQLITE_OS_UNIX -+#include -+#include -+static inline int OsGetTid(void) -+{ -+#if defined(__linux__) -+ return (int)syscall(__NR_gettid); -+#elif defined(__APPLE__) -+ return (int)syscall(SYS_thread_selfid); -+#else -+ return 0; -+#endif -+} -+ -+static void ResetLockStatus(void) -+{ -+ (void)memset(&g_lockStatus, 0, sizeof(g_lockStatus)); -+ g_lockStatus.curTid = OsGetTid(); -+} -+/* -+** Record lock info, correspond wal aLock buf, 1 aLock: 1 -+*/ -+static inline void TryRecordTid(int *tidBuf, int ofs, int lockLen) -+{ -+ int lockOfs = ofs + lockLen; -+ for (int i = ofs; i < lockOfs; i++) { -+ if (tidBuf[i] == 0) { -+ tidBuf[i] = g_lockStatus.curTid; -+ } -+ } -+} -+/* -+** Clear locks info. -+*/ -+static inline void TryClearTid(int *tidBuf, int ofs, int lockLen) -+{ -+ int lockOfs = ofs + lockLen; -+ for (int i = ofs; i < lockOfs; i++) { -+ if (tidBuf[i] == g_lockStatus.curTid) { -+ tidBuf[i] = 0; -+ } -+ } -+} -+ -+static inline void MarkLockBusy(u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess) -+{ -+ g_lockStatus.busyLockIdx = lockIdx; -+ g_lockStatus.busyLockType = lockType; -+ g_lockStatus.lockByProcess = lockByProcess; -+ g_lockStatus.lockLen = lockLen; -+} -+ -+static void MarkLockStatus(u32 lockIdx, u32 lockLen, u8 lockType) -+{ -+ if (lockLen == 0 || (lockIdx + lockLen) > MAX_LOCK_NUM) { -+ sqlite3_log(SQLITE_ERROR, "Unexpect lock index %u lockLen %d!", lockIdx, lockLen); -+ return; -+ } -+ // only busy error code need record -+ if (g_lockStatus.lockLen != 0 && lockIdx == g_lockStatus.busyLockIdx) { -+ g_lockStatus.busyLockIdx = 0; -+ g_lockStatus.busyLockType = NO_LOCK; -+ g_lockStatus.lockLen = 0; -+ } -+ if (lockLen == 1) { -+ g_lockStatus.lockStatus[lockIdx] = lockType; -+ } else { -+ size_t len = sizeof(u8) * lockLen; -+ (void)memset(&g_lockStatus.lockStatus[lockIdx], lockType, len); -+ } -+} -+ -+static inline void MarkLockStatusByRc(int rc, u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess) -+{ -+ if (rc == SQLITE_OK) { -+ MarkLockStatus(lockIdx, lockLen, lockType); -+ } else if (rc == SQLITE_BUSY) { -+ MarkLockBusy(lockIdx, lockLen, lockType, lockByProcess); -+ } -+} -+ -+static inline const char *TrxLockName(int eLock) -+{ -+ return eLock == NO_LOCK ? "NO_LOCK" : -+ eLock == RESERVED_LOCK ? "RESERVED" : -+ eLock == EXCLUSIVE_LOCK ? "EXCLUSIVE" : -+ eLock == SHARED_LOCK ? "SHARED" : -+ eLock == PENDING_LOCK ? "PENDING": -+ eLock == UNKNOWN_LOCK ? "UNKNOWN" : "UNKNOWN_LOCK"; -+} -+ -+static inline const char *IdxToLockName(u32 idx) -+{ -+ const char *lockName[MAX_LOCK_NUM] = {"write", "ckpt", "recover", "read0", -+ "read1", "read2", "read3", "read4", "wal_dms", "trxLock"}; -+ return (idx < MAX_LOCK_NUM) ? lockName[idx] : "errLock"; -+} -+ -+static void DumpHandleLock(char *dumpBuf, int dumpBufLen) -+{ -+ char *tmp = dumpBuf; -+ u8 *lockStatus = g_lockStatus.lockStatus; -+ int availLen = dumpBufLen - 1; -+ dumpBuf[availLen] = '\0'; -+ for (int i = 0; i < MAX_LOCK_NUM && availLen > DUMP_MAX_STR_LEN; i++) { -+ if (lockStatus[i] != NO_LOCK) { -+ tmp[0] = '\0'; -+ sqlite3_snprintf(availLen, tmp, "<%s, %s>", IdxToLockName((u32)i), TrxLockName(lockStatus[i])); -+ int len = strlen(tmp); -+ tmp += len; -+ availLen -= len; -+ } -+ } -+ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]BusyLine:%d, idx:%d, type:%d, fileLock:%d, len:%d, handleLocks:%s", -+ g_lockStatus.busyLine, g_lockStatus.busyLockIdx, g_lockStatus.busyLockType, g_lockStatus.lockByProcess, -+ g_lockStatus.lockLen, tmp != dumpBuf ? dumpBuf : "none"); -+} -+ -+static inline const char *FlockToName(int l_type) -+{ -+ return l_type == F_RDLCK ? "F_RDLCK" : -+ l_type == F_WRLCK ? "F_WRLCK" : -+ l_type == F_UNLCK ? "F_UNLCK" : "F_UNKNOWN"; -+} -+ -+static int DumpProcessLocks(int fd, struct flock *lock, const char *lockName, char *dumpBuf, int bufLen) -+{ -+ dumpBuf[0] = '\0'; -+ if (osFcntl(fd, F_GETLK, lock) != SQLITE_OK) { -+ sqlite3_log(SQLITE_ERROR, "[SQLite]Get wal file lock ofs %u failed, errno: %d", lock->l_start, errno); -+ return 0; -+ } -+ if (lock->l_type != F_UNLCK) { -+ sqlite3_snprintf(bufLen, dumpBuf, "<%s, pid:%u, %s>", lockName, lock->l_pid, FlockToName(lock->l_type)); -+ return strlen(dumpBuf); -+ } -+ return 0; -+} -+ -+static void DumpTrxProcessLocks(unixFile *file, char *dumpBuf, int dumpBufLen) -+{ -+ unixInodeInfo *inode = file->pInode; -+ if (inode == NULL) { -+ sqlite3_log(SQLITE_ERROR, "[SQLite]Inode is null!"); -+ return; -+ } -+ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]acqLock:%s, dbRef:%d, lockCnt:%d, curLock:%s, processLock:%d", -+ TrxLockName(file->eFileLock), inode->nRef, inode->nLock, TrxLockName(inode->eFileLock), inode->bProcessLock); -+ const char *lockName[DB_LOCK_NUM] = {"pending", "reserved", "shared_first"}; -+ char *tmp = dumpBuf; -+ int availLen = dumpBufLen - 1; -+ dumpBuf[availLen] = '\0'; -+ for (int i = 0; i < DB_LOCK_NUM && availLen > DUMP_MAX_STR_LEN; i++) { -+ off_t ofs = i + PENDING_BYTE; -+ off_t lockLen = (ofs == SHARED_FIRST) ? SHARED_SIZE : 1; -+ struct flock lock = {.l_type = F_WRLCK, .l_start = ofs, .l_len = lockLen, .l_whence = SEEK_SET}; -+ int lockBufLen = DumpProcessLocks(file->h, &lock, lockName[i], tmp, availLen); -+ tmp += lockBufLen; -+ availLen -= lockBufLen; -+ } -+ if (tmp != dumpBuf) { -+ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]Trx locks: %s", dumpBuf); -+ } -+} -+ -+static void DumpWalLocks(unixFile *file, u8 walEnabled, char *dumpBuf, int dumpBufLen) -+{ -+ if (!walEnabled || file->pShm == NULL || file->pShm->pShmNode == NULL) { -+ sqlite3_log(SQLITE_ERROR, "[SQLite]Wal mode disabled!"); -+ return; -+ } -+ unixShmNode *pShmNode = file->pShm->pShmNode; -+ char *tmp = dumpBuf; -+ int availLen = dumpBufLen - 1; -+ dumpBuf[availLen] = '\0'; -+ for (int i = 0; i < WAL_LOCK_NUM && availLen > DUMP_MAX_STR_LEN; i++) { -+ if (i < SQLITE_SHM_NLOCK && pShmNode->aLock[i]) { -+ tmp[0] = '\0'; -+ sqlite3_snprintf(availLen, tmp, "<%s, %d, tid:%d>", IdxToLockName((u32)i), pShmNode->aLock[i], -+ pShmNode->aLockTid[i]); -+ int strLen = strlen(tmp); -+ tmp += strLen; -+ availLen -= strLen; -+ } -+ off_t ofs = i + WALINDEX_LOCK_OFFSET; -+ struct flock lock = {.l_type = F_WRLCK, .l_start = ofs, .l_len = 1, .l_whence = SEEK_SET}; -+ int bufLen = DumpProcessLocks(pShmNode->hShm, &lock, IdxToLockName((u32)i), tmp, availLen); -+ tmp += bufLen; -+ availLen -= bufLen; -+ } -+ if (tmp != dumpBuf) { -+ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]Wal locks: %s", dumpBuf); -+ } -+} -+ -+static void DumpLocksInfo(unixFile *file, int walEnabled) -+{ -+ char *dumpBuf = sqlite3Malloc(DUMP_BUF_MAX_LEN); -+ if (dumpBuf == NULL) { -+ sqlite3_log(SQLITE_ERROR, "[SQLite]Can't alloc bufferSz %d for dump!", DUMP_BUF_MAX_LEN); -+ return; -+ } -+ DumpHandleLock(dumpBuf, DUMP_BUF_MAX_LEN); -+ DumpTrxProcessLocks(file, dumpBuf, DUMP_BUF_MAX_LEN); -+ DumpWalLocks(file, walEnabled, dumpBuf, DUMP_BUF_MAX_LEN); -+ sqlite3_free(dumpBuf); -+} -+ -+#ifndef SQLITE_OMIT_WAL -+static void DumpLocksByWal(Wal *pWal) -+{ -+ if (pWal == NULL) { -+ sqlite3_log(SQLITE_ERROR, "Wal ptr is NULL!"); -+ return; -+ } -+ if (pWal->pVfs == NULL || sqlite3_stricmp(pWal->pVfs->zName, "unix") != 0) { -+ return; -+ } -+ DumpLocksInfo((unixFile *)(pWal->pDbFd), 1); -+} -+#endif /* #ifndef SQLITE_OMIT_WAL */ -+ -+static void DumpLocksByPager(Pager *pPager) -+{ -+ if (pPager == NULL) { -+ sqlite3_log(SQLITE_ERROR, "Pager ptr is NULL!"); -+ return; -+ } -+ if (pPager->pVfs == NULL || sqlite3_stricmp(pPager->pVfs->zName, "unix") != 0) { -+ return; -+ } -+#ifndef SQLITE_OMIT_WAL -+ DumpLocksInfo((unixFile *)(pPager->fd), pPager->pWal != NULL); -+#else /* #ifndef SQLITE_OMIT_WAL */ -+ DumpLocksInfo((unixFile *)(pPager->fd), 0); -+#endif /* #ifndef SQLITE_OMIT_WAL */ -+} -+#endif /* SQLITE_OS_UNIX */ - -+// hw export the symbols - #ifdef SQLITE_EXPORT_SYMBOLS - /************** Begin hw export the symbols *****************************************/ - #if defined(__GNUC__) --- -2.34.1 - diff --git a/patch/0003-suport-meta-recovery.patch b/patch/0003-suport-meta-recovery.patch deleted file mode 100644 index bbb574d..0000000 --- a/patch/0003-suport-meta-recovery.patch +++ /dev/null @@ -1,1346 +0,0 @@ -From d35904a31c2fe03afdccba31b75a34deb3bbcdbb Mon Sep 17 00:00:00 2001 -From: ryne3366 -Date: Tue, 25 Feb 2025 11:28:45 +0800 -Subject: [PATCH] support meta recovery - -Signed-off-by: ryne3366 ---- - src/sqlite3.c | 1151 ++++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 1140 insertions(+), 11 deletions(-) - -diff --git a/src/sqlite3.c b/src/sqlite3.c -index 1ec1ae9..17d0d25 100644 ---- a/src/sqlite3.c -+++ b/src/sqlite3.c -@@ -788,6 +788,7 @@ SQLITE_API int sqlite3_exec( - #define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ - #define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ - #define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ -+#define SQLITE_META_RECOVERED 66 /* meta page recovered*/ - /* end-of-error-codes */ - - /* -@@ -15626,7 +15627,6 @@ typedef int VList; - # define SQLITE_OS_UNIX 0 - #endif - -- - #endif /* SQLITE_OS_SETUP_H */ - - /************** End of os_setup.h ********************************************/ -@@ -45066,6 +45066,7 @@ static int unixOpen( - flags |= SQLITE_OPEN_READONLY; - openFlags |= O_RDONLY; - isReadonly = 1; -+ sqlite3_log(SQLITE_WARNING, "Try open file readonly"); - pReadonly = findReusableFd(zName, flags); - if( pReadonly ){ - fd = pReadonly->fd; -@@ -58068,6 +58069,26 @@ struct PagerSavepoint { - #endif - }; - -+#if !defined(SQLITE_OS_UNIX) && defined(SQLITE_META_DWR) -+#undef SQLITE_META_DWR -+#endif -+ -+#ifdef SQLITE_META_DWR -+static int PragmaMetaDoubleWrie(sqlite3 *db, int iDb, Parse *parse, const char *zLeft, const char *zRight); -+typedef struct MetaDwrHdr MetaDwrHdr; -+static int MetaDwrWriteHeader(Pager *pPager, MetaDwrHdr *hdr); -+static int MetaDwrUpdateMetaPages(Btree *pBt); -+static void MetaDwrPagerRelease(Pager *pPager); -+static int MetaDwrOpenFile(Pager *pPager, u8 openCreate); -+static void MetaDwrCheckVacuum(BtShared *pBt); -+static int MetaDwrRecoverAndBeginTran(Btree *pBt, int wrflag, int *pSchemaVersion); -+static int MetaDwrOpenAndCheck(Btree *pBt); -+static void MetaDwrDisable(Btree *pBt); -+#define META_HEADER_CHANGED 1 -+#define META_SCHEMA_CHANGED 2 -+#define META_IN_RECOVERY 1 -+#define META_RECOVER_SUCCESS 2 -+#endif - /* - ** Bits of the Pager.doNotSpill flag. See further description below. - */ -@@ -58333,6 +58354,13 @@ struct Pager { - Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */ - char *zWal; /* File name for write-ahead log */ - #endif -+#ifdef SQLITE_META_DWR -+ u8 metaChanged; -+ sqlite3_file *metaFd; -+ MetaDwrHdr *metaHdr; -+ void *metaMapPage; -+ int (*xGetMethod)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */ -+#endif - }; - - /* -@@ -58691,7 +58719,11 @@ static void setGetterMethod(Pager *pPager){ - pPager->xGet = getPageMMap; - #endif /* SQLITE_MAX_MMAP_SIZE>0 */ - }else{ -+#ifdef SQLITE_META_DWR -+ pPager->xGet = pPager->xGetMethod ? pPager->xGetMethod : getPageNormal; -+#else - pPager->xGet = getPageNormal; -+#endif - } - } - -@@ -59765,7 +59797,14 @@ static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){ - } - sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize); - } -- -+#ifdef SQLITE_META_DWR -+ if (bCommit && pPager->metaChanged != 0) { -+ sqlite3BeginBenignMalloc(); -+ (void)MetaDwrWriteHeader(pPager, pPager->metaHdr); -+ sqlite3EndBenignMalloc(); -+ pPager->metaChanged = 0; -+ } -+#endif - if( pagerUseWal(pPager) ){ - /* Drop the WAL write-lock, if any. Also, if the connection was in - ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE -@@ -61860,6 +61899,9 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ - sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,a); - pPager->pWal = 0; - } -+#endif -+#ifdef SQLITE_META_DWR -+ MetaDwrPagerRelease(pPager); - #endif - pager_reset(pPager); - if( MEMDB ){ -@@ -62699,7 +62741,11 @@ act_like_temp_file: - rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb, - !memDb?pagerStress:0, (void *)pPager, pPager->pPCache); - } -- -+#ifdef SQLITE_META_DWR -+ if( rc==SQLITE_OK && !memDb && !readOnly){ -+ (void)MetaDwrOpenFile(pPager, 0); -+ } -+#endif - /* If an error occurred above, free the Pager structure and close the file. - */ - if( rc!=SQLITE_OK ){ -@@ -63123,7 +63169,6 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ - if( pPager->tempFile==0 && pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){ - rc = pagerPagecount(pPager, &pPager->dbSize); - } -- - failed: - if( rc!=SQLITE_OK ){ - assert( !MEMDB ); -@@ -64416,7 +64461,6 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){ - pPager->eState = PAGER_READER; - return SQLITE_OK; - } -- - PAGERTRACE(("COMMIT %d\n", PAGERID(pPager))); - rc = pager_end_transaction(pPager, pPager->setSuper, 1); - return pager_error(pPager, rc); -@@ -70676,6 +70720,10 @@ struct BtShared { - #endif - u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ - int nPreformatSize; /* Size of last cell written by TransferRow() */ -+#ifdef SQLITE_META_DWR -+ u32 maxMetaPage; -+ u32 metaRecoverStatus; -+#endif - }; - - /* -@@ -74077,8 +74125,8 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( - } - } - #endif -- *ppBtree = p; - -+ *ppBtree = p; - btree_open_out: - if( rc!=SQLITE_OK ){ - if( pBt && pBt->pPager ){ -@@ -75048,7 +75096,12 @@ trans_begun: - rc = sqlite3PagerOpenSavepoint(pPager, p->db->nSavepoint); - } - } -- -+#ifdef SQLITE_META_DWR -+ if (rc == SQLITE_NOTADB || rc == SQLITE_CORRUPT) { -+ int rc1 = MetaDwrRecoverAndBeginTran(p, wrflag, pSchemaVersion); -+ rc = (rc1 == SQLITE_OK) ? SQLITE_OK : rc; -+ } -+#endif - btreeIntegrity(p); - sqlite3BtreeLeave(p); - return rc; -@@ -75437,6 +75490,9 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){ - if( rc==SQLITE_OK ){ - rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); - put4byte(&pBt->pPage1->aData[28], pBt->nPage); -+#ifdef SQLITE_META_DWR -+ MetaDwrCheckVacuum(pBt); -+#endif - } - }else{ - rc = SQLITE_DONE; -@@ -75521,6 +75577,9 @@ static int autoVacuumCommit(Btree *p){ - put4byte(&pBt->pPage1->aData[28], nFin); - pBt->bDoTruncate = 1; - pBt->nPage = nFin; -+#ifdef SQLITE_META_DWR -+ MetaDwrCheckVacuum(pBt); -+#endif - } - if( rc!=SQLITE_OK ){ - sqlite3PagerRollback(pPager); -@@ -75577,6 +75636,9 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){ - if( pBt->bDoTruncate ){ - sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage); - } -+#endif -+#ifdef SQLITE_META_DWR -+ (void)MetaDwrUpdateMetaPages(p); - #endif - rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zSuperJrnl, 0); - sqlite3BtreeLeave(p); -@@ -81669,6 +81731,11 @@ SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ - assert( iMeta==0 || iMeta==1 ); - pBt->incrVacuum = (u8)iMeta; - } -+#endif -+#ifdef SQLITE_META_DWR -+ if (idx == 1 && pBt->pPager->metaFd) { -+ pBt->pPager->metaChanged = META_SCHEMA_CHANGED; -+ } - #endif - } - sqlite3BtreeLeave(p); -@@ -82082,7 +82149,6 @@ static int checkTreePage( - if( rc==SQLITE_IOERR_NOMEM ) pCheck->rc = SQLITE_NOMEM; - goto end_of_check; - } -- - /* Clear MemPage.isInit to make sure the corruption detection code in - ** btreeInitPage() is executed. */ - savedIsInit = pPage->isInit; -@@ -83293,6 +83359,12 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ - } - } - } -+ #ifdef SQLITE_META_DWR -+ if (rc == SQLITE_OK && p->pDest->pBt->pPager->metaFd) { -+ p->pDest->pBt->pPager->metaChanged = META_SCHEMA_CHANGED; -+ (void)MetaDwrUpdateMetaPages(p->pDest); -+ } -+ #endif - if( rc==SQLITE_OK ){ - rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1); - } -@@ -83323,6 +83395,12 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ - } - }else{ - sqlite3PagerTruncateImage(pDestPager, nDestTruncate); -+ #ifdef SQLITE_META_DWR -+ if (rc == SQLITE_OK && p->pDest->pBt->pPager->metaFd) { -+ p->pDest->pBt->pPager->metaChanged = META_SCHEMA_CHANGED; -+ (void)MetaDwrUpdateMetaPages(p->pDest); -+ } -+ #endif - rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0); - } - -@@ -140300,8 +140378,14 @@ SQLITE_PRIVATE void sqlite3Pragma( - /* sqlite3CodecPragma executes internal */ - goto pragma_out; - } --#endif /* SQLITE_HAS_CODEC */ -- -+#endif -+/* END CODEC */ -+#ifdef SQLITE_META_DWR -+ if(PragmaMetaDoubleWrie(db, iDb, pParse, zLeft, zRight)) { -+ /* PragmaMetaDoubleWrie executes internal */ -+ goto pragma_out; -+ } -+#endif - /* Locate the pragma in the lookup table */ - pPragma = pragmaLocate(zLeft); - if( pPragma==0 ){ -@@ -155771,7 +155855,6 @@ static void updateVirtualTable( - } - } - -- - if( eOnePass==ONEPASS_OFF ){ - /* End the virtual table scan */ - if( pSrc->nSrc==1 ){ -@@ -182655,6 +182738,10 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){ - zErr = "no more rows available"; - break; - } -+ case SQLITE_META_RECOVERED: { -+ zErr = "warning meta recover message"; -+ break; -+ } - default: { - rc &= 0xff; - if( ALWAYS(rc>=0) && rccheckFileId) { -+ unixFile *fd = (unixFile *)pPager->fd; -+ if (fd == NULL || fd->pInode == NULL || pPager->pVfs == NULL) { -+ return SQLITE_INTERNAL; -+ } -+ if (fd->pInode->fileId.ino != hdr->dbFileInode) { -+ sqlite3_log(SQLITE_IOERR_DATA, "Ino mismatch file %llu dwr file %llu", -+ fd->pInode->fileId.ino, hdr->dbFileInode); -+ return SQLITE_IOERR_DATA; -+ } -+ } -+#endif -+ if (hdr->pageCnt > META_DWR_MAX_PAGES || hdr->version != META_DWR_VERSION || -+ hdr->magic != META_DWR_MAGIC || hdr->checkSum != META_DWR_MAGIC) { -+ sqlite3_log(SQLITE_IOERR_DATA, "Meta dwr file check wrong pageCnt %u, version %u, magic %u, checkSum %u", -+ hdr->pageCnt, hdr->version, hdr->magic, hdr->checkSum); -+ return SQLITE_IOERR_DATA; -+ } -+ if (hdr->pageSz != pPager->pageSize) { -+ sqlite3_log(SQLITE_IOERR_DATA, "Meta dwr file check wrong pageSz %u-%u", hdr->pageSz, pPager->pageSize); -+ return SQLITE_IOERR_DATA; -+ } -+ return SQLITE_OK; -+} -+ -+static int PragmaMetaDoubleWrie(sqlite3 *db, int iDb, Parse *parse, const char *zLeft, const char *zRight) { -+ Btree *pBt = db->aDb[iDb].pBt; -+ if (pBt == NULL || zLeft == NULL || sqlite3StrICmp(zLeft, "meta_double_write") != 0) { -+ return 0; -+ } -+ Pager *pPager = pBt->pBt->pPager; -+ if (pPager == NULL) { -+ sqlite3_log(SQLITE_WARNING_DUMP, "Invalid pager handle"); -+ return 1; -+ } -+ if (zRight == NULL) { -+ Vdbe *v = sqlite3GetVdbe(parse); -+ sqlite3VdbeSetNumCols(v, 1); -+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "meta_double_write", SQLITE_STATIC); -+ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, pPager->metaFd ? "enabled" : "disabled", 0); -+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); -+ } else if (strncmp(zRight, "enabled", 7) == 0) { -+ sqlite3_mutex_enter(db->mutex); -+ // only support enabled meta double write -+ int rc = MetaDwrOpenAndCheck(pBt); -+ if (rc != SQLITE_OK) { -+ parse->nErr++; -+ parse->rc = rc; -+ } -+ sqlite3_mutex_leave(db->mutex); -+ } else if (strncmp(zRight, "disabled", 8) == 0) { -+ sqlite3_mutex_enter(db->mutex); -+ MetaDwrDisable(pBt); -+ sqlite3_mutex_leave(db->mutex); -+ } -+ return 1; -+} -+ -+static int GetBtreePageNo(MemPage *pPage, void *args) { -+ ScanPages *pInfo = (ScanPages *)args; -+ // realloc buffer to store pages -+ u32 pageCnt = pInfo->pageCnt; -+ if (pageCnt == pInfo->pageBufSize) { -+ u32 memSz = sizeof(Pgno) * ROUND8(pageCnt + 1); -+ Pgno *pages = sqlite3Malloc(memSz); -+ if (pages == NULL) { -+ sqlite3_log(SQLITE_NOMEM, "GetPages alloc buffer go wrong %u", memSz); -+ return SQLITE_NOMEM; -+ } -+ if (pageCnt != 0) { -+ memcpy(pages, pInfo->pages, pageCnt * sizeof(Pgno)); -+ } -+ sqlite3_free(pInfo->pages); -+ pInfo->pageBufSize = ROUND8(pageCnt + 1); -+ pInfo->pages = pages; -+ } -+ pInfo->pages[pageCnt] = pPage->pgno; -+ pInfo->pageCnt++; -+ if (pInfo->maxPageNo < pPage->pgno) { -+ pInfo->maxPageNo = pPage->pgno; -+ } -+ return 0; -+} -+ -+typedef int (*ScanFn)(MemPage *pPage, void *args); -+static SQLITE_NOINLINE int ScanOverflowPages( -+ MemPage *pPage, /* The page that contains the Cell */ -+ unsigned char *pCell, /* First byte of the Cell */ -+ CellInfo *pInfo, /* Size information about the cell */ -+ ScanFn fn, /* Scan pages function */ -+ void *args) { -+ BtShared *pBt; -+ Pgno ovflPgno; -+ int rc; -+ int nOvfl; -+ u32 ovflPageSize; -+ -+ if (pCell + pInfo->nSize > pPage->aDataEnd) { -+ /* Cell extends past end of page */ -+ return SQLITE_CORRUPT_BKPT; -+ } -+ ovflPgno = get4byte(pCell + pInfo->nSize - 4); -+ pBt = pPage->pBt; -+ assert(pBt->usableSize > 4); -+ ovflPageSize = pBt->usableSize - 4; -+ nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1) / ovflPageSize; -+ assert(nOvfl > 0 || -+ (CORRUPT_DB && (pInfo->nPayload + ovflPageSize) < ovflPageSize)); -+ while (nOvfl--) { -+ Pgno iNext = 0; -+ MemPage *pOvfl = 0; -+ if (ovflPgno < 2 || ovflPgno > btreePagecount(pBt)) { -+ return SQLITE_CORRUPT_BKPT; -+ } -+ rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext); -+ if (rc) -+ return rc; -+ if (pOvfl) { -+ rc = fn(pOvfl, args); -+ if (rc) { -+ return rc; -+ } -+ sqlite3PagerUnref(pOvfl->pDbPage); -+ } -+ ovflPgno = iNext; -+ } -+ return SQLITE_OK; -+} -+ -+static int ScanBtreePage( -+ BtShared *pBt, /* The BTree that contains the table */ -+ Pgno pgno, /* Page number to clear */ -+ ScanFn fn, /* Scan pages function */ -+ void *args) { /* Scan pages args */ -+ MemPage *pPage; -+ int rc; -+ unsigned char *pCell; -+ int i; -+ int hdr; -+ CellInfo info; -+ -+ assert(sqlite3_mutex_held(pBt->mutex)); -+ if (pgno > btreePagecount(pBt)) { -+ return SQLITE_OK; -+ } -+ rc = getAndInitPage(pBt, pgno, &pPage, 0); -+ if (rc) { -+ return rc; -+ } -+ rc = fn(pPage, args); -+ if (rc) { -+ goto SCAN_PAGE_OUT; -+ } -+ hdr = pPage->hdrOffset; -+ for (i = pPage->nCell - 1; i >= 0; i--) { -+ pCell = findCell(pPage, i); -+ if (!pPage->leaf) { -+ rc = ScanBtreePage(pBt, get4byte(pCell), fn, args); -+ if (rc) { -+ goto SCAN_PAGE_OUT; -+ } -+ } -+ pPage->xParseCell(pPage, pCell, &info); -+ if (info.nLocal != info.nPayload) { -+ rc = ScanOverflowPages(pPage, pCell, &info, fn, args); -+ if (rc) { -+ goto SCAN_PAGE_OUT; -+ } -+ } -+ } -+ if (!pPage->leaf) { -+ rc = ScanBtreePage(pBt, get4byte(&pPage->aData[hdr + 8]), fn, args); -+ if (rc) { -+ goto SCAN_PAGE_OUT; -+ } -+ } -+SCAN_PAGE_OUT: -+ releasePage(pPage); -+ return rc; -+} -+ -+static inline int ScanMetaPages(Btree *pBt, ScanPages *pages) { -+ return ScanBtreePage(pBt->pBt, 1, GetBtreePageNo, pages); -+} -+ -+static int ReleaseMetaPages(ScanPages *pages) { -+ sqlite3_free(pages->pages); -+ pages->pages = NULL; -+ return SQLITE_OK; -+} -+ -+static void InitMetaHeader(MetaDwrHdr *hdr) { -+ (void)memset(hdr, 0, META_VERIFIED_HDR_LEN); -+ hdr->magic = META_DWR_MAGIC; -+ hdr->version = META_DWR_VERSION; -+ hdr->checkSum = META_DWR_MAGIC; -+} -+ -+static void MetaDwrReleaseHdr(MetaDwrHdr *hdr) { -+ if (!hdr) { -+ return; -+ } -+ sqlite3_free(hdr->zones); -+ sqlite3_free(hdr); -+} -+ -+static int ExpandMetaPageBuf(MetaDwrHdr *hdr, u32 minimalPageCnt, u32 bufHasData) { -+ if (minimalPageCnt < hdr->pageBufSize && hdr->zones != NULL) { -+ return SQLITE_OK; -+ } -+ int pageBufSz = ROUND8(MAX(hdr->pageCnt, minimalPageCnt)); -+ u8 *zones = (u8 *)sqlite3Malloc(pageBufSz * (sizeof(u8) + sizeof(Pgno))); -+ if (zones == NULL) { -+ return SQLITE_NOMEM_BKPT; -+ } -+ Pgno *pgnos = (Pgno *)(zones + pageBufSz); -+ if (hdr->zones != NULL) { -+ if (bufHasData && hdr->pageCnt > 0) { -+ (void)memcpy(zones, hdr->zones, hdr->pageCnt * sizeof(u8)); -+ (void)memcpy(pgnos, hdr->pages, hdr->pageCnt * sizeof(Pgno)); -+ } -+ sqlite3_free(hdr->zones); -+ } -+ hdr->pageBufSize = pageBufSz; -+ hdr->zones = zones; -+ hdr->pages = pgnos; -+ return SQLITE_OK; -+} -+ -+static MetaDwrHdr *AllocInitMetaHeaderDwr(Pager *pPager) { -+ MetaDwrHdr *hdr = sqlite3MallocZero(sizeof(MetaDwrHdr)); -+ if (hdr == NULL) { -+ return NULL; -+ } -+ InitMetaHeader(hdr); -+ int rc = ExpandMetaPageBuf(hdr, META_DWR_HEADER_DEFAULT_PAGE_CNT, 0); -+ if (rc != SQLITE_OK) { -+ MetaDwrReleaseHdr(hdr); -+ return NULL; -+ } -+ hdr->checkFileId = (pPager->pVfs != NULL && sqlite3_stricmp(pPager->pVfs->zName, "unix") == 0); -+ return hdr; -+} -+ -+static void MetaDwrCloseFile(Pager *pPager) { -+ if (!pPager->metaFd) { -+ return; -+ } -+#if SQLITE_OS_UNIX -+ if (pPager->metaMapPage) { -+ osMunmap(pPager->metaMapPage, META_DWR_HEADER_PAGE_SIZE); -+ pPager->metaMapPage = NULL; -+ } -+#endif -+ if (pPager->metaHdr && pPager->metaHdr->needSync > 0) { -+ (void)sqlite3OsSync(pPager->metaFd, SQLITE_SYNC_NORMAL); -+ } -+ sqlite3OsClose(pPager->metaFd); -+} -+ -+static void MetaDwrPagerRelease(Pager *pPager) { -+ MetaDwrCloseFile(pPager); -+ MetaDwrReleaseHdr(pPager->metaHdr); -+ pPager->metaHdr = NULL; -+ if (pPager->metaFd) { -+ sqlite3_free(pPager->metaFd); -+ pPager->metaFd = NULL; -+ } -+} -+ -+static inline int ReadFromHdrPage(Pager *pPager, void *data, int amt, i64 offset) { -+ if (pPager->metaMapPage) { -+ (void)memcpy(data, (u8 *)pPager->metaMapPage + offset, amt); -+ return SQLITE_OK; -+ } -+ return sqlite3OsRead(pPager->metaFd, data, amt, offset); -+} -+ -+static int MetaDwrReadHeader(Pager *pPager, MetaDwrHdr *hdr) { -+ i64 sz = 0; -+ int rc = sqlite3OsFileSize(pPager->metaFd, &sz); -+ if (rc != SQLITE_OK) { -+ sqlite3_log(rc, "Meta dwr file size go wrong"); -+ return rc; -+ } -+ if (sz <= META_DWR_HEADER_PAGE_SIZE) { -+ rc = SQLITE_IOERR_DATA; -+ goto READ_META_OUT; -+ } -+ rc = ReadFromHdrPage(pPager, hdr, META_VERIFIED_HDR_LEN, 0); -+ if (rc != SQLITE_OK) { -+ sqlite3_log(rc, "Meta dwr file header read wrong"); -+ goto READ_META_OUT; -+ } -+ rc = MetaDwrHeaderSimpleCheck(pPager, hdr); -+ if (rc != SQLITE_OK) { -+ goto READ_META_OUT; -+ } -+ // avoid realloc buffer if buf can't hold all pages -+ rc = ExpandMetaPageBuf(hdr, hdr->pageCnt, 0); -+ if (rc != SQLITE_OK) { -+ goto READ_META_OUT; -+ } -+ int zoneSize = hdr->pageCnt * sizeof(u8); -+ rc = ReadFromHdrPage(pPager, hdr->zones, zoneSize, META_VERIFIED_HDR_LEN); -+ if (rc != SQLITE_OK) { -+ goto READ_META_OUT; -+ } -+ rc = ReadFromHdrPage(pPager, hdr->pages, hdr->pageCnt * sizeof(Pgno), META_PAGE_NO_OFFSET); -+ if (rc != SQLITE_OK) { -+ goto READ_META_OUT; -+ } -+ for (u32 i = 0; i < hdr->pageCnt; i++) { -+ u8 zoneIdx = hdr->zones[i]; -+ if (zoneIdx != 0 && zoneIdx != 1 && zoneIdx != META_DWR_INVALID_ZONE) { -+ sqlite3_log(SQLITE_IOERR_DATA, "Invalid zoneIdx %d", zoneIdx); -+ rc = SQLITE_IOERR_DATA; -+ break; -+ } -+ } -+READ_META_OUT: -+ if (rc == SQLITE_IOERR_DATA) { -+ InitMetaHeader(hdr); -+ rc = SQLITE_OK; -+ } -+ return rc; -+} -+ -+static inline u64 CaculateMetaDwrWriteOffset(int pageSz, u32 idx, u8 zone) { -+ // 1 header page, idx correspond 2 zone pages -+ return META_DWR_HEADER_PAGE_SIZE + pageSz * (idx * 2 + zone); -+} -+ -+static void MetaDwrUpdateHeaderDbInfo(BtShared *pBt) { -+ MetaDwrHdr *hdr = pBt->pPager->metaHdr; -+ // 28 offset: dbSize, freelist pageNo, freelist pages count, schema cookie -+ const u8 *dbHdrInfo = &pBt->pPage1->aData[28]; -+ hdr->dbSize = sqlite3Get4byte(dbHdrInfo); -+#ifndef SQLITE_OMIT_WAL -+ if (pagerUseWal(pBt->pPager)) { -+ WalIndexHdr *pWalHdr = &pBt->pPager->pWal->hdr; -+ if (pWalHdr->isInit) { -+ hdr->mxFrameInWal = pWalHdr->mxFrame; -+ hdr->dbSize = pWalHdr->nPage; -+ } -+ } else { -+ hdr->mxFrameInWal = 0; -+ } -+#endif -+#if SQLITE_OS_UNIX -+ if (hdr->checkFileId) { -+ unixFile *fd = (unixFile *)pBt->pPager->fd; -+ if (fd == NULL || fd->pInode == NULL) { -+ sqlite3_log(SQLITE_WARNING_DUMP, "update meta header invalid fd"); -+ hdr->hdrValid = 0; -+ return; -+ } -+ hdr->dbFileInode = fd->pInode->fileId.ino; -+ } -+#endif -+ hdr->freeListPageNo = sqlite3Get4byte(dbHdrInfo + 4); -+ hdr->freeListPageCnt = sqlite3Get4byte(dbHdrInfo + 8); -+ hdr->schemaCookie = sqlite3Get4byte(dbHdrInfo + 12); -+ hdr->hdrValid = 1; -+} -+ -+static inline int WriteToHdrPage(Pager *pPager, const void *data, int amt, i64 offset) { -+ if (pPager->metaMapPage) { -+ (void)memcpy((u8 *)pPager->metaMapPage + offset, data, amt); -+ return SQLITE_OK; -+ } -+ return sqlite3OsWrite(pPager->metaFd, data, amt, offset); -+} -+ -+static int MetaDwrWriteHeader(Pager *pPager, MetaDwrHdr *hdr) { -+ if (pPager->metaChanged == 0 || hdr == NULL || hdr->pageCnt == 0 || hdr->hdrValid == 0) { -+ return SQLITE_OK; -+ } -+ hdr->hdrValid = 0; -+ hdr->pageSz = pPager->pageSize; -+ hdr->dbSize = pPager->dbSize; -+ int rc = WriteToHdrPage(pPager, hdr, META_VERIFIED_HDR_LEN, 0); -+ if (rc != SQLITE_OK) { -+ sqlite3_log(rc, "update meta header write hdr %u wrong", META_VERIFIED_HDR_LEN); -+ return rc; -+ } -+ if (hdr->zones) { -+ int zoneSize = hdr->pageCnt * sizeof(u8); -+ rc = WriteToHdrPage(pPager, hdr->zones, zoneSize, META_VERIFIED_HDR_LEN); -+ if (rc != SQLITE_OK) { -+ sqlite3_log(rc, "update meta header write zonebuf %u wrong", zoneSize); -+ return rc; -+ } -+ } -+ if (hdr->pages) { -+ int pageBufSz = hdr->pageCnt * sizeof(Pgno); -+ rc = WriteToHdrPage(pPager, hdr->pages, pageBufSz, META_PAGE_NO_OFFSET); -+ if (rc != SQLITE_OK) { -+ sqlite3_log(rc, "update meta header write pagebuf %u wrong", pageBufSz); -+ } -+ } -+ if (rc == SQLITE_OK) { -+ u64 size = CaculateMetaDwrWriteOffset((int)pPager->pageSize, hdr->pageCnt, 0); -+ rc = sqlite3OsTruncate(pPager->metaFd, size); -+ if (rc != SQLITE_OK) { -+ sqlite3_log(rc, "update meta header truncate filesz %lu wrong", size); -+ } -+ i64 timeMs = 0; -+ sqlite3OsCurrentTimeInt64(pPager->pVfs, &timeMs); -+ if ((timeMs - hdr->lastSyncTime) > META_FILE_SYNC_TIMEOUT_MS || -+ hdr->needSync >= META_FILE_UPDATE_TIMES_PER_SYNC) { -+ rc = sqlite3OsSync(pPager->metaFd, SQLITE_SYNC_NORMAL); -+ if (rc != SQLITE_OK) { -+ sqlite3_log(rc, "update meta header sync filesz %lu wrong", size); -+ } -+ hdr->lastSyncTime = timeMs; -+ hdr->needSync = 0; -+ } else { -+ hdr->needSync++; -+ } -+ } -+ return rc; -+} -+ -+static int MetaDwrFindPageIdx(MetaDwrHdr *hdr, u32 pgno, u32 *idx) { -+ for (u32 i = 0; i < hdr->pageCnt && i < META_DWR_MAX_PAGES; i++) { -+ if (pgno == hdr->pages[i]) { -+ *idx = i; -+ return 1; -+ } -+ } -+ return 0; -+} -+ -+static int MetaDwrWriteOnePage(Btree *pBt, PgHdr *pPage, MetaDwrHdr *hdr, u8 curZones, u32 idx) { -+ int rc = SQLITE_OK; -+ u8 pageExpand = 0; -+ if (hdr->pageCnt <= idx) { -+ rc = ExpandMetaPageBuf(hdr, idx + 1, 1); -+ if (rc != SQLITE_OK) { -+ return rc; -+ } -+ pageExpand = 1; -+ } -+ Pager *pPager = pBt->pBt->pPager; -+ // asume zone 0 or 1 -+ u8 zone = 1 - curZones; -+ int pageSz = sqlite3BtreeGetPageSize(pBt); -+ u64 ofs = CaculateMetaDwrWriteOffset(pageSz, idx, zone); -+ void *pData; -+#if defined(SQLITE_HAS_CODEC) -+ if ((pData = sqlite3PagerCodec(pPage)) == 0) -+ return SQLITE_NOMEM; -+#else -+ pData = pPage->pData; -+#endif -+ rc = sqlite3OsWrite(pPager->metaFd, pData, pageSz, ofs); -+ if (rc != SQLITE_OK) { -+ return rc; -+ } -+ hdr->zones[idx] = zone; -+ hdr->pages[idx] = pPage->pgno; -+ if (pageExpand) { -+ hdr->pageCnt++; -+ } -+ return SQLITE_OK; -+} -+ -+static int MetaDwrRestoreAllPages(Btree *pBt, const ScanPages *metaPages, MetaDwrHdr *hdr) { -+ u32 i = 0; -+ PgHdr *p = NULL; -+ int rc = SQLITE_OK; -+ for (i = 0; i < metaPages->pageCnt && i < META_DWR_MAX_PAGES; i++) { -+ Pgno pgno = metaPages->pages[i]; -+ if (pgno > btreePagecount(pBt->pBt)) { -+ sqlite3_log(SQLITE_WARNING_DUMP, "pageno %d overlimit", pgno); -+ return SQLITE_CORRUPT_BKPT; -+ } -+ rc = sqlite3PagerGet(pBt->pBt->pPager, pgno, &p, 0); -+ if (rc) { -+ return rc; -+ } -+ rc = MetaDwrWriteOnePage(pBt, p, hdr, 1, i); -+ sqlite3PagerUnref(p); -+ if (rc) { -+ return rc; -+ } -+ } -+ MetaDwrUpdateHeaderDbInfo(pBt->pBt); -+ return rc; -+} -+ -+static inline const char *GetMetaFilePath(Pager *pPager) -+{ -+ return pPager->metaFd == NULL ? NULL : ((const char *)pPager->metaFd + ROUND8(pPager->pVfs->szOsFile)); -+} -+ -+static int MetaDwrOpenFile(Pager *pPager, u8 openCreate) { -+ if (pPager->metaFd || pPager->zFilename == NULL) { -+ return SQLITE_OK; -+ } -+ sqlite3BeginBenignMalloc(); -+ sqlite3_vfs *pVfs = pPager->pVfs; -+ int size = strlen(pPager->zFilename) + sizeof("-dwr"); -+ int szOsFile = ROUND8(pVfs->szOsFile); -+ sqlite3_file *metaFd = (sqlite3_file *)sqlite3MallocZero(szOsFile + size); -+ char *metaPath = (char *)metaFd + szOsFile; -+ if (metaFd == NULL) { -+ sqlite3EndBenignMalloc(); -+ sqlite3_log(SQLITE_NOMEM_BKPT, "sqlite alloc memsize %d go wrong", szOsFile + size); -+ return SQLITE_NOMEM_BKPT; -+ } -+ sqlite3_snprintf(size, metaPath, "%s-dwr", pPager->zFilename); -+ int exists = 0; -+ int rc = sqlite3OsAccess(pVfs, metaPath, SQLITE_ACCESS_EXISTS, &exists); -+ if (rc != SQLITE_OK) { -+ goto INIT_META_OUT; -+ } -+ if (!exists && !openCreate) { -+ sqlite3_free(metaFd); -+ goto INIT_META_OUT; -+ } -+ u32 flags = (SQLITE_OPEN_READWRITE | SQLITE_OPEN_SUPER_JOURNAL); -+ if (openCreate) { -+ flags |= SQLITE_OPEN_CREATE; -+ } -+ rc = sqlite3OsOpen(pVfs, metaPath, metaFd, (int)flags, 0); -+ if (rc != SQLITE_OK) { -+ goto INIT_META_OUT; -+ } -+#if SQLITE_OS_UNIX -+ if (pPager->metaMapPage == NULL) { -+ sqlite3_int64 sz = META_DWR_HEADER_PAGE_SIZE; -+ sqlite3OsFileControlHint(metaFd, SQLITE_FCNTL_CHUNK_SIZE, &sz); -+ sqlite3OsFileControlHint(metaFd, SQLITE_FCNTL_SIZE_HINT, &sz); -+ void *page = osMmap(0, META_DWR_HEADER_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, -+ ((unixFile *)metaFd)->h, 0); -+ if (page != MAP_FAILED) { -+ pPager->metaMapPage = page; -+ } -+ } -+#endif -+ pPager->metaFd = metaFd; -+INIT_META_OUT: -+ sqlite3EndBenignMalloc(); -+ if (rc != SQLITE_OK && metaFd != NULL) { -+ sqlite3_free(metaFd); -+ } -+ return rc; -+} -+ -+void MetaDwrCheckVacuum(BtShared *pBt) { -+ if (!pBt || !pBt->pPager->metaFd) { -+ return; -+ } -+ if (pBt->nPage < pBt->maxMetaPage) { -+ pBt->pPager->metaChanged = META_SCHEMA_CHANGED; -+ } -+} -+ -+static inline u8 LocalMetaHdrValid(Pager *pPager) { -+ return pPager->metaMapPage != NULL && memcmp(pPager->metaMapPage, pPager->metaHdr, -+ META_VERIFIED_HDR_LEN) == 0; -+} -+ -+static int MetaDwrLoadHdr(Pager *pPager) { -+ if (!pPager->metaHdr) { -+ pPager->metaHdr = AllocInitMetaHeaderDwr(pPager); -+ if (pPager->metaHdr == NULL) { -+ return SQLITE_NOMEM_BKPT; -+ } -+ } -+ if (LocalMetaHdrValid(pPager)) { -+ return SQLITE_OK; -+ } -+ return MetaDwrReadHeader(pPager, pPager->metaHdr); -+} -+ -+static int MetaDwrLoadAndCheckMetaFile(BtShared *pBt, u8 reportErr) { -+ int rc = MetaDwrLoadHdr(pBt->pPager); -+ if (rc != SQLITE_OK) { -+ return rc; -+ } -+ MetaDwrHdr *hdr = pBt->pPager->metaHdr; -+ if (hdr->pageCnt == 0) { -+ return reportErr ? SQLITE_IOERR_DATA : SQLITE_OK; -+ } -+ // 28 offset: dbSize, freelist pageNo, freelist pages count, schema cookie -+ u8 *dbHdrInfo = &pBt->pPage1->aData[28]; -+ if (hdr->dbSize != pBt->pPager->dbSize || hdr->dbSize != sqlite3Get4byte(dbHdrInfo) || -+ hdr->freeListPageNo != sqlite3Get4byte(dbHdrInfo + 4) || -+ hdr->freeListPageCnt != sqlite3Get4byte(dbHdrInfo + 8) || -+ hdr->schemaCookie != sqlite3Get4byte(dbHdrInfo + 12)) { -+ sqlite3_log(SQLITE_IOERR_DATA, "Meta dwr file expect %u-%u-%u-%u-%u but gotton %u-%u-%u-%u-%u", -+ pBt->pPager->dbSize, hdr->dbSize, sqlite3Get4byte(dbHdrInfo), sqlite3Get4byte(dbHdrInfo + 4), -+ sqlite3Get4byte(dbHdrInfo + 8), sqlite3Get4byte(dbHdrInfo + 12), hdr->dbSize, hdr->freeListPageNo, -+ hdr->freeListPageCnt, hdr->schemaCookie); -+ // reinit -+ InitMetaHeader(hdr); -+ if (reportErr) { -+ return SQLITE_IOERR_DATA; -+ } -+ } -+ return SQLITE_OK; -+} -+ -+static int MetaDwrReadOnePage(Pager *pPager, MetaDwrHdr *hdr, int idx, u8 *pData) { -+ u64 ofs = CaculateMetaDwrWriteOffset(pPager->pageSize, idx, hdr->zones[idx]); -+ int rc = sqlite3OsRead(pPager->metaFd, pData, pPager->pageSize, ofs); -+ CODEC1(pPager, pData, hdr->pages[idx], 3, rc = SQLITE_NOMEM_BKPT); -+ return rc; -+} -+ -+static int MetaDwrRecoverHeadPage( -+ Pager *pPager, /* The pager open on the database file */ -+ Pgno pgno, /* Page number to fetch */ -+ DbPage **pDbPage, -+ int flag) { -+ if (pPager->metaFd == NULL) { -+ return pgno == 1 ? SQLITE_NOTADB : SQLITE_CORRUPT; -+ } -+ sqlite3_pcache_page *pCachePage = sqlite3PcacheFetch(pPager->pPCache, pgno, 3); -+ if (pCachePage == NULL) { -+ sqlite3_log(SQLITE_NOMEM_BKPT, "Get meta page wrong %d", pgno); -+ return SQLITE_NOMEM_BKPT; -+ } -+ DbPage *pPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pCachePage); -+ pPage->pPager = pPager; -+ assert(pCachePage != 0); -+ int rc = MetaDwrLoadHdr(pPager); -+ if (rc != SQLITE_OK) { -+ goto RELEASE_OUT; -+ } -+ MetaDwrHdr *hdr = pPager->metaHdr; -+ u8 walChecked = 0; -+#ifndef SQLITE_OMIT_WAL -+ if (pagerUseWal(pPager)) { -+ WalIndexHdr *pWalHdr = &pPager->pWal->hdr; -+ if (pWalHdr->isInit && pWalHdr->mxFrame != 0) { -+ if (hdr->mxFrameInWal != pWalHdr->mxFrame || hdr->dbSize != pWalHdr->nPage) { -+ rc = SQLITE_NOTADB; -+ sqlite3_log(SQLITE_WARNING_DUMP, "Meta dwr wal hdr expect %u-%u but gotten %u-%u", -+ hdr->mxFrameInWal, hdr->dbSize, pWalHdr->mxFrame, pWalHdr->nPage); -+ goto RELEASE_OUT; -+ } else { -+ walChecked = 1; -+ } -+ } -+ } -+ if (walChecked == 0) { -+ i64 size = 0; -+ rc = sqlite3OsFileSize(pPager->fd, &size); -+ if (rc != SQLITE_OK) { -+ rc = SQLITE_NOTADB; -+ sqlite3_log(SQLITE_WARNING_DUMP, "Meta dwr get db file size go wrong"); -+ goto RELEASE_OUT; -+ } -+ i64 expectSz = (i64)hdr->dbSize * (i64)hdr->pageSz; -+ if (size != expectSz) { -+ rc = SQLITE_NOTADB; -+ sqlite3_log(SQLITE_WARNING_DUMP, "Meta dwr expect file size %lu but gotten size %llu", -+ expectSz, size); -+ goto RELEASE_OUT; -+ } -+ } -+#endif -+ rc = SQLITE_NOTADB; -+ for (u32 i = 0; i < hdr->pageCnt; i++) { -+ if (hdr->pages[i] != pgno) { -+ continue; -+ } -+ rc = MetaDwrReadOnePage(pPager, hdr, i, sqlite3PagerGetData(pPage)); -+ if (rc == SQLITE_OK) { -+ *pDbPage = pPage; -+ if (pPage->pgno == 1) { -+ memcpy(&pPager->dbFileVers, &((u8 *)pPage->pData)[24], sizeof(pPager->dbFileVers)); -+ } -+ pager_set_pagehash(pPage); -+ } -+ break; -+ } -+RELEASE_OUT: -+ if (rc != SQLITE_OK && pPage != NULL) { -+ sqlite3PcacheDrop(pPage); -+ } -+ return rc; -+} -+ -+static int MetaDwrRestoreChangedPages(Btree *pBt) { -+ Pager *pPager = pBt->pBt->pPager; -+ MetaDwrHdr *hdr = pPager->metaHdr; -+ u8 *zones = sqlite3MallocZero(hdr->pageBufSize * sizeof(u8)); -+ if (zones == NULL) { -+ sqlite3_log(SQLITE_NOMEM_BKPT, "Alloc zones buffer size %u go wrong", hdr->pageBufSize * sizeof(u8)); -+ return SQLITE_NOMEM_BKPT; -+ } -+ if (hdr->pageCnt > 0) { -+ memcpy(zones, hdr->zones, hdr->pageCnt * sizeof(u8)); -+ } -+ u32 idx = 0; -+ PgHdr *p = 0; -+ PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache); -+ int rc = SQLITE_OK; -+ for (p = pList; p; p = p->pDirty) { -+ if (MetaDwrFindPageIdx(hdr, p->pgno, &idx) == 0) { -+ continue; -+ } -+ rc = MetaDwrWriteOnePage(pBt, p, hdr, zones[idx], idx); -+ if (rc != SQLITE_OK) { -+ break; -+ } -+ } -+ if (rc == SQLITE_OK) { -+ MetaDwrUpdateHeaderDbInfo(pBt->pBt); -+ } -+ sqlite3_free(zones); -+ return rc; -+} -+ -+static int MetaDwrUpdateMetaPages(Btree *pBt) { -+ Pager *pPager = pBt->pBt->pPager; -+ if (!pPager || !pPager->metaFd || pPager->memDb || pPager->readOnly || pBt->pBt->pPage1 == NULL) { -+ return SQLITE_OK; -+ } -+ if (pPager->metaChanged == 0) { -+ if ((pBt->pBt->pPage1->pDbPage->flags & PGHDR_DIRTY) == 0) { -+ return SQLITE_OK; -+ } -+ pPager->metaChanged = META_HEADER_CHANGED; -+ } -+ sqlite3BeginBenignMalloc(); -+ int rc = MetaDwrLoadHdr(pPager); -+ if (rc != SQLITE_OK) { -+ goto UPDATE_OUT; -+ } -+ // only update header page -+ if (pPager->metaChanged == META_HEADER_CHANGED) { -+ rc = MetaDwrRestoreChangedPages(pBt); -+ goto UPDATE_OUT; -+ } -+ // update schema pages -+ ScanPages metaPages = {0}; -+ rc = ScanMetaPages(pBt, &metaPages); -+ if (rc != SQLITE_OK) { -+ goto UPDATE_OUT; -+ } -+ MetaDwrHdr *hdr = pPager->metaHdr; -+ // rewrite -+ if (hdr->pageCnt == 0 || hdr->pageCnt != metaPages.pageCnt || pBt->pBt->nPage > pBt->pBt->maxMetaPage || -+ memcmp(hdr->pages, metaPages.pages, hdr->pageCnt * sizeof(Pgno))) { -+ // if page numbers unorderred, restore all pages -+ rc = MetaDwrRestoreAllPages(pBt, &metaPages, hdr); -+ } else { -+ rc = MetaDwrRestoreChangedPages(pBt); -+ } -+ if (rc == SQLITE_OK) { -+ pBt->pBt->maxMetaPage = metaPages.maxPageNo; -+ } -+ ReleaseMetaPages(&metaPages); -+UPDATE_OUT: -+ sqlite3EndBenignMalloc(); -+ return rc; -+} -+ -+static int MetaDwrRecoverSinglePage(Btree *pBt, int pgno, u8 *pData) { -+ if (pgno < 1 || pBt == NULL) { -+ return SQLITE_CORRUPT_BKPT; -+ } -+ Pager *pPager = sqlite3BtreePager(pBt); -+ DbPage *pDbPage = NULL; -+ int rc = sqlite3PagerGet(pPager, pgno, &pDbPage, 0); -+ if (rc) { -+ return rc; -+ } -+ if ((rc = sqlite3PagerWrite(pDbPage)) == SQLITE_OK) { -+ memcpy(sqlite3PagerGetData(pDbPage), pData, pPager->pageSize); -+ } else { -+ sqlite3_log(rc, "Dwr recoverwrite meta page %d failed", pgno); -+ } -+ sqlite3PagerUnref(pDbPage); -+ return rc; -+} -+ -+static int MetaDwrCheckMeta(Btree *pBt) { -+ int nErr = 0; -+ Pgno aRoot[2] = {0, 1}; // quick check and only check root btree -+ sqlite3_value aMem[2] = {0}; -+ char *errStr = NULL; -+ int rc = sqlite3BtreeIntegrityCheck(pBt->db, pBt, &aRoot[0], &aMem[0], 2, SQLITE_INTEGRITY_CHECK_ERROR_MAX, -+ &nErr, &errStr); -+ if (nErr == 0) { -+ assert(errStr == 0); -+ return SQLITE_OK; -+ } -+ if (rc != SQLITE_OK) { -+ sqlite3_free(errStr); -+ return rc; -+ } -+ sqlite3_log(SQLITE_WARNING_DUMP, "Integrity check %s", errStr); -+ sqlite3_free(errStr); -+ return SQLITE_CORRUPT; -+} -+ -+static int MetaDwrBeginTrans(Btree *pBt, int wrflag) { -+ pBt->pBt->btsFlags &= ~BTS_READ_ONLY; -+ Pager *pPager = pBt->pBt->pPager; -+ void *xGetMethod = pPager->xGet; -+ pPager->xGetMethod = MetaDwrRecoverHeadPage; -+ pPager->xGet = MetaDwrRecoverHeadPage; -+ int rc = sqlite3BtreeBeginTrans(pBt, wrflag, 0); -+ pPager->xGet = xGetMethod; -+ pPager->xGetMethod = 0; -+ if (rc == SQLITE_OK) { -+ sqlite3PagerWrite(pBt->pBt->pPage1->pDbPage); -+ sqlite3_log(rc, "sqlite fix meta header"); -+ } -+ return rc; -+} -+ -+static int MetaDwrRecoverAndBeginTran(Btree *pBt, int wrflag, int *pSchemaVersion) -+{ -+ Pager *pPager = pBt->pBt->pPager; -+ assert(sqlite3_mutex_held(pBt->pBt->mutex)); -+ if (!pPager->metaFd || pBt->pBt->metaRecoverStatus || pPager->readOnly || pPager->memDb) { -+ return SQLITE_NOTADB; -+ } -+ int rc = MetaDwrLoadHdr(pPager); -+ if (rc != SQLITE_OK) { -+ sqlite3_log(rc, "MetaDwr load header failed"); -+ return rc; -+ } -+ pBt->pBt->metaRecoverStatus = META_IN_RECOVERY; -+ rc = MetaDwrBeginTrans(pBt, 2); -+ if (rc != SQLITE_OK) { -+ return rc; -+ } -+ void *pData = NULL; -+ pPager->metaChanged = META_HEADER_CHANGED; -+ MetaDwrHdr *hdr = pPager->metaHdr; -+ sqlite3_log(SQLITE_WARNING_DUMP, "sqlite meta recover %u frames", hdr->pageCnt); -+ int szPage = sqlite3BtreeGetPageSize(pBt); -+ pData = sqlite3Malloc(szPage); -+ if (pData == NULL) { -+ rc = SQLITE_NOMEM; -+ sqlite3_log(rc, "Dwr malloc mem size %d failed", szPage); -+ goto DWR_RECOVER_OUT; -+ } -+ for (u32 i = 0; i < hdr->pageCnt; i++) { -+ rc = MetaDwrReadOnePage(pPager, hdr, i, pData); -+ if (rc != SQLITE_OK) { -+ sqlite3_log(rc, "Dwr read %d meta page failed ", i); -+ break; -+ } -+ rc = MetaDwrRecoverSinglePage(pBt, hdr->pages[i], pData); -+ if (rc != SQLITE_OK) { -+ sqlite3_log(rc, "Dwr recover %d meta page failed ", i); -+ break; -+ } -+ } -+DWR_RECOVER_OUT: -+ /* Close the transaction, if one was opened. */ -+ if (rc == SQLITE_OK) { -+ sqlite3BtreeCommit(pBt); -+ } else { -+ (void)sqlite3BtreeRollback(pBt, SQLITE_ABORT_ROLLBACK, 0); -+ } -+ if (rc == SQLITE_OK) { -+ rc = sqlite3BtreeBeginTrans(pBt, wrflag, pSchemaVersion); -+ } -+ if (rc == SQLITE_OK) { -+ pBt->pBt->metaRecoverStatus = META_RECOVER_SUCCESS; -+ } -+ if (pData) { -+ sqlite3_free(pData); -+ } -+ return rc; -+} -+ -+static int Sqlite3MetaDwrCheckRestore(Btree *pBt) { -+ Pager *pPager = pBt->pBt->pPager; -+ int rc = MetaDwrOpenFile(pPager, 1); -+ if (rc != SQLITE_OK) { -+ return rc; -+ } -+ ScanPages metaPages = {0}; -+ rc = ScanMetaPages(pBt, &metaPages); -+ if (rc != SQLITE_OK || metaPages.pageCnt == 0) { -+ goto CHK_RESTORE_OUT; -+ } -+ rc = MetaDwrLoadAndCheckMetaFile(pBt->pBt, 0); -+ if (rc != SQLITE_OK) { -+ goto CHK_RESTORE_OUT; -+ } -+ MetaDwrHdr *hdr = pPager->metaHdr; -+ if (hdr->pageCnt == 0 || hdr->pageCnt != metaPages.pageCnt || -+ memcmp(hdr->pages, metaPages.pages, hdr->pageCnt * sizeof(Pgno))) { -+ sqlite3_log(SQLITE_WARNING_DUMP, "sqlite meta restore all"); -+ rc = MetaDwrRestoreAllPages(pBt, &metaPages, hdr); -+ if (rc == SQLITE_OK) { -+ pPager->metaChanged = META_SCHEMA_CHANGED; -+ rc = MetaDwrWriteHeader(pPager, hdr); -+ pPager->metaChanged = 0; -+ } -+ } -+ if (rc == SQLITE_OK) { -+ pBt->pBt->maxMetaPage = metaPages.maxPageNo; -+ } -+CHK_RESTORE_OUT: -+ ReleaseMetaPages(&metaPages); -+ return rc; -+} -+ -+static inline u8 IsConnectionValidForCheck(Pager *pPager) -+{ -+#if SQLITE_OS_UNIX -+ unixFile *fd = (unixFile *)pPager->fd; -+ // unix and only one connection exist -+ if (fd == NULL || fd->pInode == NULL || pPager->pVfs == NULL || -+ sqlite3_stricmp(pPager->pVfs->zName, "unix") != 0 || fd->pInode->nRef != 1) { -+ return 0; -+ } -+ return 1; -+#else -+ return 0; -+#endif -+} -+ -+static int MetaDwrOpenAndCheck(Btree *pBt) -+{ -+ Pager *pPager = pBt->pBt->pPager; -+ if (pPager->memDb || pPager->readOnly || !IsConnectionValidForCheck(pPager)) { -+ return SQLITE_OK; -+ } -+#ifdef SQLITE_HAS_CODEC -+ // not support codec right now -+ if (pPager->xCodec) { -+ return SQLITE_OK; -+ } -+#endif -+ sqlite3BtreeEnter(pBt); -+ int rc = SQLITE_OK; -+ int openedTransaction = 0; -+ int tnxState = sqlite3BtreeTxnState(pBt); -+ if (tnxState == SQLITE_TXN_NONE) { -+ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); -+ if (rc != SQLITE_OK) { -+ goto DWR_OPEN_OUT; -+ } -+ openedTransaction = 1; -+ } -+ rc = MetaDwrCheckMeta(pBt); -+ if (rc == SQLITE_CORRUPT || rc == SQLITE_NOTADB) { -+ // keep txn status after recover -+ rc = MetaDwrRecoverAndBeginTran(pBt, tnxState == SQLITE_TXN_WRITE ? 1 : 0, 0); -+ goto DWR_OPEN_OUT; -+ } -+ rc = Sqlite3MetaDwrCheckRestore(pBt); -+DWR_OPEN_OUT: -+ if (rc == SQLITE_OK && pBt->pBt->metaRecoverStatus == META_RECOVER_SUCCESS) { -+ rc = MetaDwrCheckMeta(pBt); -+ if (rc == SQLITE_OK) { -+ rc = SQLITE_META_RECOVERED; -+ } -+ } -+ /* Close the transaction, if one was opened. */ -+ if (openedTransaction) { -+ sqlite3BtreeCommit(pBt); -+ } -+ sqlite3BtreeLeave(pBt); -+ return rc; -+} - -+static void MetaDwrDisable(Btree *pBt) -+{ -+ Pager *pPager = pBt->pBt->pPager; -+ if (pPager->metaFd == NULL || pPager->memDb || pPager->readOnly || !IsConnectionValidForCheck(pPager)) { -+ return; -+ } -+#ifdef SQLITE_HAS_CODEC -+ // not support codec right now -+ if (pPager->xCodec) { -+ return; -+ } -+#endif -+ sqlite3BtreeEnter(pBt); -+ MetaDwrCloseFile(pPager); -+ MetaDwrReleaseHdr(pPager->metaHdr); -+ pPager->metaHdr = NULL; -+ const char *metaPath = GetMetaFilePath(pPager); -+ if (metaPath != NULL) { -+ (void)osUnlink(metaPath); -+ } -+ if (pPager->metaFd) { -+ sqlite3_free(pPager->metaFd); -+ pPager->metaFd = NULL; -+ } -+ sqlite3BtreeLeave(pBt); -+} -+#endif - #if SQLITE_OS_UNIX - #include - #include --- -2.34.1 - diff --git a/patch/0004-Enable-and-optimize-ICU.patch b/patch/0004-Enable-and-optimize-ICU.patch deleted file mode 100644 index fbfdd4b..0000000 --- a/patch/0004-Enable-and-optimize-ICU.patch +++ /dev/null @@ -1,2119 +0,0 @@ -From 5526b966d88575fd479dfe69af0c70c4ac43de14 Mon Sep 17 00:00:00 2001 -From: MartinChoo <214582617@qq.com> -Date: Tue, 25 Feb 2025 17:02:54 +0800 -Subject: [PATCH] Enable and optimize ICU - -Signed-off-by: MartinChoo <214582617@qq.com> ---- - src/sqlite3.c | 1065 ++++------------------------------------------ - src/sqlite3icu.c | 925 ++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 1009 insertions(+), 981 deletions(-) - create mode 100644 src/sqlite3icu.c - -diff --git a/src/sqlite3.c b/src/sqlite3.c -index 17d0d25..f348f3c 100644 ---- a/src/sqlite3.c -+++ b/src/sqlite3.c -@@ -2506,6 +2506,7 @@ struct sqlite3_mem_methods { - #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ - #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ - #define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */ -+#define SQLITE_CONFIG_ENABLE_ICU 31 /* boolean */ - - /* - ** CAPI3REF: Database Connection Configuration Options -@@ -3283,6 +3284,17 @@ SQLITE_API int sqlite3_get_table( - ); - SQLITE_API void sqlite3_free_table(char **result); - -+// hw export the symbols -+#ifdef SQLITE_EXPORT_SYMBOLS -+#if defined(__GNUC__) -+# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) -+#elif defined(_MSC_VER) -+# define EXPORT_SYMBOLS __declspec(dllexport) -+#else -+# define EXPORT_SYMBOLS -+#endif -+#endif // SQLITE_EXPORT_SYMBOLS -+ - /* - ** CAPI3REF: Formatted String Printing Functions - ** -@@ -181005,6 +181017,7 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db); - /************** End of rtree.h ***********************************************/ - /************** Continuing where we left off in main.c ***********************/ - #endif -+#include "sqlite3tokenizer.h" - #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) - /************** Include sqliteicu.h in the middle of main.c ******************/ - /************** Begin file sqliteicu.h ***************************************/ -@@ -181029,13 +181042,54 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db); - extern "C" { - #endif /* __cplusplus */ - --SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db); -+SQLITE_PRIVATE int sqlite3IcuInitInner(sqlite3 *db); - - #if 0 - } /* extern "C" */ - #endif /* __cplusplus */ - - /************** End of sqliteicu.h *******************************************/ -+#ifndef _WIN32 -+#include -+#endif -+ -+typedef void (*sqlite3Fts3IcuTokenizerModule_ptr)(sqlite3_tokenizer_module const** ppModule); -+typedef int (*sqlite3IcuInit_ptr)(sqlite3 *db); -+static sqlite3Fts3IcuTokenizerModule_ptr tokenModulePtr = NULL; -+static sqlite3IcuInit_ptr icuInitPtr = NULL; -+static u32 icuEnable = 0u; -+static u32 icuInit = 0u; -+static void *g_library = NULL; -+ -+int sqlite3IcuModuleInit(){ -+ int rc = SQLITE_OK; -+ if( icuInit ){ -+ return rc; -+ } -+#ifndef _WIN32 -+ g_library = dlopen("libsqliteicu.z.so", RTLD_LAZY); -+ if( g_library==NULL ){ -+ sqlite3_log(SQLITE_ERROR, "load icu so failed"); -+ return SQLITE_ERROR; -+ } -+ tokenModulePtr = (sqlite3Fts3IcuTokenizerModule_ptr)dlsym(g_library, "sqlite3Fts3IcuTokenizerModule"); -+ icuInitPtr = (sqlite3IcuInit_ptr)dlsym(g_library, "sqlite3IcuInit"); -+ if( tokenModulePtr==NULL || icuInitPtr==NULL ){ -+ sqlite3_log(SQLITE_ERROR, "load icu init function failed"); -+ return SQLITE_ERROR; -+ } -+ icuInit = 1u; -+#endif -+ return rc; -+} -+ -+SQLITE_PRIVATE int sqlite3IcuInitInner(sqlite3 *db) -+{ -+ if( !icuEnable ){ -+ return SQLITE_OK; -+ } -+ return icuInitPtr(db); -+} - /************** Continuing where we left off in main.c ***********************/ - #endif - -@@ -181075,7 +181129,7 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = { - sqlite3Fts5Init, - #endif - #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) -- sqlite3IcuInit, -+ sqlite3IcuInitInner, - #endif - #ifdef SQLITE_ENABLE_RTREE - sqlite3RtreeInit, -@@ -181467,6 +181521,19 @@ SQLITE_API int sqlite3_shutdown(void){ - SQLITE_API int sqlite3_config(int op, ...){ - va_list ap; - int rc = SQLITE_OK; -+ va_start(ap, op); -+ -+#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) -+ if( op==SQLITE_CONFIG_ENABLE_ICU ){ -+ int iVal = va_arg(ap, int); -+ if( iVal==0 ){ -+ icuEnable = 0u; -+ }else{ -+ icuEnable = 1u; -+ } -+ return rc; -+ } -+#endif /* SQLITE_ENABLE_ICU */ - - /* sqlite3_config() normally returns SQLITE_MISUSE if it is invoked while - ** the SQLite library is in use. Except, a few selected opcodes -@@ -181484,7 +181551,6 @@ SQLITE_API int sqlite3_config(int op, ...){ - testcase( op==SQLITE_CONFIG_PCACHE_HDRSZ ); - } - -- va_start(ap, op); - switch( op ){ - - /* Mutex configuration options are only available in a threadsafe -@@ -184609,6 +184675,12 @@ static int openDatabase( - sqlite3RegisterPerConnectionBuiltinFunctions(db); - rc = sqlite3_errcode(db); - -+#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) -+ if( icuEnable ){ -+ rc = sqlite3IcuModuleInit(); -+ if( rc!=SQLITE_OK ) return rc; -+ } -+#endif - - /* Load compiled-in extensions */ - for(i=0; rc==SQLITE_OK && i arg1 arg2) -- ** -- ** then argc is set to 2, and the argv[] array contains pointers -- ** to the strings "arg1" and "arg2". -- ** -- ** This method should return either SQLITE_OK (0), or an SQLite error -- ** code. If SQLITE_OK is returned, then *ppTokenizer should be set -- ** to point at the newly created tokenizer structure. The generic -- ** sqlite3_tokenizer.pModule variable should not be initialized by -- ** this callback. The caller will do so. -- */ -- int (*xCreate)( -- int argc, /* Size of argv array */ -- const char *const*argv, /* Tokenizer argument strings */ -- sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ -- ); -- -- /* -- ** Destroy an existing tokenizer. The fts3 module calls this method -- ** exactly once for each successful call to xCreate(). -- */ -- int (*xDestroy)(sqlite3_tokenizer *pTokenizer); -- -- /* -- ** Create a tokenizer cursor to tokenize an input buffer. The caller -- ** is responsible for ensuring that the input buffer remains valid -- ** until the cursor is closed (using the xClose() method). -- */ -- int (*xOpen)( -- sqlite3_tokenizer *pTokenizer, /* Tokenizer object */ -- const char *pInput, int nBytes, /* Input buffer */ -- sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */ -- ); -- -- /* -- ** Destroy an existing tokenizer cursor. The fts3 module calls this -- ** method exactly once for each successful call to xOpen(). -- */ -- int (*xClose)(sqlite3_tokenizer_cursor *pCursor); -- -- /* -- ** Retrieve the next token from the tokenizer cursor pCursor. This -- ** method should either return SQLITE_OK and set the values of the -- ** "OUT" variables identified below, or SQLITE_DONE to indicate that -- ** the end of the buffer has been reached, or an SQLite error code. -- ** -- ** *ppToken should be set to point at a buffer containing the -- ** normalized version of the token (i.e. after any case-folding and/or -- ** stemming has been performed). *pnBytes should be set to the length -- ** of this buffer in bytes. The input text that generated the token is -- ** identified by the byte offsets returned in *piStartOffset and -- ** *piEndOffset. *piStartOffset should be set to the index of the first -- ** byte of the token in the input buffer. *piEndOffset should be set -- ** to the index of the first byte just past the end of the token in -- ** the input buffer. -- ** -- ** The buffer *ppToken is set to point at is managed by the tokenizer -- ** implementation. It is only required to be valid until the next call -- ** to xNext() or xClose(). -- */ -- /* TODO(shess) current implementation requires pInput to be -- ** nul-terminated. This should either be fixed, or pInput/nBytes -- ** should be converted to zInput. -- */ -- int (*xNext)( -- sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */ -- const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */ -- int *piStartOffset, /* OUT: Byte offset of token in input buffer */ -- int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */ -- int *piPosition /* OUT: Number of tokens returned before this one */ -- ); -- -- /*********************************************************************** -- ** Methods below this point are only available if iVersion>=1. -- */ -- -- /* -- ** Configure the language id of a tokenizer cursor. -- */ -- int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid); --}; -- --struct sqlite3_tokenizer { -- const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */ -- /* Tokenizer implementations will typically add additional fields */ --}; -- --struct sqlite3_tokenizer_cursor { -- sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */ -- /* Tokenizer implementations will typically add additional fields */ --}; - - int fts3_global_term_cnt(int iTerm, int iCol); - int fts3_term_cnt(int iTerm, int iCol); -@@ -191576,9 +191540,6 @@ SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(sqlite3_tokenizer_module co - #ifndef SQLITE_DISABLE_FTS3_UNICODE - SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const**ppModule); - #endif --#ifdef SQLITE_ENABLE_ICU --SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); --#endif - - /* - ** Initialize the fts3 extension. If this extension is built as part -@@ -191597,7 +191558,14 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){ - - #ifdef SQLITE_ENABLE_ICU - const sqlite3_tokenizer_module *pIcu = 0; -- sqlite3Fts3IcuTokenizerModule(&pIcu); -+ if( icuEnable ){ -+ if( tokenModulePtr!=NULL ){ -+ tokenModulePtr(&pIcu); -+ }else{ -+ sqlite3_log(SQLITE_ERROR, "icu module ptr is null"); -+ return SQLITE_ERROR; -+ } -+ } - #endif - - #ifndef SQLITE_DISABLE_FTS3_UNICODE -@@ -191633,7 +191601,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){ - || sqlite3Fts3HashInsert(&pHash->hash, "unicode61", 10, (void *)pUnicode) - #endif - #ifdef SQLITE_ENABLE_ICU -- || (pIcu && sqlite3Fts3HashInsert(&pHash->hash, "icu", 4, (void *)pIcu)) -+ || (icuEnable && pIcu && sqlite3Fts3HashInsert(&pHash->hash, "icu", 4, (void *)pIcu)) - #endif - ){ - rc = SQLITE_NOMEM; -@@ -217955,862 +217923,6 @@ SQLITE_API int sqlite3_rtree_init( - #endif - - /************** End of rtree.c ***********************************************/ --/************** Begin file icu.c *********************************************/ --/* --** 2007 May 6 --** --** The author disclaims copyright to this source code. In place of --** a legal notice, here is a blessing: --** --** May you do good and not evil. --** May you find forgiveness for yourself and forgive others. --** May you share freely, never taking more than you give. --** --************************************************************************* --** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $ --** --** This file implements an integration between the ICU library --** ("International Components for Unicode", an open-source library --** for handling unicode data) and SQLite. The integration uses --** ICU to provide the following to SQLite: --** --** * An implementation of the SQL regexp() function (and hence REGEXP --** operator) using the ICU uregex_XX() APIs. --** --** * Implementations of the SQL scalar upper() and lower() functions --** for case mapping. --** --** * Integration of ICU and SQLite collation sequences. --** --** * An implementation of the LIKE operator that uses ICU to --** provide case-independent matching. --*/ -- --#if !defined(SQLITE_CORE) \ -- || defined(SQLITE_ENABLE_ICU) \ -- || defined(SQLITE_ENABLE_ICU_COLLATIONS) -- --/* Include ICU headers */ --#include --#include --#include --#include -- --/* #include */ -- --#ifndef SQLITE_CORE --/* #include "sqlite3ext.h" */ -- SQLITE_EXTENSION_INIT1 --#else --/* #include "sqlite3.h" */ --#endif -- --/* --** This function is called when an ICU function called from within --** the implementation of an SQL scalar function returns an error. --** --** The scalar function context passed as the first argument is --** loaded with an error message based on the following two args. --*/ --static void icuFunctionError( -- sqlite3_context *pCtx, /* SQLite scalar function context */ -- const char *zName, /* Name of ICU function that failed */ -- UErrorCode e /* Error code returned by ICU function */ --){ -- char zBuf[128]; -- sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e)); -- zBuf[127] = '\0'; -- sqlite3_result_error(pCtx, zBuf, -1); --} -- --#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) -- --/* --** Maximum length (in bytes) of the pattern in a LIKE or GLOB --** operator. --*/ --#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH --# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000 --#endif -- --/* --** Version of sqlite3_free() that is always a function, never a macro. --*/ --static void xFree(void *p){ -- sqlite3_free(p); --} -- --/* --** This lookup table is used to help decode the first byte of --** a multi-byte UTF8 character. It is copied here from SQLite source --** code file utf8.c. --*/ --static const unsigned char icuUtf8Trans1[] = { -- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, -- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, -- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, -- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, -- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -- 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, --}; -- --#define SQLITE_ICU_READ_UTF8(zIn, c) \ -- c = *(zIn++); \ -- if( c>=0xc0 ){ \ -- c = icuUtf8Trans1[c-0xc0]; \ -- while( (*zIn & 0xc0)==0x80 ){ \ -- c = (c<<6) + (0x3f & *(zIn++)); \ -- } \ -- } -- --#define SQLITE_ICU_SKIP_UTF8(zIn) \ -- assert( *zIn ); \ -- if( *(zIn++)>=0xc0 ){ \ -- while( (*zIn & 0xc0)==0x80 ){zIn++;} \ -- } -- -- --/* --** Compare two UTF-8 strings for equality where the first string is --** a "LIKE" expression. Return true (1) if they are the same and --** false (0) if they are different. --*/ --static int icuLikeCompare( -- const uint8_t *zPattern, /* LIKE pattern */ -- const uint8_t *zString, /* The UTF-8 string to compare against */ -- const UChar32 uEsc /* The escape character */ --){ -- static const uint32_t MATCH_ONE = (uint32_t)'_'; -- static const uint32_t MATCH_ALL = (uint32_t)'%'; -- -- int prevEscape = 0; /* True if the previous character was uEsc */ -- -- while( 1 ){ -- -- /* Read (and consume) the next character from the input pattern. */ -- uint32_t uPattern; -- SQLITE_ICU_READ_UTF8(zPattern, uPattern); -- if( uPattern==0 ) break; -- -- /* There are now 4 possibilities: -- ** -- ** 1. uPattern is an unescaped match-all character "%", -- ** 2. uPattern is an unescaped match-one character "_", -- ** 3. uPattern is an unescaped escape character, or -- ** 4. uPattern is to be handled as an ordinary character -- */ -- if( uPattern==MATCH_ALL && !prevEscape && uPattern!=(uint32_t)uEsc ){ -- /* Case 1. */ -- uint8_t c; -- -- /* Skip any MATCH_ALL or MATCH_ONE characters that follow a -- ** MATCH_ALL. For each MATCH_ONE, skip one character in the -- ** test string. -- */ -- while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){ -- if( c==MATCH_ONE ){ -- if( *zString==0 ) return 0; -- SQLITE_ICU_SKIP_UTF8(zString); -- } -- zPattern++; -- } -- -- if( *zPattern==0 ) return 1; -- -- while( *zString ){ -- if( icuLikeCompare(zPattern, zString, uEsc) ){ -- return 1; -- } -- SQLITE_ICU_SKIP_UTF8(zString); -- } -- return 0; -- -- }else if( uPattern==MATCH_ONE && !prevEscape && uPattern!=(uint32_t)uEsc ){ -- /* Case 2. */ -- if( *zString==0 ) return 0; -- SQLITE_ICU_SKIP_UTF8(zString); -- -- }else if( uPattern==(uint32_t)uEsc && !prevEscape ){ -- /* Case 3. */ -- prevEscape = 1; -- -- }else{ -- /* Case 4. */ -- uint32_t uString; -- SQLITE_ICU_READ_UTF8(zString, uString); -- uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT); -- uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT); -- if( uString!=uPattern ){ -- return 0; -- } -- prevEscape = 0; -- } -- } -- -- return *zString==0; --} -- --/* --** Implementation of the like() SQL function. This function implements --** the build-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 --** --** is implemented as like(B, A). If there is an escape character E, --** --** A LIKE B ESCAPE E --** --** is mapped to like(B, A, E). --*/ --static void icuLikeFunc( -- sqlite3_context *context, -- int argc, -- sqlite3_value **argv --){ -- const unsigned char *zA = sqlite3_value_text(argv[0]); -- const unsigned char *zB = sqlite3_value_text(argv[1]); -- UChar32 uEsc = 0; -- -- /* Limit the length of the LIKE or GLOB pattern to avoid problems -- ** of deep recursion and N*N behavior in patternCompare(). -- */ -- if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){ -- sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); -- return; -- } -- -- -- if( argc==3 ){ -- /* The escape character string must consist of a single UTF-8 character. -- ** Otherwise, return an error. -- */ -- int nE= sqlite3_value_bytes(argv[2]); -- const unsigned char *zE = sqlite3_value_text(argv[2]); -- int i = 0; -- if( zE==0 ) return; -- U8_NEXT(zE, i, nE, uEsc); -- if( i!=nE){ -- sqlite3_result_error(context, -- "ESCAPE expression must be a single character", -1); -- return; -- } -- } -- -- if( zA && zB ){ -- sqlite3_result_int(context, icuLikeCompare(zA, zB, uEsc)); -- } --} -- --/* --** Function to delete compiled regexp objects. Registered as --** a destructor function with sqlite3_set_auxdata(). --*/ --static void icuRegexpDelete(void *p){ -- URegularExpression *pExpr = (URegularExpression *)p; -- uregex_close(pExpr); --} -- --/* --** Implementation of SQLite REGEXP operator. This scalar function takes --** two arguments. The first is a regular expression pattern to compile --** the second is a string to match against that pattern. If either --** argument is an SQL NULL, then NULL Is returned. Otherwise, the result --** is 1 if the string matches the pattern, or 0 otherwise. --** --** SQLite maps the regexp() function to the regexp() operator such --** that the following two are equivalent: --** --** zString REGEXP zPattern --** regexp(zPattern, zString) --** --** Uses the following ICU regexp APIs: --** --** uregex_open() --** uregex_matches() --** uregex_close() --*/ --static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ -- UErrorCode status = U_ZERO_ERROR; -- URegularExpression *pExpr; -- UBool res; -- const UChar *zString = sqlite3_value_text16(apArg[1]); -- -- (void)nArg; /* Unused parameter */ -- -- /* If the left hand side of the regexp operator is NULL, -- ** then the result is also NULL. -- */ -- if( !zString ){ -- return; -- } -- -- pExpr = sqlite3_get_auxdata(p, 0); -- if( !pExpr ){ -- const UChar *zPattern = sqlite3_value_text16(apArg[0]); -- if( !zPattern ){ -- return; -- } -- pExpr = uregex_open(zPattern, -1, 0, 0, &status); -- -- if( U_SUCCESS(status) ){ -- sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete); -- pExpr = sqlite3_get_auxdata(p, 0); -- } -- if( !pExpr ){ -- icuFunctionError(p, "uregex_open", status); -- return; -- } -- } -- -- /* Configure the text that the regular expression operates on. */ -- uregex_setText(pExpr, zString, -1, &status); -- if( !U_SUCCESS(status) ){ -- icuFunctionError(p, "uregex_setText", status); -- return; -- } -- -- /* Attempt the match */ -- res = uregex_matches(pExpr, 0, &status); -- if( !U_SUCCESS(status) ){ -- icuFunctionError(p, "uregex_matches", status); -- return; -- } -- -- /* Set the text that the regular expression operates on to a NULL -- ** pointer. This is not really necessary, but it is tidier than -- ** leaving the regular expression object configured with an invalid -- ** pointer after this function returns. -- */ -- uregex_setText(pExpr, 0, 0, &status); -- -- /* Return 1 or 0. */ -- sqlite3_result_int(p, res ? 1 : 0); --} -- --/* --** Implementations of scalar functions for case mapping - upper() and --** lower(). Function upper() converts its input to upper-case (ABC). --** Function lower() converts to lower-case (abc). --** --** ICU provides two types of case mapping, "general" case mapping and --** "language specific". Refer to ICU documentation for the differences --** between the two. --** --** To utilise "general" case mapping, the upper() or lower() scalar --** functions are invoked with one argument: --** --** upper('ABC') -> 'abc' --** lower('abc') -> 'ABC' --** --** To access ICU "language specific" case mapping, upper() or lower() --** should be invoked with two arguments. The second argument is the name --** of the locale to use. Passing an empty string ("") or SQL NULL value --** as the second argument is the same as invoking the 1 argument version --** of upper() or lower(). --** --** lower('I', 'en_us') -> 'i' --** lower('I', 'tr_tr') -> '\u131' (small dotless i) --** --** http://www.icu-project.org/userguide/posix.html#case_mappings --*/ --static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ -- const UChar *zInput; /* Pointer to input string */ -- UChar *zOutput = 0; /* Pointer to output buffer */ -- int nInput; /* Size of utf-16 input string in bytes */ -- int nOut; /* Size of output buffer in bytes */ -- int cnt; -- int bToUpper; /* True for toupper(), false for tolower() */ -- UErrorCode status; -- const char *zLocale = 0; -- -- assert(nArg==1 || nArg==2); -- bToUpper = (sqlite3_user_data(p)!=0); -- if( nArg==2 ){ -- zLocale = (const char *)sqlite3_value_text(apArg[1]); -- } -- -- zInput = sqlite3_value_text16(apArg[0]); -- if( !zInput ){ -- return; -- } -- nOut = nInput = sqlite3_value_bytes16(apArg[0]); -- if( nOut==0 ){ -- sqlite3_result_text16(p, "", 0, SQLITE_STATIC); -- return; -- } -- -- for(cnt=0; cnt<2; cnt++){ -- UChar *zNew = sqlite3_realloc(zOutput, nOut); -- if( zNew==0 ){ -- sqlite3_free(zOutput); -- sqlite3_result_error_nomem(p); -- return; -- } -- zOutput = zNew; -- status = U_ZERO_ERROR; -- if( bToUpper ){ -- nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); -- }else{ -- nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); -- } -- -- if( U_SUCCESS(status) ){ -- sqlite3_result_text16(p, zOutput, nOut, xFree); -- }else if( status==U_BUFFER_OVERFLOW_ERROR ){ -- assert( cnt==0 ); -- continue; -- }else{ -- icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status); -- } -- return; -- } -- assert( 0 ); /* Unreachable */ --} -- --#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ -- --/* --** Collation sequence destructor function. The pCtx argument points to --** a UCollator structure previously allocated using ucol_open(). --*/ --static void icuCollationDel(void *pCtx){ -- UCollator *p = (UCollator *)pCtx; -- ucol_close(p); --} -- --/* --** Collation sequence comparison function. The pCtx argument points to --** a UCollator structure previously allocated using ucol_open(). --*/ --static int icuCollationColl( -- void *pCtx, -- int nLeft, -- const void *zLeft, -- int nRight, -- const void *zRight --){ -- UCollationResult res; -- UCollator *p = (UCollator *)pCtx; -- res = ucol_strcoll(p, (UChar *)zLeft, nLeft/2, (UChar *)zRight, nRight/2); -- switch( res ){ -- case UCOL_LESS: return -1; -- case UCOL_GREATER: return +1; -- case UCOL_EQUAL: return 0; -- } -- assert(!"Unexpected return value from ucol_strcoll()"); -- return 0; --} -- --/* --** Implementation of the scalar function icu_load_collation(). --** --** This scalar function is used to add ICU collation based collation --** types to an SQLite database connection. It is intended to be called --** as follows: --** --** SELECT icu_load_collation(, ); --** --** Where is a string containing an ICU locale identifier (i.e. --** "en_AU", "tr_TR" etc.) and is the name of the --** collation sequence to create. --*/ --static void icuLoadCollation( -- sqlite3_context *p, -- int nArg, -- sqlite3_value **apArg --){ -- sqlite3 *db = (sqlite3 *)sqlite3_user_data(p); -- UErrorCode status = U_ZERO_ERROR; -- const char *zLocale; /* Locale identifier - (eg. "jp_JP") */ -- const char *zName; /* SQL Collation sequence name (eg. "japanese") */ -- UCollator *pUCollator; /* ICU library collation object */ -- int rc; /* Return code from sqlite3_create_collation_x() */ -- -- assert(nArg==2 || nArg==3); -- (void)nArg; /* Unused parameter */ -- zLocale = (const char *)sqlite3_value_text(apArg[0]); -- zName = (const char *)sqlite3_value_text(apArg[1]); -- -- if( !zLocale || !zName ){ -- return; -- } -- -- pUCollator = ucol_open(zLocale, &status); -- if( !U_SUCCESS(status) ){ -- icuFunctionError(p, "ucol_open", status); -- return; -- } -- assert(p); -- if(nArg==3){ -- const char *zOption = (const char*)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]) ){ -- sqlite3_str *pStr = sqlite3_str_new(sqlite3_context_db_handle(p)); -- sqlite3_str_appendf(pStr, -- "unknown collation strength \"%s\" - should be one of:", -- zOption); -- for(i=0; izName, p->nArg, p->enc, -- p->iContext ? (void*)db : (void*)0, -- p->xFunc, 0, 0 -- ); -- } -- -- return rc; --} -- --#if !SQLITE_CORE --#ifdef _WIN32 --__declspec(dllexport) --#endif --SQLITE_API int sqlite3_icu_init( -- sqlite3 *db, -- char **pzErrMsg, -- const sqlite3_api_routines *pApi --){ -- SQLITE_EXTENSION_INIT2(pApi) -- return sqlite3IcuInit(db); --} --#endif -- --#endif -- --/************** End of icu.c *************************************************/ --/************** Begin file fts3_icu.c ****************************************/ --/* --** 2007 June 22 --** --** The author disclaims copyright to this source code. In place of --** a legal notice, here is a blessing: --** --** May you do good and not evil. --** May you find forgiveness for yourself and forgive others. --** May you share freely, never taking more than you give. --** --************************************************************************* --** This file implements a tokenizer for fts3 based on the ICU library. --*/ --/* #include "fts3Int.h" */ --#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) --#ifdef SQLITE_ENABLE_ICU -- --/* #include */ --/* #include */ --/* #include "fts3_tokenizer.h" */ -- --#include --/* #include */ --/* #include */ --#include -- --typedef struct IcuTokenizer IcuTokenizer; --typedef struct IcuCursor IcuCursor; -- --struct IcuTokenizer { -- sqlite3_tokenizer base; -- char *zLocale; --}; -- --struct IcuCursor { -- sqlite3_tokenizer_cursor base; -- -- UBreakIterator *pIter; /* ICU break-iterator object */ -- int nChar; /* Number of UChar elements in pInput */ -- UChar *aChar; /* Copy of input using utf-16 encoding */ -- int *aOffset; /* Offsets of each character in utf-8 input */ -- -- int nBuffer; -- char *zBuffer; -- -- int iToken; --}; -- --/* --** Create a new tokenizer instance. --*/ --static int icuCreate( -- int argc, /* Number of entries in argv[] */ -- const char * const *argv, /* Tokenizer creation arguments */ -- sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ --){ -- IcuTokenizer *p; -- int n = 0; -- -- if( argc>0 ){ -- n = strlen(argv[0])+1; -- } -- p = (IcuTokenizer *)sqlite3_malloc64(sizeof(IcuTokenizer)+n); -- if( !p ){ -- return SQLITE_NOMEM; -- } -- memset(p, 0, sizeof(IcuTokenizer)); -- -- if( n ){ -- p->zLocale = (char *)&p[1]; -- memcpy(p->zLocale, argv[0], n); -- } -- -- *ppTokenizer = (sqlite3_tokenizer *)p; -- -- return SQLITE_OK; --} -- --/* --** Destroy a tokenizer --*/ --static int icuDestroy(sqlite3_tokenizer *pTokenizer){ -- IcuTokenizer *p = (IcuTokenizer *)pTokenizer; -- sqlite3_free(p); -- return SQLITE_OK; --} -- --/* --** Prepare to begin tokenizing a particular string. The input --** string to be tokenized is pInput[0..nBytes-1]. A cursor --** used to incrementally tokenize this string is returned in --** *ppCursor. --*/ --static int icuOpen( -- sqlite3_tokenizer *pTokenizer, /* The tokenizer */ -- const char *zInput, /* Input string */ -- int nInput, /* Length of zInput in bytes */ -- sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ --){ -- IcuTokenizer *p = (IcuTokenizer *)pTokenizer; -- IcuCursor *pCsr; -- -- const int32_t opt = U_FOLD_CASE_DEFAULT; -- UErrorCode status = U_ZERO_ERROR; -- int nChar; -- -- UChar32 c; -- int iInput = 0; -- int iOut = 0; -- -- *ppCursor = 0; -- -- if( zInput==0 ){ -- nInput = 0; -- zInput = ""; -- }else if( nInput<0 ){ -- nInput = strlen(zInput); -- } -- nChar = nInput+1; -- pCsr = (IcuCursor *)sqlite3_malloc64( -- sizeof(IcuCursor) + /* IcuCursor */ -- ((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */ -- (nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */ -- ); -- if( !pCsr ){ -- return SQLITE_NOMEM; -- } -- memset(pCsr, 0, sizeof(IcuCursor)); -- pCsr->aChar = (UChar *)&pCsr[1]; -- pCsr->aOffset = (int *)&pCsr->aChar[(nChar+3)&~3]; -- -- pCsr->aOffset[iOut] = iInput; -- U8_NEXT(zInput, iInput, nInput, c); -- while( c>0 ){ -- int isError = 0; -- c = u_foldCase(c, opt); -- U16_APPEND(pCsr->aChar, iOut, nChar, c, isError); -- if( isError ){ -- sqlite3_free(pCsr); -- return SQLITE_ERROR; -- } -- pCsr->aOffset[iOut] = iInput; -- -- if( iInputpIter = ubrk_open(UBRK_WORD, p->zLocale, pCsr->aChar, iOut, &status); -- if( !U_SUCCESS(status) ){ -- sqlite3_free(pCsr); -- return SQLITE_ERROR; -- } -- pCsr->nChar = iOut; -- -- ubrk_first(pCsr->pIter); -- *ppCursor = (sqlite3_tokenizer_cursor *)pCsr; -- return SQLITE_OK; --} -- --/* --** Close a tokenization cursor previously opened by a call to icuOpen(). --*/ --static int icuClose(sqlite3_tokenizer_cursor *pCursor){ -- IcuCursor *pCsr = (IcuCursor *)pCursor; -- ubrk_close(pCsr->pIter); -- sqlite3_free(pCsr->zBuffer); -- sqlite3_free(pCsr); -- return SQLITE_OK; --} -- --/* --** Extract the next token from a tokenization cursor. --*/ --static int icuNext( -- sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by simpleOpen */ -- const char **ppToken, /* OUT: *ppToken is the token text */ -- int *pnBytes, /* OUT: Number of bytes in token */ -- int *piStartOffset, /* OUT: Starting offset of token */ -- int *piEndOffset, /* OUT: Ending offset of token */ -- int *piPosition /* OUT: Position integer of token */ --){ -- IcuCursor *pCsr = (IcuCursor *)pCursor; -- -- int iStart = 0; -- int iEnd = 0; -- int nByte = 0; -- -- while( iStart==iEnd ){ -- UChar32 c; -- -- iStart = ubrk_current(pCsr->pIter); -- iEnd = ubrk_next(pCsr->pIter); -- if( iEnd==UBRK_DONE ){ -- return SQLITE_DONE; -- } -- -- while( iStartaChar, iWhite, pCsr->nChar, c); -- if( u_isspace(c) ){ -- iStart = iWhite; -- }else{ -- break; -- } -- } -- assert(iStart<=iEnd); -- } -- -- do { -- UErrorCode status = U_ZERO_ERROR; -- if( nByte ){ -- char *zNew = sqlite3_realloc(pCsr->zBuffer, nByte); -- if( !zNew ){ -- return SQLITE_NOMEM; -- } -- pCsr->zBuffer = zNew; -- pCsr->nBuffer = nByte; -- } -- -- u_strToUTF8( -- pCsr->zBuffer, pCsr->nBuffer, &nByte, /* Output vars */ -- &pCsr->aChar[iStart], iEnd-iStart, /* Input vars */ -- &status /* Output success/failure */ -- ); -- } while( nByte>pCsr->nBuffer ); -- -- *ppToken = pCsr->zBuffer; -- *pnBytes = nByte; -- *piStartOffset = pCsr->aOffset[iStart]; -- *piEndOffset = pCsr->aOffset[iEnd]; -- *piPosition = pCsr->iToken++; -- -- return SQLITE_OK; --} -- --/* --** The set of routines that implement the simple tokenizer --*/ --static const sqlite3_tokenizer_module icuTokenizerModule = { -- 0, /* iVersion */ -- icuCreate, /* xCreate */ -- icuDestroy, /* xCreate */ -- icuOpen, /* xOpen */ -- icuClose, /* xClose */ -- icuNext, /* xNext */ -- 0, /* xLanguageid */ --}; -- --/* --** Set *ppModule to point at the implementation of the ICU tokenizer. --*/ --SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( -- sqlite3_tokenizer_module const**ppModule --){ -- *ppModule = &icuTokenizerModule; --} -- --#endif /* defined(SQLITE_ENABLE_ICU) */ --#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ -- --/************** End of fts3_icu.c ********************************************/ - /************** Begin file sqlite3rbu.c **************************************/ - /* - ** 2014 August 30 -@@ -261916,15 +261028,6 @@ static void DumpLocksByPager(Pager *pPager) - - // hw export the symbols - #ifdef SQLITE_EXPORT_SYMBOLS --/************** Begin hw export the symbols *****************************************/ --#if defined(__GNUC__) --# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) --#elif defined(_MSC_VER) --# define EXPORT_SYMBOLS __declspec(dllexport) --#else --# define EXPORT_SYMBOLS --#endif -- - struct sqlite3_api_routines_hw { - int (*initialize)(); - int (*config)(int,...); -diff --git a/src/sqlite3icu.c b/src/sqlite3icu.c -new file mode 100644 -index 0000000..75aa78c ---- /dev/null -+++ b/src/sqlite3icu.c -@@ -0,0 +1,925 @@ -+/****************************************************************************** -+** This file is an amalgamation of many separate C source files from SQLite -+** version 3.40.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 -+** of 5% or more are commonly seen when SQLite is compiled as a single -+** translation unit. -+** -+** This file is all you need to compile SQLite. To use SQLite in other -+** programs, you need this file and the "sqlite3.h" header file that defines -+** the programming interface to the SQLite library. (If you do not have -+** the "sqlite3.h" header file at hand, you will find a copy embedded within -+** the text of this file. Search for "Begin file sqlite3.h" to find the start -+** of the embedded sqlite3.h header file.) Additional code files may be needed -+** if you want a wrapper to interface SQLite with your choice of programming -+** language. The code for the "sqlite3" command-line shell is also in a -+** separate file. This file contains only code for the core SQLite library. -+*/ -+/* -+** 2019.09.02-Complete codec logic for encryption and decryption. -+** Huawei Technologies Co, Ltd. -+*/ -+/************** Begin file icu.c *********************************************/ -+/* -+** 2007 May 6 -+** -+** The author disclaims copyright to this source code. In place of -+** a legal notice, here is a blessing: -+** -+** May you do good and not evil. -+** May you find forgiveness for yourself and forgive others. -+** May you share freely, never taking more than you give. -+** -+************************************************************************* -+** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $ -+** -+** This file implements an integration between the ICU library -+** ("International Components for Unicode", an open-source library -+** for handling unicode data) and SQLite. The integration uses -+** ICU to provide the following to SQLite: -+** -+** * An implementation of the SQL regexp() function (and hence REGEXP -+** operator) using the ICU uregex_XX() APIs. -+** -+** * Implementations of the SQL scalar upper() and lower() functions -+** for case mapping. -+** -+** * Integration of ICU and SQLite collation sequences. -+** -+** * An implementation of the LIKE operator that uses ICU to -+** provide case-independent matching. -+*/ -+#include -+#include -+#include -+#include -+#include -+ -+#include "sqlite3icu.h" -+#include "sqlite3.h" -+ -+#ifdef HARMONY_OS -+#include "common/unicode/putil.h" -+#endif -+ -+#if !defined(SQLITE_CORE) \ -+ || defined(SQLITE_ENABLE_ICU) \ -+ || defined(SQLITE_ENABLE_ICU_COLLATIONS) -+ -+/* Include ICU headers */ -+#include -+#include -+#include -+#include -+ -+#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) -+ /* This case when the file really is being compiled as a loadable -+ ** extension */ -+# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; -+# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; -+# define SQLITE_EXTENSION_INIT3 \ -+ extern const sqlite3_api_routines *sqlite3_api; -+#else -+ /* 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 */ -+# define SQLITE_EXTENSION_INIT3 /*no-op*/ -+#endif -+ -+/* #include */ -+ -+#ifndef SQLITE_CORE -+/* #include "sqlite3ext.h" */ -+ SQLITE_EXTENSION_INIT1 -+#else -+/* #include "sqlite3.h" */ -+#endif -+ -+// hw export the symbols -+#ifdef SQLITE_EXPORT_SYMBOLS -+#if defined(__GNUC__) -+# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) -+#elif defined(_MSC_VER) -+# define EXPORT_SYMBOLS __declspec(dllexport) -+#else -+# define EXPORT_SYMBOLS -+#endif -+#endif -+ -+EXPORT_SYMBOLS SQLITE_API int sqlite3IcuInit(sqlite3 *db); -+#ifdef SQLITE_ENABLE_ICU -+EXPORT_SYMBOLS SQLITE_API void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); -+#endif -+/* -+** This function is called when an ICU function called from within -+** the implementation of an SQL scalar function returns an error. -+** -+** The scalar function context passed as the first argument is -+** loaded with an error message based on the following two args. -+*/ -+static void icuFunctionError( -+ sqlite3_context *pCtx, /* SQLite scalar function context */ -+ const char *zName, /* Name of ICU function that failed */ -+ UErrorCode e /* Error code returned by ICU function */ -+){ -+ char zBuf[128]; -+ sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e)); -+ zBuf[127] = '\0'; -+ sqlite3_result_error(pCtx, zBuf, -1); -+} -+ -+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) -+ -+/* -+** Maximum length (in bytes) of the pattern in a LIKE or GLOB -+** operator. -+*/ -+#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH -+# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000 -+#endif -+ -+/* -+** Version of sqlite3_free() that is always a function, never a macro. -+*/ -+static void xFree(void *p){ -+ sqlite3_free(p); -+} -+ -+/* -+** This lookup table is used to help decode the first byte of -+** a multi-byte UTF8 character. It is copied here from SQLite source -+** code file utf8.c. -+*/ -+static const unsigned char icuUtf8Trans1[] = { -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, -+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, -+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, -+}; -+ -+#define SQLITE_ICU_READ_UTF8(zIn, c) \ -+ c = *(zIn++); \ -+ if( c>=0xc0 ){ \ -+ c = icuUtf8Trans1[c-0xc0]; \ -+ while( (*zIn & 0xc0)==0x80 ){ \ -+ c = (c<<6) + (0x3f & *(zIn++)); \ -+ } \ -+ } -+ -+#define SQLITE_ICU_SKIP_UTF8(zIn) \ -+ assert( *zIn ); \ -+ if( *(zIn++)>=0xc0 ){ \ -+ while( (*zIn & 0xc0)==0x80 ){zIn++;} \ -+ } -+ -+ -+/* -+** Compare two UTF-8 strings for equality where the first string is -+** a "LIKE" expression. Return true (1) if they are the same and -+** false (0) if they are different. -+*/ -+static int icuLikeCompare( -+ const uint8_t *zPattern, /* LIKE pattern */ -+ const uint8_t *zString, /* The UTF-8 string to compare against */ -+ const UChar32 uEsc /* The escape character */ -+){ -+ static const uint32_t MATCH_ONE = (uint32_t)'_'; -+ static const uint32_t MATCH_ALL = (uint32_t)'%'; -+ -+ int prevEscape = 0; /* True if the previous character was uEsc */ -+ -+ while( 1 ){ -+ -+ /* Read (and consume) the next character from the input pattern. */ -+ uint32_t uPattern; -+ SQLITE_ICU_READ_UTF8(zPattern, uPattern); -+ if( uPattern==0 ) break; -+ -+ /* There are now 4 possibilities: -+ ** -+ ** 1. uPattern is an unescaped match-all character "%", -+ ** 2. uPattern is an unescaped match-one character "_", -+ ** 3. uPattern is an unescaped escape character, or -+ ** 4. uPattern is to be handled as an ordinary character -+ */ -+ if( uPattern==MATCH_ALL && !prevEscape && uPattern!=(uint32_t)uEsc ){ -+ /* Case 1. */ -+ uint8_t c; -+ -+ /* Skip any MATCH_ALL or MATCH_ONE characters that follow a -+ ** MATCH_ALL. For each MATCH_ONE, skip one character in the -+ ** test string. -+ */ -+ while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){ -+ if( c==MATCH_ONE ){ -+ if( *zString==0 ) return 0; -+ SQLITE_ICU_SKIP_UTF8(zString); -+ } -+ zPattern++; -+ } -+ -+ if( *zPattern==0 ) return 1; -+ -+ while( *zString ){ -+ if( icuLikeCompare(zPattern, zString, uEsc) ){ -+ return 1; -+ } -+ SQLITE_ICU_SKIP_UTF8(zString); -+ } -+ return 0; -+ -+ }else if( uPattern==MATCH_ONE && !prevEscape && uPattern!=(uint32_t)uEsc ){ -+ /* Case 2. */ -+ if( *zString==0 ) return 0; -+ SQLITE_ICU_SKIP_UTF8(zString); -+ -+ }else if( uPattern==(uint32_t)uEsc && !prevEscape ){ -+ /* Case 3. */ -+ prevEscape = 1; -+ -+ }else{ -+ /* Case 4. */ -+ uint32_t uString; -+ SQLITE_ICU_READ_UTF8(zString, uString); -+ uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT); -+ uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT); -+ if( uString!=uPattern ){ -+ return 0; -+ } -+ prevEscape = 0; -+ } -+ } -+ -+ return *zString==0; -+} -+ -+/* -+** Implementation of the like() SQL function. This function implements -+** the build-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 -+** -+** is implemented as like(B, A). If there is an escape character E, -+** -+** A LIKE B ESCAPE E -+** -+** is mapped to like(B, A, E). -+*/ -+static void icuLikeFunc( -+ sqlite3_context *context, -+ int argc, -+ sqlite3_value **argv -+){ -+ const unsigned char *zA = sqlite3_value_text(argv[0]); -+ const unsigned char *zB = sqlite3_value_text(argv[1]); -+ UChar32 uEsc = 0; -+ -+ /* Limit the length of the LIKE or GLOB pattern to avoid problems -+ ** of deep recursion and N*N behavior in patternCompare(). -+ */ -+ if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){ -+ sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); -+ return; -+ } -+ -+ -+ if( argc==3 ){ -+ /* The escape character string must consist of a single UTF-8 character. -+ ** Otherwise, return an error. -+ */ -+ int nE= sqlite3_value_bytes(argv[2]); -+ const unsigned char *zE = sqlite3_value_text(argv[2]); -+ int i = 0; -+ if( zE==0 ) return; -+ U8_NEXT(zE, i, nE, uEsc); -+ if( i!=nE){ -+ sqlite3_result_error(context, -+ "ESCAPE expression must be a single character", -1); -+ return; -+ } -+ } -+ -+ if( zA && zB ){ -+ sqlite3_result_int(context, icuLikeCompare(zA, zB, uEsc)); -+ } -+} -+ -+/* -+** Function to delete compiled regexp objects. Registered as -+** a destructor function with sqlite3_set_auxdata(). -+*/ -+static void icuRegexpDelete(void *p){ -+ URegularExpression *pExpr = (URegularExpression *)p; -+ uregex_close(pExpr); -+} -+ -+/* -+** Implementation of SQLite REGEXP operator. This scalar function takes -+** two arguments. The first is a regular expression pattern to compile -+** the second is a string to match against that pattern. If either -+** argument is an SQL NULL, then NULL Is returned. Otherwise, the result -+** is 1 if the string matches the pattern, or 0 otherwise. -+** -+** SQLite maps the regexp() function to the regexp() operator such -+** that the following two are equivalent: -+** -+** zString REGEXP zPattern -+** regexp(zPattern, zString) -+** -+** Uses the following ICU regexp APIs: -+** -+** uregex_open() -+** uregex_matches() -+** uregex_close() -+*/ -+static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ -+ UErrorCode status = U_ZERO_ERROR; -+ URegularExpression *pExpr; -+ UBool res; -+ const UChar *zString = sqlite3_value_text16(apArg[1]); -+ -+ (void)nArg; /* Unused parameter */ -+ -+ /* If the left hand side of the regexp operator is NULL, -+ ** then the result is also NULL. -+ */ -+ if( !zString ){ -+ return; -+ } -+ -+ pExpr = sqlite3_get_auxdata(p, 0); -+ if( !pExpr ){ -+ const UChar *zPattern = sqlite3_value_text16(apArg[0]); -+ if( !zPattern ){ -+ return; -+ } -+ pExpr = uregex_open(zPattern, -1, 0, 0, &status); -+ -+ if( U_SUCCESS(status) ){ -+ sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete); -+ pExpr = sqlite3_get_auxdata(p, 0); -+ } -+ if( !pExpr ){ -+ icuFunctionError(p, "uregex_open", status); -+ return; -+ } -+ } -+ -+ /* Configure the text that the regular expression operates on. */ -+ uregex_setText(pExpr, zString, -1, &status); -+ if( !U_SUCCESS(status) ){ -+ icuFunctionError(p, "uregex_setText", status); -+ return; -+ } -+ -+ /* Attempt the match */ -+ res = uregex_matches(pExpr, 0, &status); -+ if( !U_SUCCESS(status) ){ -+ icuFunctionError(p, "uregex_matches", status); -+ return; -+ } -+ -+ /* Set the text that the regular expression operates on to a NULL -+ ** pointer. This is not really necessary, but it is tidier than -+ ** leaving the regular expression object configured with an invalid -+ ** pointer after this function returns. -+ */ -+ uregex_setText(pExpr, 0, 0, &status); -+ -+ /* Return 1 or 0. */ -+ sqlite3_result_int(p, res ? 1 : 0); -+} -+ -+/* -+** Implementations of scalar functions for case mapping - upper() and -+** lower(). Function upper() converts its input to upper-case (ABC). -+** Function lower() converts to lower-case (abc). -+** -+** ICU provides two types of case mapping, "general" case mapping and -+** "language specific". Refer to ICU documentation for the differences -+** between the two. -+** -+** To utilise "general" case mapping, the upper() or lower() scalar -+** functions are invoked with one argument: -+** -+** upper('ABC') -> 'abc' -+** lower('abc') -> 'ABC' -+** -+** To access ICU "language specific" case mapping, upper() or lower() -+** should be invoked with two arguments. The second argument is the name -+** of the locale to use. Passing an empty string ("") or SQL NULL value -+** as the second argument is the same as invoking the 1 argument version -+** of upper() or lower(). -+** -+** lower('I', 'en_us') -> 'i' -+** lower('I', 'tr_tr') -> '\u131' (small dotless i) -+** -+** http://www.icu-project.org/userguide/posix.html#case_mappings -+*/ -+static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ -+ const UChar *zInput; /* Pointer to input string */ -+ UChar *zOutput = 0; /* Pointer to output buffer */ -+ int nInput; /* Size of utf-16 input string in bytes */ -+ int nOut; /* Size of output buffer in bytes */ -+ int cnt; -+ int bToUpper; /* True for toupper(), false for tolower() */ -+ UErrorCode status; -+ const char *zLocale = 0; -+ -+ assert(nArg==1 || nArg==2); -+ bToUpper = (sqlite3_user_data(p)!=0); -+ if( nArg==2 ){ -+ zLocale = (const char *)sqlite3_value_text(apArg[1]); -+ } -+ -+ zInput = sqlite3_value_text16(apArg[0]); -+ if( !zInput ){ -+ return; -+ } -+ nOut = nInput = sqlite3_value_bytes16(apArg[0]); -+ if( nOut==0 ){ -+ sqlite3_result_text16(p, "", 0, SQLITE_STATIC); -+ return; -+ } -+ -+ for(cnt=0; cnt<2; cnt++){ -+ UChar *zNew = sqlite3_realloc(zOutput, nOut); -+ if( zNew==0 ){ -+ sqlite3_free(zOutput); -+ sqlite3_result_error_nomem(p); -+ return; -+ } -+ zOutput = zNew; -+ status = U_ZERO_ERROR; -+ if( bToUpper ){ -+ nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); -+ }else{ -+ nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); -+ } -+ -+ if( U_SUCCESS(status) ){ -+ sqlite3_result_text16(p, zOutput, nOut, xFree); -+ }else if( status==U_BUFFER_OVERFLOW_ERROR ){ -+ assert( cnt==0 ); -+ continue; -+ }else{ -+ icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status); -+ } -+ return; -+ } -+ assert( 0 ); /* Unreachable */ -+} -+ -+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ -+ -+/* -+** Collation sequence destructor function. The pCtx argument points to -+** a UCollator structure previously allocated using ucol_open(). -+*/ -+static void icuCollationDel(void *pCtx){ -+ UCollator *p = (UCollator *)pCtx; -+ ucol_close(p); -+} -+ -+/* -+** Collation sequence comparison function. The pCtx argument points to -+** a UCollator structure previously allocated using ucol_open(). -+*/ -+static int icuCollationColl( -+ void *pCtx, -+ int nLeft, -+ const void *zLeft, -+ int nRight, -+ const void *zRight -+){ -+ UCollationResult res; -+ UCollator *p = (UCollator *)pCtx; -+ res = ucol_strcoll(p, (UChar *)zLeft, nLeft/2, (UChar *)zRight, nRight/2); -+ switch( res ){ -+ case UCOL_LESS: return -1; -+ case UCOL_GREATER: return +1; -+ case UCOL_EQUAL: return 0; -+ } -+ assert(!"Unexpected return value from ucol_strcoll()"); -+ return 0; -+} -+ -+/* -+** Implementation of the scalar function icu_load_collation(). -+** -+** This scalar function is used to add ICU collation based collation -+** types to an SQLite database connection. It is intended to be called -+** as follows: -+** -+** SELECT icu_load_collation(, ); -+** -+** Where is a string containing an ICU locale identifier (i.e. -+** "en_AU", "tr_TR" etc.) and is the name of the -+** collation sequence to create. -+*/ -+static void icuLoadCollation( -+ sqlite3_context *p, -+ int nArg, -+ sqlite3_value **apArg -+){ -+ sqlite3 *db = (sqlite3 *)sqlite3_user_data(p); -+ UErrorCode status = U_ZERO_ERROR; -+ const char *zLocale; /* Locale identifier - (eg. "jp_JP") */ -+ const char *zName; /* SQL Collation sequence name (eg. "japanese") */ -+ UCollator *pUCollator; /* ICU library collation object */ -+ int rc; /* Return code from sqlite3_create_collation_x() */ -+ -+ assert(nArg==2 || nArg==3); -+ (void)nArg; /* Unused parameter */ -+ zLocale = (const char *)sqlite3_value_text(apArg[0]); -+ zName = (const char *)sqlite3_value_text(apArg[1]); -+ -+ if( !zLocale || !zName ){ -+ return; -+ } -+ -+ pUCollator = ucol_open(zLocale, &status); -+ if( !U_SUCCESS(status) ){ -+ icuFunctionError(p, "ucol_open", status); -+ return; -+ } -+ assert(p); -+ if(nArg==3){ -+ const char *zOption = (const char*)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]) ){ -+ sqlite3_str *pStr = sqlite3_str_new(sqlite3_context_db_handle(p)); -+ sqlite3_str_appendf(pStr, -+ "unknown collation strength \"%s\" - should be one of:", -+ zOption); -+ for(i=0; izName, p->nArg, p->enc, -+ p->iContext ? (void*)db : (void*)0, -+ p->xFunc, 0, 0 -+ ); -+ } -+ -+ return rc; -+} -+ -+#if !SQLITE_CORE -+#ifdef _WIN32 -+__declspec(dllexport) -+#endif -+SQLITE_API int sqlite3_icu_init( -+ sqlite3 *db, -+ char **pzErrMsg, -+ const sqlite3_api_routines *pApi -+){ -+ SQLITE_EXTENSION_INIT2(pApi) -+ return sqlite3IcuInit(db); -+} -+#endif -+ -+#endif -+ -+/************** End of icu.c *************************************************/ -+/************** Begin file fts3_icu.c ****************************************/ -+/* -+** 2007 June 22 -+** -+** The author disclaims copyright to this source code. In place of -+** a legal notice, here is a blessing: -+** -+** May you do good and not evil. -+** May you find forgiveness for yourself and forgive others. -+** May you share freely, never taking more than you give. -+** -+************************************************************************* -+** This file implements a tokenizer for fts3 based on the ICU library. -+*/ -+/* #include "fts3Int.h" */ -+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) -+#ifdef SQLITE_ENABLE_ICU -+ -+/* #include */ -+/* #include */ -+/* #include "fts3_tokenizer.h" */ -+ -+#include -+/* #include */ -+/* #include */ -+#include -+ -+typedef struct IcuTokenizer IcuTokenizer; -+typedef struct IcuCursor IcuCursor; -+ -+struct IcuTokenizer { -+ sqlite3_tokenizer base; -+ char *zLocale; -+}; -+ -+struct IcuCursor { -+ sqlite3_tokenizer_cursor base; -+ -+ UBreakIterator *pIter; /* ICU break-iterator object */ -+ int nChar; /* Number of UChar elements in pInput */ -+ UChar *aChar; /* Copy of input using utf-16 encoding */ -+ int *aOffset; /* Offsets of each character in utf-8 input */ -+ -+ int nBuffer; -+ char *zBuffer; -+ -+ int iToken; -+}; -+ -+/* -+** Create a new tokenizer instance. -+*/ -+static int icuCreate( -+ int argc, /* Number of entries in argv[] */ -+ const char * const *argv, /* Tokenizer creation arguments */ -+ sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ -+){ -+ IcuTokenizer *p; -+ int n = 0; -+ -+ if( argc>0 ){ -+ n = strlen(argv[0])+1; -+ } -+ p = (IcuTokenizer *)sqlite3_malloc64(sizeof(IcuTokenizer)+n); -+ if( !p ){ -+ return SQLITE_NOMEM; -+ } -+ memset(p, 0, sizeof(IcuTokenizer)); -+ -+ if( n ){ -+ p->zLocale = (char *)&p[1]; -+ memcpy(p->zLocale, argv[0], n); -+ } -+ -+ *ppTokenizer = (sqlite3_tokenizer *)p; -+ -+ return SQLITE_OK; -+} -+ -+/* -+** Destroy a tokenizer -+*/ -+static int icuDestroy(sqlite3_tokenizer *pTokenizer){ -+ IcuTokenizer *p = (IcuTokenizer *)pTokenizer; -+ sqlite3_free(p); -+ return SQLITE_OK; -+} -+ -+/* -+** Prepare to begin tokenizing a particular string. The input -+** string to be tokenized is pInput[0..nBytes-1]. A cursor -+** used to incrementally tokenize this string is returned in -+** *ppCursor. -+*/ -+static int icuOpen( -+ sqlite3_tokenizer *pTokenizer, /* The tokenizer */ -+ const char *zInput, /* Input string */ -+ int nInput, /* Length of zInput in bytes */ -+ sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ -+){ -+ IcuTokenizer *p = (IcuTokenizer *)pTokenizer; -+ IcuCursor *pCsr; -+ -+ const int32_t opt = U_FOLD_CASE_DEFAULT; -+ UErrorCode status = U_ZERO_ERROR; -+ int nChar; -+ -+ UChar32 c; -+ int iInput = 0; -+ int iOut = 0; -+ -+ *ppCursor = 0; -+ -+ if( zInput==0 ){ -+ nInput = 0; -+ zInput = ""; -+ }else if( nInput<0 ){ -+ nInput = strlen(zInput); -+ } -+ nChar = nInput+1; -+ pCsr = (IcuCursor *)sqlite3_malloc64( -+ sizeof(IcuCursor) + /* IcuCursor */ -+ ((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */ -+ (nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */ -+ ); -+ if( !pCsr ){ -+ return SQLITE_NOMEM; -+ } -+ memset(pCsr, 0, sizeof(IcuCursor)); -+ pCsr->aChar = (UChar *)&pCsr[1]; -+ pCsr->aOffset = (int *)&pCsr->aChar[(nChar+3)&~3]; -+ -+ pCsr->aOffset[iOut] = iInput; -+ U8_NEXT(zInput, iInput, nInput, c); -+ while( c>0 ){ -+ int isError = 0; -+ c = u_foldCase(c, opt); -+ U16_APPEND(pCsr->aChar, iOut, nChar, c, isError); -+ if( isError ){ -+ sqlite3_free(pCsr); -+ return SQLITE_ERROR; -+ } -+ pCsr->aOffset[iOut] = iInput; -+ -+ if( iInputpIter = ubrk_open(UBRK_WORD, p->zLocale, pCsr->aChar, iOut, &status); -+ if( !U_SUCCESS(status) ){ -+ sqlite3_free(pCsr); -+ return SQLITE_ERROR; -+ } -+ pCsr->nChar = iOut; -+ -+ ubrk_first(pCsr->pIter); -+ *ppCursor = (sqlite3_tokenizer_cursor *)pCsr; -+ return SQLITE_OK; -+} -+ -+/* -+** Close a tokenization cursor previously opened by a call to icuOpen(). -+*/ -+static int icuClose(sqlite3_tokenizer_cursor *pCursor){ -+ IcuCursor *pCsr = (IcuCursor *)pCursor; -+ ubrk_close(pCsr->pIter); -+ sqlite3_free(pCsr->zBuffer); -+ sqlite3_free(pCsr); -+ return SQLITE_OK; -+} -+ -+/* -+** Extract the next token from a tokenization cursor. -+*/ -+static int icuNext( -+ sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by simpleOpen */ -+ const char **ppToken, /* OUT: *ppToken is the token text */ -+ int *pnBytes, /* OUT: Number of bytes in token */ -+ int *piStartOffset, /* OUT: Starting offset of token */ -+ int *piEndOffset, /* OUT: Ending offset of token */ -+ int *piPosition /* OUT: Position integer of token */ -+){ -+ IcuCursor *pCsr = (IcuCursor *)pCursor; -+ -+ int iStart = 0; -+ int iEnd = 0; -+ int nByte = 0; -+ -+ while( iStart==iEnd ){ -+ UChar32 c; -+ -+ iStart = ubrk_current(pCsr->pIter); -+ iEnd = ubrk_next(pCsr->pIter); -+ if( iEnd==UBRK_DONE ){ -+ return SQLITE_DONE; -+ } -+ -+ while( iStartaChar, iWhite, pCsr->nChar, c); -+ if( u_isspace(c) ){ -+ iStart = iWhite; -+ }else{ -+ break; -+ } -+ } -+ assert(iStart<=iEnd); -+ } -+ -+ do { -+ UErrorCode status = U_ZERO_ERROR; -+ if( nByte ){ -+ char *zNew = sqlite3_realloc(pCsr->zBuffer, nByte); -+ if( !zNew ){ -+ return SQLITE_NOMEM; -+ } -+ pCsr->zBuffer = zNew; -+ pCsr->nBuffer = nByte; -+ } -+ -+ u_strToUTF8( -+ pCsr->zBuffer, pCsr->nBuffer, &nByte, /* Output vars */ -+ &pCsr->aChar[iStart], iEnd-iStart, /* Input vars */ -+ &status /* Output success/failure */ -+ ); -+ } while( nByte>pCsr->nBuffer ); -+ -+ *ppToken = pCsr->zBuffer; -+ *pnBytes = nByte; -+ *piStartOffset = pCsr->aOffset[iStart]; -+ *piEndOffset = pCsr->aOffset[iEnd]; -+ *piPosition = pCsr->iToken++; -+ -+ return SQLITE_OK; -+} -+ -+/* -+** The set of routines that implement the simple tokenizer -+*/ -+static const sqlite3_tokenizer_module icuTokenizerModule = { -+ 0, /* iVersion */ -+ icuCreate, /* xCreate */ -+ icuDestroy, /* xCreate */ -+ icuOpen, /* xOpen */ -+ icuClose, /* xClose */ -+ icuNext, /* xNext */ -+ 0, /* xLanguageid */ -+}; -+ -+/* -+** Set *ppModule to point at the implementation of the ICU tokenizer. -+*/ -+EXPORT_SYMBOLS SQLITE_API void sqlite3Fts3IcuTokenizerModule( -+ sqlite3_tokenizer_module const**ppModule -+){ -+ *ppModule = &icuTokenizerModule; -+} -+ -+#endif /* defined(SQLITE_ENABLE_ICU) */ -+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ -+ -+/************** End of fts3_icu.c ********************************************/ --- -2.47.0.windows.2 - diff --git a/patch/0005-Report-corruption-when-runtime-decteted.patch b/patch/0005-Report-corruption-when-runtime-decteted.patch deleted file mode 100644 index 2af605a..0000000 --- a/patch/0005-Report-corruption-when-runtime-decteted.patch +++ /dev/null @@ -1,1446 +0,0 @@ -From 0fdc896d7434be7ad9a3947aaca13d5ce760547d Mon Sep 17 00:00:00 2001 -From: MartinChoo <214582617@qq.com> -Date: Tue, 25 Feb 2025 22:16:42 +0800 -Subject: [PATCH] Report corruption when runtime detected - -Signed-off-by: MartinChoo <214582617@qq.com> ---- - src/sqlite3.c | 717 ++++++++++++++++++++++++++++++++++++++++++-------- - 1 file changed, 605 insertions(+), 112 deletions(-) - -diff --git a/src/sqlite3.c b/src/sqlite3.c -index f348f3c..0666938 100644 ---- a/src/sqlite3.c -+++ b/src/sqlite3.c -@@ -2474,6 +2474,21 @@ struct sqlite3_mem_methods { - ** 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. -+** -+** [[SQLITE_CONFIG_CORRUPTION]]

    SQLITE_CONFIG_CORRUPTION
    -+**
    The SQLITE_CONFIG_CORRUPTION option is used to configure the SQLite -+** global [ corruption error]. -+** (^The SQLITE_CONFIG_CORRUPTION option takes two arguments: a pointer to a -+** function with a call signature of void(*)(void*,const void*), -+** and a pointer to void. ^If the function pointer is not NULL, it is -+** invoked to process each data corruption event. ^If the -+** function pointer is NULL, no=op will do when corruption detect. -+** ^The void pointer that is the second argument to SQLITE_CONFIG_CORRUPTION is -+** passed through as the first parameter to the application-defined corruption -+** function whenever that function is invoked. ^The second parameter to -+** the corruption function is a corruption message after formatting via [sqlite3_snprintf()]. -+** In a multi-threaded application, the application-defined corruption -+** function must be threadsafe.
    - ** - */ - #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ -@@ -2506,7 +2521,8 @@ struct sqlite3_mem_methods { - #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ - #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ - #define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */ --#define SQLITE_CONFIG_ENABLE_ICU 31 /* boolean */ -+#define SQLITE_CONFIG_CORRUPTION 31 /* xCorruption */ -+#define SQLITE_CONFIG_ENABLE_ICU 32 /* boolean */ - - /* - ** CAPI3REF: Database Connection Configuration Options -@@ -20360,6 +20376,8 @@ struct Sqlite3Config { - int iOnceResetThreshold; /* When to reset OP_Once counters */ - u32 szSorterRef; /* Min size in bytes to use sorter-refs */ - unsigned int iPrngSeed; /* Alternative fixed seed for the PRNG */ -+ void (*xCorruption)(void *, const void *); -+ void *pCorruptionArg; - /* vvvv--- must be last ---vvv */ - #ifdef SQLITE_DEBUG - sqlite3_int64 aTune[SQLITE_NTUNE]; /* Tuning parameters */ -@@ -20627,6 +20645,57 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprLis - } \ - } - -+#define SQLITE_PRINT_CORRUPT_SIZE (SQLITE_PRINT_BUF_SIZE * 2) -+ -+#define SQLITE_CORRUPT_CONTEXT(N,P,T,O,S,M,R) \ -+ { .nPage=(N), .pgno=(P), .type=(T), \ -+ .zoneRange={(O),(S)}, .zMsg=(M), .reservedArgs=(R) } -+ -+typedef struct { -+ int offset; -+ size_t size; -+}sqlite3CorruptRange; -+ -+typedef enum { -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ CORRUPT_TYPE_PAGE_BTREE_INTERIOR, -+ CORRUPT_TYPE_PAGE_INDEX_LEAF, -+ CORRUPT_TYPE_PAGE_INDEX_INTERIOR, -+ CORRUPT_TYPE_PAGE_OVERFLOW, -+ CORRUPT_TYPE_PAGE_PTR_MAP, -+ CORRUPT_TYPE_PAGE_FREE_LIST, -+ CORRUPT_TYPE_FRAME_WAL, -+ CORRUPT_TYPE_ENTRY_JOURNAL, -+ CORRUPT_TYPE_VDBE, -+ CORRUPT_TYPE_FILE_HEADER, -+ CORRUPT_TYPE_UNKOWN, -+} CorruptType; -+ -+typedef struct { -+ size_t nPage; /* Number of pages */ -+ unsigned int pgno; /* Page number for corrupted page */ -+ CorruptType type; -+ sqlite3CorruptRange zoneRange; -+ const char *zMsg; -+ void *reservedArgs; -+}sqlite3CorruptContext; -+ -+// Encode buffer with base16, return size after encode -+static size_t sqlite3base16Encode(const unsigned char *buffer, size_t bufSize, char *encodeBuf, size_t encodeBufSize) -+{ -+ if (buffer == NULL || bufSize == 0 || encodeBuf == NULL || encodeBufSize == 0) { -+ return 0; -+ } -+ static const char base16Code[] = "0123456789ABCDEF"; -+ size_t i = 0; -+ for (; i < bufSize && (i * 2 < encodeBufSize - 1); i++) { -+ *encodeBuf++ = base16Code[(buffer[i] >> 4) & 0x0F]; -+ *encodeBuf++ = base16Code[buffer[i] & 0x0F]; -+ } -+ *encodeBuf = '\0'; -+ return i * 2; -+} -+ - /* - ** The SQLITE_*_BKPT macros are substitutes for the error codes with - ** the same name but without the _BKPT suffix. These macros invoke -@@ -20635,10 +20704,11 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprLis - ** to set a debugger breakpoint. - */ - SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType); --SQLITE_PRIVATE int sqlite3CorruptError(int); -+SQLITE_PRIVATE int sqlite3CorruptError(int lineno, sqlite3CorruptContext *context); - SQLITE_PRIVATE int sqlite3MisuseError(int); - SQLITE_PRIVATE int sqlite3CantopenError(int); --#define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__) -+#define SQLITE_CORRUPT_REPORT(context) sqlite3CorruptError(__LINE__,(context)) -+#define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__,NULL) - #define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__) - #define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__) - #ifdef SQLITE_DEBUG -@@ -20650,12 +20720,13 @@ SQLITE_PRIVATE int sqlite3IoerrnomemError(int); - # define SQLITE_NOMEM_BKPT SQLITE_NOMEM - # define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM - #endif --#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO) -+#if (defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO)) - SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno); --# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P)) -+# define SQLITE_CORRUPT_PGNO(P,context) sqlite3CorruptPgnoError(__LINE__,(P)) - #else --# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__) -+# define SQLITE_CORRUPT_PGNO(P,context) sqlite3CorruptError(__LINE__,(context)) - #endif -+# define SQLITE_CORRUPT_REPORT_PGNO(context) SQLITE_CORRUPT_PGNO((context)->pgno,(context)) - - /* - ** FTS3 and FTS4 both require virtual table support -@@ -23111,6 +23182,8 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { - 0x7ffffffe, /* iOnceResetThreshold */ - SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */ - 0, /* iPrngSeed */ -+ 0, /* xCorruption */ -+ 0, /* pCorruptionArg */ - #ifdef SQLITE_DEBUG - {0,0,0,0,0,0}, /* aTune */ - #endif -@@ -60758,7 +60831,7 @@ static int readDbPage(PgHdr *pPg){ - assert( isOpen(pPager->fd) ); - - if( pagerUseWal(pPager) ){ -- rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); -+ rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); // find in wal-index - if( rc ) return rc; - } - if( iFrame ){ -@@ -63281,7 +63354,12 @@ static int getPageNormal( - assert( assert_pager_state(pPager) ); - assert( pPager->hasHeldSharedLock==1 ); - -- if( pgno==0 ) return SQLITE_CORRUPT_BKPT; -+ if( pgno==0 ) { -+ const char *zMsg = "pgno should not be 0"; -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, 0, CORRUPT_TYPE_UNKOWN, -+ -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_REPORT(&context); -+ } - pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3); - if( pBase==0 ){ - pPg = 0; -@@ -63313,7 +63391,11 @@ static int getPageNormal( - ** (2) Never try to fetch the locking page - */ - if( pgno==PAGER_SJ_PGNO(pPager) ){ -- rc = SQLITE_CORRUPT_BKPT; -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "try fetching the locking page(%u)", pgno); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, pgno, CORRUPT_TYPE_UNKOWN, -+ -1, 0, zMsg, NULL); -+ rc = SQLITE_CORRUPT_REPORT(&context); - goto pager_acquire_err; - } - -@@ -63399,7 +63481,10 @@ static int getPageMMap( - ** test in the previous statement, and avoid testing pgno==0 in the - ** common case where pgno is large. */ - if( pgno<=1 && pgno==0 ){ -- return SQLITE_CORRUPT_BKPT; -+ const char *zMsg = "pgno should not be 0"; -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, 0, CORRUPT_TYPE_UNKOWN, -+ -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_REPORT(&context); - } - assert( pPager->eState>=PAGER_READER ); - assert( assert_pager_state(pPager) ); -@@ -65010,7 +65095,11 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i - if( pPgOld ){ - if( NEVER(pPgOld->nRef>1) ){ - sqlite3PagerUnrefNotNull(pPgOld); -- return SQLITE_CORRUPT_BKPT; -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "page(%u) should be no references, ref cnt:%d", pgno, (int)pPgOld->nRef); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, pgno, CORRUPT_TYPE_UNKOWN, -+ -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_REPORT(&context); - } - pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); - if( pPager->tempFile ){ -@@ -66940,7 +67029,13 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ - /* Write the aPgno[] array entry and the hash-table slot. */ - nCollide = idx; - for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ -- if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT; -+ if( (nCollide--)==0 ){ -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "no place for page(%u) to map into WAL, idx:%d", iPage, idx); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, iPage, CORRUPT_TYPE_FRAME_WAL, -+ -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_REPORT(&context); -+ } - } - sLoc.aPgno[idx-1] = iPage; - AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx); -@@ -67889,7 +67984,13 @@ static int walCheckpoint( - ** database plus the amount of data in the wal file, plus the - ** maximum size of the pending-byte page (65536 bytes), then - ** must be corruption somewhere. */ -- rc = SQLITE_CORRUPT_BKPT; -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, -+ "final db size unexpected,nSize=%lld,mxFrame=%u,pageSize=%d,nReq=%lld", -+ nSize, pWal->hdr.mxFrame, szPage, nReq); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, 0, CORRUPT_TYPE_FRAME_WAL, -+ -1, 0, zMsg, NULL); -+ rc = SQLITE_CORRUPT_REPORT(&context); - }else{ - sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT,&nReq); - } -@@ -69201,7 +69302,11 @@ static int walFindFrame( - } - if( (nCollide--)==0 ){ - *piRead = 0; -- return SQLITE_CORRUPT_BKPT; -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "mis-match page(%u) to map into WAL", pgno); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, pgno, CORRUPT_TYPE_FRAME_WAL, -+ -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_REPORT(&context); - } - iKey = walNextHash(iKey); - } -@@ -70005,7 +70110,12 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( - /* Copy data from the log to the database file. */ - if( rc==SQLITE_OK ){ - if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ -- rc = SQLITE_CORRUPT_BKPT; -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "mis-match between pageSize=%d and bufferSize=%d, mxFrame=%u", -+ walPagesize(pWal),nBuf,pWal->hdr.mxFrame); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, 0, CORRUPT_TYPE_FRAME_WAL, -+ -1, 0, zMsg, NULL); -+ rc = SQLITE_CORRUPT_REPORT(&context); - }else{ - rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags,zBuf); - } -@@ -71469,7 +71579,7 @@ static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf){ - ** with the page number and filename associated with the (MemPage*). - */ - #ifdef SQLITE_DEBUG --int corruptPageError(int lineno, MemPage *p){ -+int corruptPageError(int lineno, MemPage *p, sqlite3CorruptContext *context){ - char *zMsg; - sqlite3BeginBenignMalloc(); - zMsg = sqlite3_mprintf("database corruption page %u of %s", -@@ -71480,11 +71590,11 @@ int corruptPageError(int lineno, MemPage *p){ - sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg); - } - sqlite3_free(zMsg); -- return SQLITE_CORRUPT_BKPT; -+ return SQLITE_CORRUPT_REPORT(context); - } --# define SQLITE_CORRUPT_PAGE(pMemPage) corruptPageError(__LINE__, pMemPage) -+# define SQLITE_CORRUPT_PAGE(context,pMemPage) corruptPageError(__LINE__, (pMemPage),(context)) - #else --# define SQLITE_CORRUPT_PAGE(pMemPage) SQLITE_CORRUPT_PGNO(pMemPage->pgno) -+# define SQLITE_CORRUPT_PAGE(context,pMemPage) SQLITE_CORRUPT_PGNO((pMemPage)->pgno,(context)) - #endif - - /* Default value for SHARED_LOCK_TRACE macro if shared-cache is disabled -@@ -72210,7 +72320,12 @@ static int btreeMoveto( - if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT; - sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey); - if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){ -- rc = SQLITE_CORRUPT_BKPT; -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpected fields in total:%u, should != 0 and < %u", -+ pIdxKey->nField,pKeyInfo->nAllField); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pCur->pBt->nPage, 0, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ -1, 0, zMsg, NULL); -+ rc = SQLITE_CORRUPT_REPORT(&context); - }else{ - rc = sqlite3BtreeIndexMoveto(pCur, pIdxKey, pRes); - } -@@ -72407,7 +72522,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ - assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) ); - - assert( pBt->autoVacuum ); -- if( key==0 ){ -+ if( key==0 ){ // The pgno of each entry on ptrmap page starts from 3, an unexpected pgno indicates data corrupted - *pRC = SQLITE_CORRUPT_BKPT; - return; - } -@@ -72421,12 +72536,24 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ - /* The first byte of the extra data is the MemPage.isInit byte. - ** If that byte is set, it means this page is also being used - ** as a btree page. */ -- *pRC = SQLITE_CORRUPT_BKPT; -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode((unsigned char *)sqlite3PagerGetExtra(pDbPage), 8, xBuffer, sizeof(xBuffer)); -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "page(%u) been initialized before as a btree page, base16:%s", -+ iPtrmap, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, -+ -1, 0, zMsg, NULL); -+ *pRC = SQLITE_CORRUPT_REPORT(&context); - goto ptrmap_exit; - } - offset = PTRMAP_PTROFFSET(iPtrmap, key); - if( offset<0 ){ -- *pRC = SQLITE_CORRUPT_BKPT; -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpect offset in ptrmap page(%u), target:%u, page usableSize=%u", -+ iPtrmap, key, pBt->usableSize); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, -+ -1, 0, zMsg, NULL); -+ *pRC = SQLITE_CORRUPT_REPORT(&context); - goto ptrmap_exit; - } - assert( offset <= (int)pBt->usableSize-5 ); -@@ -72471,7 +72598,12 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ - offset = PTRMAP_PTROFFSET(iPtrmap, key); - if( offset<0 ){ - sqlite3PagerUnref(pDbPage); -- return SQLITE_CORRUPT_BKPT; -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpect offset in ptrmap page(%d), target:%u, page usableSize=%u", -+ iPtrmap, key, pBt->usableSize); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, -+ -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_REPORT(&context); - } - assert( offset <= (int)pBt->usableSize-5 ); - assert( pEType!=0 ); -@@ -72479,7 +72611,15 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ - if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); - - sqlite3PagerUnref(pDbPage); -- if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_PGNO(iPtrmap); -+ if( *pEType<1 || *pEType>5 ){ -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; // 5 bytes for each entry on ptrmap page -+ (void)sqlite3base16Encode(pPtrmap, 5, xBuffer, sizeof(xBuffer)); -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpect entry type:%d, base16:%s", (int)*pEType, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, -+ offset, 5, zMsg, NULL); -+ return SQLITE_CORRUPT_REPORT_PGNO(&context); -+ } - return SQLITE_OK; - } - -@@ -72919,7 +73059,14 @@ static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){ - Pgno ovfl; - if( SQLITE_OVERFLOW(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){ - testcase( pSrc!=pPage ); -- *pRC = SQLITE_CORRUPT_BKPT; -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; // Output cell header as much as possible, 4 bytes for overflow pgno -+ (void)sqlite3base16Encode(pCell, info.nSize - info.nLocal - 4, xBuffer, sizeof(xBuffer)); -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell overflow, offset=%d, rest=%d, length=%u, base16:%s", -+ (int)(pCell - pPage->aData), (int)(pSrc->aDataEnd - pCell), info.nSize, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ pCell - pPage->aData, info.nSize, zMsg, NULL); -+ *pRC = SQLITE_CORRUPT_REPORT(&context); - return; - } - ovfl = get4byte(&pCell[info.nSize-4]); -@@ -72977,10 +73124,29 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ - ** reconstruct the entire page. */ - if( (int)data[hdr+7]<=nMaxFrag ){ - int iFree = get2byte(&data[hdr+1]); -- if( iFree>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); -+ if( iFree>usableSize-4 ){ -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Output first 8 bytes as it's page header -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset=%d overflow, usableSize=%d, base16:%s", -+ iFree, usableSize, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ 0, 8, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); -+ } - if( iFree ){ - int iFree2 = get2byte(&data[iFree]); -- if( iFree2>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); -+ if( iFree2>usableSize-4 ){ -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(data, 4, xBuffer, sizeof(xBuffer)); // Output first freeblock's header 4 bytes -+ sqlite3_snprintf(sizeof(zMsg), zMsg, -+ "1st freeblock's next pointer overflow, point:%d, usableSize=%d, base16:%s", -+ iFree2, usableSize, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ iFree, 4, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); -+ } - if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){ - u8 *pEnd = &data[cellOffset + nCell*2]; - u8 *pAddr; -@@ -72988,16 +73154,51 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ - int sz = get2byte(&data[iFree+2]); - int top = get2byte(&data[hdr+5]); - if( top>=iFree ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Print first 8 bytes which is page header -+ sqlite3_snprintf(sizeof(zMsg), zMsg, -+ "1st freeblock's offset:%d should > CellContentArea's offset:%d, base16:%s", -+ iFree, top, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ iFree, 8, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - if( iFree2 ){ -- if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PAGE(pPage); -+ if( iFree+sz>iFree2 ){ -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Print first 8 bytes which is page header -+ sqlite3_snprintf(sizeof(zMsg), zMsg, -+ "the 1st 2 freeblocks mis-order, 1st block offset:%d, size:%d, 2nd block offset:%d, base16:%s", -+ iFree, sz, iFree2, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ iFree, 4, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); -+ } - sz2 = get2byte(&data[iFree2+2]); -- if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage); -+ if( iFree2+sz2 > usableSize ){ -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(data + iFree2, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to 2nd block -+ sqlite3_snprintf(sizeof(zMsg), zMsg, -+ "the 2nd freeblock overflow, offset:%d, size:%d, usableSize:%d, base16:%s", -+ iFree2, sz2, usableSize, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ iFree2, 4, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); -+ } - memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); - sz += sz2; - }else if( iFree+sz>usableSize ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(data + iFree, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to 1st block -+ sqlite3_snprintf(sizeof(zMsg), zMsg, -+ "the 1st freeblock overflow, offset:%d, size:%d, usableSize:%d, base16:%s", iFree, sz, usableSize, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ iFree, 4, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - - cbrk = top+sz; -@@ -73030,13 +73231,24 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ - ** if PRAGMA cell_size_check=ON. - */ - if( pc>iCellLast ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; // Print 4 bytes belong to 1st block -+ (void)sqlite3base16Encode(data + cellOffset + i*2, 2, xBuffer, sizeof(xBuffer)); -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "%d-th cell pointer:%d out of range[%d, %d], base16:%s", -+ i, pc, iCellStart, iCellLast, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ cellOffset + i*2, 2, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - assert( pc>=0 && pc<=iCellLast ); - size = pPage->xCellSize(pPage, &src[pc]); - cbrk -= size; - if( cbrkusableSize ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "move %d-th cell from %d using unexpected size:%d", i, pc, size); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - assert( cbrk+size<=usableSize && cbrk>=iCellStart ); - testcase( cbrk+size==usableSize ); -@@ -73050,7 +73262,13 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ - defragment_out: - assert( pPage->nFree>=0 ); - if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, -+ "after defragment, free bytes should not change, fragment bytes:%d, free space:%d, total:%d", -+ (int)data[hdr+7], cbrk-iCellFirst, pPage->nFree); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - assert( cbrk>=iCellFirst ); - put2byte(&data[hdr+5], cbrk); -@@ -73075,7 +73293,7 @@ defragment_out: - ** will be ignored if adding the extra space to the fragmentation count - ** causes the fragmentation count to exceed 60. - */ --static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ -+static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ // search on B-tree page - const int hdr = pPg->hdrOffset; /* Offset to page header */ - u8 * const aData = pPg->aData; /* Page data */ - int iAddr = hdr + 1; /* Address of ptr to pc */ -@@ -73107,7 +73325,15 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ - return &aData[pc]; - }else if( x+pc > maxPC ){ - /* This slot extends off the end of the usable part of the page */ -- *pRc = SQLITE_CORRUPT_PAGE(pPg); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(aData + pc, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to free block -+ sqlite3_snprintf(sizeof(zMsg), zMsg, -+ "freeblock rest bytes:%d begin at %d which cost %d, still exceed usableSize:%u, base16:%s", -+ x, pc, nByte, pPg->pBt->usableSize, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPg->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ pc, 4, zMsg, NULL); -+ *pRc = SQLITE_CORRUPT_PAGE(&context, pPg); - return 0; - }else{ - /* The slot remains on the free-list. Reduce its size to account -@@ -73122,14 +73348,25 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ - if( pc<=iAddr ){ - if( pc ){ - /* The next slot in the chain comes before the current slot */ -- *pRc = SQLITE_CORRUPT_PAGE(pPg); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(pTmp, 2, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to free block -+ sqlite3_snprintf(sizeof(zMsg), zMsg, -+ "the next slot:%d in chain comes before current slot:%d, base16:%s", pc, iAddr, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPg->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ iAddr, 2, zMsg, NULL); -+ *pRc = SQLITE_CORRUPT_PAGE(&context, pPg); - } - return 0; - } - } - if( pc>maxPC+nByte-4 ){ - /* The free slot chain extends off the end of the page */ -- *pRc = SQLITE_CORRUPT_PAGE(pPg); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "free slot:%d overflow, end:%d", pc, maxPC+nByte-4); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPg->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ -1, 0, zMsg, NULL); -+ *pRc = SQLITE_CORRUPT_PAGE(&context, pPg); - } - return 0; - } -@@ -73177,10 +73414,16 @@ static SQLITE_INLINE int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ - if( top==0 && pPage->pBt->usableSize==65536 ){ - top = 65536; - }else{ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Print 8 bytes belong to page header -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpected cellContentArea offset:%d, base16:%s", top, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - }else if( top>(int)pPage->pBt->usableSize ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pPage); - } - - /* If there is enough space between gap and top for one more cell pointer, -@@ -73197,7 +73440,11 @@ static SQLITE_INLINE int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ - assert( pSpace+nByte<=data+pPage->pBt->usableSize ); - *pIdx = g2 = (int)(pSpace-data); - if( g2<=gap ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cellpointers(end:%d) overlap with freeblock(%d)", gap, g2); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - }else{ - return SQLITE_OK; - } -@@ -73276,12 +73523,23 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ - while( (iFreeBlk = get2byte(&data[iPtr]))pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - iPtr = iFreeBlk; - } - if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(data + iPtr, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to freeblock -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset:%d overflow, base16:%s", (int)iFreeBlk, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, iPtr, 4, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - assert( iFreeBlk>iPtr || iFreeBlk==0 || CORRUPT_DB ); - -@@ -73293,10 +73551,24 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ - */ - if( iFreeBlk && iEnd+3>=iFreeBlk ){ - nFrag = iFreeBlk - iEnd; -- if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage); -+ if( iEnd>iFreeBlk ){ -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset:%d overlaps with pre block's end:%u", -+ (int)iFreeBlk, iEnd); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); -+ } - iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]); - if( iEnd > pPage->pBt->usableSize ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(data + iFreeBlk, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to freeblock -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset:%d, end:%u overflow, usableSize:%u, base16:%s", -+ (int)iFreeBlk, iEnd, pPage->pBt->usableSize, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, iFreeBlk, 4, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - iSize = iEnd - iStart; - iFreeBlk = get2byte(&data[iFreeBlk]); -@@ -73309,13 +73581,27 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ - if( iPtr>hdr+1 ){ - int iPtrEnd = iPtr + get2byte(&data[iPtr+2]); - if( iPtrEnd+3>=iStart ){ -- if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PAGE(pPage); -+ if( iPtrEnd>iStart ){ -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "check pre freeblock end:%d overlaps with the pending free block:%d", -+ iPtrEnd, (int)iStart); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, iPtr, iPtrEnd - iPtr, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); -+ } - nFrag += iStart - iPtrEnd; - iSize = iEnd - iPtr; - iStart = iPtr; - } - } -- if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage); -+ if( nFrag>data[hdr+7] ){ -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "fragment free bytes:%d increase unexpectly, should be %d", -+ (int)nFrag, (int)data[hdr+7]); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); -+ } - data[hdr+7] -= nFrag; - } - pTmp = &data[hdr+5]; -@@ -73329,8 +73615,21 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ - /* The new freeblock is at the beginning of the cell content area, - ** so just extend the cell content area rather than create another - ** freelist entry */ -- if( iStart= the beginning of the CellContentArea:%d", (int)x, (int)iStart); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); -+ } -+ if( iPtr!=hdr+1 ){ -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "1st freeblock's pos incorrect, hdr:%d, iPtr:%d", (int)hdr, (int)iPtr); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); -+ } - put2byte(&data[hdr+1], iFreeBlk); - put2byte(&data[hdr+5], iEnd); - }else{ -@@ -73391,7 +73690,13 @@ static int decodeFlags(MemPage *pPage, int flagByte){ - pPage->pgno, flagByte, pPage->isInit, pPage->intKey, pPage->intKeyLeaf, pPage->leaf, - pPage->childPtrSize, pPage->cellOffset, pPage->nCell, pPage->hdrOffset, pPage->minLocal, pPage->maxLocal, g_lastCkptTime); - #endif /* LOG_DUMP */ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(pPage->aData, 8, xBuffer, sizeof(xBuffer)); -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unrecognized flag:%d, base16:%s", flagByte, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - }else{ - pPage->childPtrSize = 4; -@@ -73422,7 +73727,13 @@ static int decodeFlags(MemPage *pPage, int flagByte){ - pPage->pgno, flagByte, pPage->isInit, pPage->intKey, pPage->intKeyLeaf, pPage->leaf, - pPage->childPtrSize, pPage->cellOffset, pPage->nCell, pPage->hdrOffset, pPage->minLocal, pPage->maxLocal, g_lastCkptTime); - #endif /* LOG_DUMP */ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(pPage->aData, 8, xBuffer, sizeof(xBuffer)); -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unrecognized flag:%d, base16:%s", flagByte, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - } - return SQLITE_OK; -@@ -73473,12 +73784,20 @@ static int btreeComputeFreeSpace(MemPage *pPage){ - /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will - ** always be at least one cell before the first freeblock. - */ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "the 1st freeblock:%d before all cells:%d", pc, top); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - while( 1 ){ - if( pc>iCellLast ){ - /* Freeblock off the end of the page */ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock end:%d out of page range:%d", pc, iCellLast); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - next = get2byte(&data[pc]); - size = get2byte(&data[pc+2]); -@@ -73488,11 +73807,19 @@ static int btreeComputeFreeSpace(MemPage *pPage){ - } - if( next>0 ){ - /* Freeblock not in ascending order */ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "all freeblocks should order by asc, pre:%d, cur:%u", pc, next); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - if( pc+size>(unsigned int)usableSize ){ - /* Last freeblock extends past page end */ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "last freeblock overflow, offset:%d, size:%u", pc, size); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - } - -@@ -73504,7 +73831,13 @@ static int btreeComputeFreeSpace(MemPage *pPage){ - ** area, according to the page header, lies within the page. - */ - if( nFree>usableSize || nFreepBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - pPage->nFree = (u16)(nFree - iCellFirst); - return SQLITE_OK; -@@ -73535,12 +73868,20 @@ static SQLITE_NOINLINE int btreeCellSizeCheck(MemPage *pPage){ - testcase( pc==iCellFirst ); - testcase( pc==iCellLast ); - if( pciCellLast ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell pointer:%d indicate out of range:[%d, %d]", pc, iCellFirst, iCellLast); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - sz = pPage->xCellSize(pPage, &data[pc]); - testcase( pc+sz==usableSize ); - if( pc+sz>usableSize ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpected cell size:%d,offset:%d, out of range:%d", sz, pc, usableSize); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - } - return SQLITE_OK; -@@ -73572,7 +73913,7 @@ static int btreeInitPage(MemPage *pPage){ - /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating - ** the b-tree page type. */ - if( decodeFlags(pPage, data[0]) ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pPage); - } - assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); - pPage->maskPage = (u16)(pBt->pageSize - 1); -@@ -73586,7 +73927,12 @@ static int btreeInitPage(MemPage *pPage){ - pPage->nCell = get2byte(&data[3]); - if( pPage->nCell>MX_CELL(pBt) ){ - /* To many cells for a single page. The page must be corrupt */ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "too many cells(%d) for the page:%u, offset:%d, out of range:%u", -+ (int)pPage->nCell, pPage->pgno, (int)pPage->hdrOffset + 3, MX_CELL(pBt)); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - testcase( pPage->nCell==MX_CELL(pBt) ); - /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only -@@ -73729,7 +74075,11 @@ static int getAndInitPage( - - if( pgno>btreePagecount(pBt) ){ - *ppPage = 0; -- return SQLITE_CORRUPT_BKPT; -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "page number(%u) > db file size(%u)", pgno, btreePagecount(pBt)); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_REPORT(&context); - } - rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly); - if( rc ){ -@@ -75199,7 +75549,12 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ - if( eType==PTRMAP_OVERFLOW2 ){ - /* The pointer is always the first 4 bytes of the page in this case. */ - if( get4byte(pPage->aData)!=iFrom ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "1st 4 bytes of ovrflow page(%u) point to next(%u), should be %u", -+ pPage->pgno, get4byte(pPage->aData), iFrom); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_PTR_MAP, -+ 0, 4, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - put4byte(pPage->aData, iTo); - }else{ -@@ -75218,7 +75573,13 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ - pPage->xParseCell(pPage, pCell, &info); - if( info.nLocal pPage->aData+pPage->pBt->usableSize ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, -+ "btree cell contain ovrflow pointer overflow, offset:%d, size:%u, usableSize:%u", -+ (int)(pCell - pPage->aData), info.nSize, pPage->pBt->usableSize); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_PTR_MAP, pCell - pPage->aData, info.nSize, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - if( iFrom==get4byte(pCell+info.nSize-4) ){ - put4byte(pCell+info.nSize-4, iTo); -@@ -75227,7 +75588,13 @@ 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); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, -+ "btree cell contain child pointer overflow, offset:%d, size:4, usableSize:%u", -+ (int)(pCell - pPage->aData), pPage->pBt->usableSize); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_PTR_MAP, pCell - pPage->aData, 4, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - if( get4byte(pCell)==iFrom ){ - put4byte(pCell, iTo); -@@ -75239,7 +75606,11 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ - if( i==nCell ){ - if( eType!=PTRMAP_BTREE || - get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "missing pointer point to overflow page on btree page(%u)", pPage->pgno); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - put4byte(&pPage->aData[pPage->hdrOffset+8], iTo); - } -@@ -75372,7 +75743,11 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){ - return rc; - } - if( eType==PTRMAP_ROOTPAGE ){ -- return SQLITE_CORRUPT_BKPT; -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "try vacuum root page(%u), should not happened", nFin); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, PTRMAP_PAGENO(pBt, iLastPg), -+ CORRUPT_TYPE_PAGE_PTR_MAP, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_REPORT(&context); - } - - if( eType==PTRMAP_FREEPAGE ){ -@@ -76448,7 +76823,12 @@ static int accessPayload( - assert( eOp==0 || eOp==1 ); - assert( pCur->eState==CURSOR_VALID ); - if( pCur->ix>=pPage->nCell ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell index:%u exceed limit:%u on the page:%u", -+ pCur->ix, pPage->nCell, pPage->pgno); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - assert( cursorHoldsMutex(pCur) ); - -@@ -76463,7 +76843,12 @@ static int accessPayload( - ** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] - ** but is recast into its current form to avoid integer overflow problems - */ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "base on payload size:%u, the max offset(%d) should > %d", -+ pCur->info.nLocal, (int)(aPayload - pPage->aData), (int)(pBt->usableSize - pCur->info.nLocal)); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ 0, 8, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - - /* Check if data must be read/written to/from the btree page itself. */ -@@ -76534,7 +76919,16 @@ static int accessPayload( - assert( rc==SQLITE_OK && amt>0 ); - while( nextPage ){ - /* If required, populate the overflow page-list cache. */ -- if( nextPage > pBt->nPage ) return SQLITE_CORRUPT_BKPT; -+ if( nextPage > pBt->nPage ){ -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(aPayload + pCur->info.nLocal, 4, xBuffer, sizeof(xBuffer)); -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow page:%u should not exceed the size of database file, base16:%s", -+ nextPage, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ aPayload - pPage->aData + pCur->info.nLocal, 4, zMsg, NULL); -+ return SQLITE_CORRUPT_REPORT(&context); -+ } - assert( pCur->aOverflow[iIdx]==0 - || pCur->aOverflow[iIdx]==nextPage - || CORRUPT_DB ); -@@ -76618,7 +77012,11 @@ static int accessPayload( - - if( rc==SQLITE_OK && amt>0 ){ - /* Overflow chain ends prematurely */ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow chain ends prematurely, rest:%d", amt); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - return rc; - } -@@ -76770,7 +77168,7 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){ - && (pCur->pPage->nCell<1 || pCur->pPage->intKey!=pCur->curIntKey) - ){ - releasePage(pCur->pPage); -- rc = SQLITE_CORRUPT_PGNO(newPgno); -+ rc = SQLITE_CORRUPT_PGNO(newPgno, NULL); - } - if( rc ){ - pCur->pPage = pCur->apPage[--pCur->iPage]; -@@ -76905,7 +77303,12 @@ static int moveToRoot(BtCursor *pCur){ - ** (or the freelist). */ - assert( pRoot->intKey==1 || pRoot->intKey==0 ); - if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){ -- return SQLITE_CORRUPT_PAGE(pCur->pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "the page(%u) state illegal, isInit:%u, pKeyInfo%s0, intKey:%u", -+ pRoot->pgno, pRoot->isInit, ((pCur->pKeyInfo==0)?"==":"!="), pRoot->intKey); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pCur->pBt->nPage, pRoot->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pCur->pPage); - } - - skip_init: -@@ -77166,7 +77569,11 @@ SQLITE_PRIVATE int sqlite3BtreeTableMoveto( - if( pPage->intKeyLeaf ){ - while( 0x80 <= *(pCell++) ){ - if( pCell>=pPage->aDataEnd ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell idx(%d) point to a cell should not out of page", idx); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - } - } -@@ -77449,7 +77856,12 @@ bypass_moveto_root: - testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */ - testcase( nCell==2 ); /* Minimum legal index key size */ - if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){ -- rc = SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "nCell:%d illegal, usableSize:%u, nPage:%u", -+ nCell, pCur->pBt->usableSize, pCur->pBt->nPage); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ rc = SQLITE_CORRUPT_PAGE(&context, pPage); - goto moveto_index_finish; - } - pCellKey = sqlite3Malloc( nCell+nOverrun ); -@@ -77523,7 +77935,7 @@ bypass_moveto_root: - && (pCur->pPage->nCell<1 || pCur->pPage->intKey!=pCur->curIntKey) - ){ - releasePage(pCur->pPage); -- rc = SQLITE_CORRUPT_PGNO(chldPg); -+ rc = SQLITE_CORRUPT_PGNO(chldPg, NULL); - } - if( rc ){ - pCur->pPage = pCur->apPage[--pCur->iPage]; -@@ -77807,7 +78219,13 @@ static int allocateBtreePage( - n = get4byte(&pPage1->aData[36]); - testcase( n==mxPage-1 ); - if( n>=mxPage ){ -- return SQLITE_CORRUPT_BKPT; -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE*3] = {0}; -+ (void)sqlite3base16Encode(pPage1->aData, 100, xBuffer, sizeof(xBuffer)); -+ sqlite3_snprintf(sizeof(zMsg), zMsg, -+ "total pages(%u) in freelist should not over the total size of db file(%u), base16:%s", n, mxPage, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, 1, CORRUPT_TYPE_FILE_HEADER, 36, 4, zMsg, NULL); -+ return SQLITE_CORRUPT_REPORT(&context); - } - if( n>0 ){ - /* There are pages on the freelist. Reuse one of those pages. */ -@@ -77863,7 +78281,12 @@ static int allocateBtreePage( - } - testcase( iTrunk==mxPage ); - if( iTrunk>mxPage || nSearch++ > n ){ -- rc = SQLITE_CORRUPT_PGNO(pPrevTrunk ? pPrevTrunk->pgno : 1); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freelist trunk page(%u) should <= the size of db(%u)", -+ iTrunk, mxPage); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, (pPrevTrunk ? pPrevTrunk->pgno : 1), -+ CORRUPT_TYPE_PAGE_FREE_LIST, -1, 0, zMsg, NULL); -+ rc = SQLITE_CORRUPT_REPORT_PGNO(&context); - }else{ - rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0); - } -@@ -77892,7 +78315,14 @@ static int allocateBtreePage( - 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); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(pTrunk->aData, 8, xBuffer, sizeof(xBuffer)); -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "total leaf pages(%u) on trunk page over limit(%u), base16:%s", -+ k, (u32)(pBt->usableSize/4 - 2), xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, -+ 0, 8, zMsg, NULL); -+ rc = SQLITE_CORRUPT_REPORT_PGNO(&context); - goto end_allocate_page; - #ifndef SQLITE_OMIT_AUTOVACUUM - }else if( searchList -@@ -77926,7 +78356,14 @@ static int allocateBtreePage( - MemPage *pNewTrunk; - Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); - if( iNewTrunk>mxPage ){ -- rc = SQLITE_CORRUPT_PGNO(iTrunk); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(pTrunk->aData, 12, xBuffer, sizeof(xBuffer)); -+ sqlite3_snprintf(sizeof(zMsg), zMsg, -+ "leaf page's pgno(%u) on trunk page exceed db file size(%u), base16:%s", iNewTrunk, mxPage, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, -+ 8, 4, zMsg, NULL); -+ rc = SQLITE_CORRUPT_REPORT_PGNO(&context); - goto end_allocate_page; - } - testcase( iNewTrunk==mxPage ); -@@ -77991,7 +78428,14 @@ static int allocateBtreePage( - iPage = get4byte(&aData[8+closest*4]); - testcase( iPage==mxPage ); - if( iPage>mxPage || iPage<2 ){ -- rc = SQLITE_CORRUPT_PGNO(iTrunk); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(aData+8+closest*4, 4, xBuffer, sizeof(xBuffer)); -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "leaf page's pgno(%u) out of range:[3, %d], base16:%s", -+ iPage, mxPage, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, -+ 8+closest*4, 4, zMsg, NULL); -+ rc = SQLITE_CORRUPT_REPORT_PGNO(&context); - goto end_allocate_page; - } - testcase( iPage==mxPage ); -@@ -78176,7 +78620,14 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ - nLeaf = get4byte(&pTrunk->aData[4]); - assert( pBt->usableSize>32 ); - if( nLeaf > (u32)pBt->usableSize/4 - 2 ){ -- rc = SQLITE_CORRUPT_BKPT; -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(pTrunk->aData, 4, xBuffer, sizeof(xBuffer)); -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "the number of leaf page(%u) on trunk page(%d) exceed limit, base16:%s", -+ nLeaf, iTrunk, xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, -+ 0, 4, zMsg, NULL); -+ rc = SQLITE_CORRUPT_REPORT(&context); - goto freepage_out; - } - if( nLeaf < (u32)pBt->usableSize/4 - 8 ){ -@@ -78265,7 +78716,12 @@ static SQLITE_NOINLINE int clearCellOverflow( - testcase( pCell + (pInfo->nSize-1) == pPage->aDataEnd ); - if( pCell + pInfo->nSize > pPage->aDataEnd ){ - /* Cell extends past end of page */ -- return SQLITE_CORRUPT_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow end of page, pgno:%u, offset:%d, size:%u, usableSize:%u", -+ pPage->pgno, (int)(pCell - pPage->aData), pInfo->nSize, pPage->pBt->usableSize); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(btreePagecount(pPage->pBt), pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - ovflPgno = get4byte(pCell + pInfo->nSize - 4); - pBt = pPage->pBt; -@@ -78282,7 +78738,14 @@ static SQLITE_NOINLINE int clearCellOverflow( - /* 0 is not a legal page number and page 1 cannot be an - ** overflow page. Therefore if ovflPgno<2 or past the end of the - ** file the database must be corrupt. */ -- return SQLITE_CORRUPT_BKPT; -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; -+ (void)sqlite3base16Encode(pCell + pInfo->nSize - 4, 4, xBuffer, sizeof(xBuffer)); -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow page's pgno(%u) illegal, out of range:[2, %u], base16:%s", -+ ovflPgno, btreePagecount(pBt), xBuffer); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(btreePagecount(pBt), pPage->pgno, -+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_REPORT(&context); - } - if( nOvfl ){ - rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext); -@@ -78558,7 +79021,12 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ - testcase( pc==(u32)get2byte(&data[hdr+5]) ); - testcase( pc+sz==pPage->pBt->usableSize ); - if( pc+sz > pPage->pBt->usableSize ){ -- *pRC = SQLITE_CORRUPT_BKPT; -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell offset:%u size:%d, idx:%d overflow, usableSize:%u", -+ pc, sz, idx, pPage->pBt->usableSize); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ -1, 0, zMsg, NULL); -+ *pRC = SQLITE_CORRUPT_REPORT(&context); - return; - } - rc = freeSpace(pPage, pc, sz); -@@ -79700,7 +80168,7 @@ static int balance_nonroot( - ** table-interior, index-leaf, or index-interior). - */ - if( pOld->aData[0]!=apOld[0]->aData[0] ){ -- rc = SQLITE_CORRUPT_PAGE(pOld); -+ rc = SQLITE_CORRUPT_PAGE(NULL, pOld); - goto balance_cleanup; - } - -@@ -79724,7 +80192,7 @@ static int balance_nonroot( - memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow)); - if( pOld->nOverflow>0 ){ - if( NEVER(limitaiOvfl[0]) ){ -- rc = SQLITE_CORRUPT_PAGE(pOld); -+ rc = SQLITE_CORRUPT_PAGE(NULL, pOld); - goto balance_cleanup; - } - limit = pOld->aiOvfl[0]; -@@ -80367,7 +80835,7 @@ static int anotherValidCursor(BtCursor *pCur){ - && pOther->eState==CURSOR_VALID - && pOther->pPage==pCur->pPage - ){ -- return SQLITE_CORRUPT_PAGE(pCur->pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pCur->pPage); - } - } - return SQLITE_OK; -@@ -80427,7 +80895,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_PAGE(pPage); -+ rc = SQLITE_CORRUPT_PAGE(NULL, pPage); - }else{ - MemPage * const pParent = pCur->apPage[iPage-1]; - int const iIdx = pCur->aiIdx[iPage-1]; -@@ -80591,7 +81059,7 @@ static SQLITE_NOINLINE int btreeOverwriteOverflowCell( - rc = btreeGetPage(pBt, ovflPgno, &pPage, 0); - if( rc ) return rc; - if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 || pPage->isInit ){ -- rc = SQLITE_CORRUPT_PAGE(pPage); -+ rc = SQLITE_CORRUPT_PAGE(NULL, pPage); - }else{ - if( iOffset+ovflPageSize<(u32)nTotal ){ - ovflPgno = get4byte(pPage->aData); -@@ -80619,7 +81087,14 @@ 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_PAGE(pPage); -+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; -+ sqlite3_snprintf(sizeof(zMsg), zMsg, -+ "cell payload cursor point to(%d), size:%u overlaps with non-cell content area:[%u, %d]", -+ (int)(pCur->info.pPayload - pPage->aData), pCur->info.nLocal, pPage->cellOffset, -+ (int)(pPage->aDataEnd - pPage->aData)); -+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -+ -1, 0, zMsg, NULL); -+ return SQLITE_CORRUPT_PAGE(&context, pPage); - } - if( pCur->info.nLocal==nTotal ){ - /* The entire cell is local */ -@@ -80700,7 +81175,7 @@ SQLITE_PRIVATE int 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_PGNO(pCur->pgnoRoot); -+ return SQLITE_CORRUPT_PGNO(pCur->pgnoRoot, NULL); - } - } - -@@ -80823,7 +81298,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( - if( pPage->nFree<0 ){ - if( NEVER(pCur->eState>CURSOR_INVALID) ){ - /* ^^^^^--- due to the moveToRoot() call above */ -- rc = SQLITE_CORRUPT_PAGE(pPage); -+ rc = SQLITE_CORRUPT_PAGE(NULL, pPage); - }else{ - rc = btreeComputeFreeSpace(pPage); - } -@@ -80865,7 +81340,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( - CellInfo info; - assert( idx>=0 ); - if( idx>=pPage->nCell ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pPage); - } - rc = sqlite3PagerWrite(pPage->pDbPage); - if( rc ){ -@@ -80892,10 +81367,10 @@ SQLITE_PRIVATE int 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_PAGE(pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pPage); - } - if( oldCell+szNew > pPage->aDataEnd ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pPage); - } - memcpy(oldCell, newCell, szNew); - return SQLITE_OK; -@@ -80997,7 +81472,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 - nIn = pSrc->info.nLocal; - aIn = pSrc->info.pPayload; - if( aIn+nIn>pSrc->pPage->aDataEnd ){ -- return SQLITE_CORRUPT_PAGE(pSrc->pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pSrc->pPage); - } - nRem = pSrc->info.nPayload; - if( nIn==nRem && nInpPage->maxLocal ){ -@@ -81022,7 +81497,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 - - if( nRem>nIn ){ - if( aIn+nIn+4>pSrc->pPage->aDataEnd ){ -- return SQLITE_CORRUPT_PAGE(pSrc->pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pSrc->pPage); - } - ovflIn = get4byte(&pSrc->info.pPayload[nIn]); - } -@@ -81118,7 +81593,7 @@ SQLITE_PRIVATE int 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_PGNO(pCur->pgnoRoot); -+ return SQLITE_CORRUPT_PGNO(pCur->pgnoRoot, NULL); - } - } - assert( pCur->eState==CURSOR_VALID ); -@@ -81127,14 +81602,14 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ - iCellIdx = pCur->ix; - pPage = pCur->pPage; - if( pPage->nCell<=iCellIdx ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pPage); - } - pCell = findCell(pPage, iCellIdx); - if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pPage); - } - if( pCell<&pPage->aCellIdx[pPage->nCell] ){ -- return SQLITE_CORRUPT_PAGE(pPage); -+ return SQLITE_CORRUPT_PAGE(NULL, pPage); - } - - /* If the BTREE_SAVEPOSITION bit is on, then the cursor position must -@@ -81225,7 +81700,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ - n = pCur->pPage->pgno; - } - pCell = findCell(pLeaf, pLeaf->nCell-1); -- if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_PAGE(pLeaf); -+ if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_PAGE(NULL, pLeaf); - nCell = pLeaf->xCellSize(pLeaf, pCell); - assert( MX_CELL_SIZE(pBt) >= nCell ); - pTmp = pBt->pTmpSpace; -@@ -81341,7 +81816,7 @@ static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){ - */ - sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot); - if( pgnoRoot>btreePagecount(pBt) ){ -- return SQLITE_CORRUPT_PGNO(pgnoRoot); -+ return SQLITE_CORRUPT_PGNO(pgnoRoot, NULL); - } - pgnoRoot++; - -@@ -81389,7 +81864,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_PGNO(pgnoRoot); -+ rc = SQLITE_CORRUPT_PGNO(pgnoRoot, NULL); - } - if( rc!=SQLITE_OK ){ - releasePage(pRoot); -@@ -81479,14 +81954,14 @@ static int clearDatabasePage( - - assert( sqlite3_mutex_held(pBt->mutex) ); - if( pgno>btreePagecount(pBt) ){ -- return SQLITE_CORRUPT_PGNO(pgno); -+ return SQLITE_CORRUPT_PGNO(pgno, NULL); - } - rc = getAndInitPage(pBt, pgno, &pPage, 0); - if( rc ) return rc; - if( (pBt->openFlags & BTREE_SINGLE)==0 - && sqlite3PagerPageRefcount(pPage->pDbPage) != (1 + (pgno==1)) - ){ -- rc = SQLITE_CORRUPT_PAGE(pPage); -+ rc = SQLITE_CORRUPT_PAGE(NULL, pPage); - goto cleardatabasepage_out; - } - hdr = pPage->hdrOffset; -@@ -81590,7 +82065,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_PGNO(iTable); -+ return SQLITE_CORRUPT_PGNO(iTable, NULL); - } - - rc = sqlite3BtreeClearTable(p, iTable, 0); -@@ -85920,7 +86395,7 @@ static int growOpArray(Vdbe *v, int nOp){ - ** - ** Other useful labels for breakpoints include: - ** test_trace_breakpoint(pc,pOp) --** sqlite3CorruptError(lineno) -+** sqlite3CorruptError(lineno,context) - ** sqlite3MisuseError(lineno) - ** sqlite3CantopenError(lineno) - */ -@@ -94157,7 +94632,7 @@ SQLITE_API int sqlite3_found_count = 0; - ** - ** Other useful labels for breakpoints include: - ** test_addop_breakpoint(pc,pOp) --** sqlite3CorruptError(lineno) -+** sqlite3CorruptError(lineno,context) - ** sqlite3MisuseError(lineno) - ** sqlite3CantopenError(lineno) - */ -@@ -181855,6 +182330,12 @@ SQLITE_API int sqlite3_config(int op, ...){ - #endif - break; - } -+ case SQLITE_CONFIG_CORRUPTION: { -+ typedef void(*CORRUPTION_FUNC_t)(void*, const void*); -+ sqlite3GlobalConfig.xCorruption = va_arg(ap, CORRUPTION_FUNC_t); -+ sqlite3GlobalConfig.pCorruptionArg = va_arg(ap, void*); -+ break; -+ } - - default: { - rc = SQLITE_ERROR; -@@ -185037,9 +185518,21 @@ SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType){ - zType, lineno, 20+sqlite3_sourceid()); - return iErr; - } --SQLITE_PRIVATE int sqlite3CorruptError(int lineno){ -+SQLITE_PRIVATE int sqlite3CorruptError(int lineno, sqlite3CorruptContext *context){ - testcase( sqlite3GlobalConfig.xLog!=0 ); -- return sqlite3ReportError(SQLITE_CORRUPT, lineno, "database corruption"); -+ if (context!=NULL && sqlite3GlobalConfig.xCorruption != 0) { -+ char zMsg[SQLITE_PRINT_BUF_SIZE] = {0}; /* Complete corruption log message */ -+ sqlite3_snprintf(sizeof(zMsg), zMsg, "pgno:%u,type:%d,range:{%d,%d},line:%d", -+ context->pgno, (int)context->type, (int)context->zoneRange.offset, (int)context->zoneRange.size, lineno); -+ sqlite3GlobalConfig.xCorruption(sqlite3GlobalConfig.pCorruptionArg, zMsg); -+ } -+ char zCorruptMsg[SQLITE_PRINT_BUF_SIZE * 10] = {0}; -+ if (context!=NULL && context->zMsg != NULL){ -+ sqlite3_snprintf(sizeof(zCorruptMsg), zCorruptMsg, "database corruption, %s", context->zMsg); -+ } else { -+ sqlite3_snprintf(sizeof(zCorruptMsg), zCorruptMsg, "database corruption"); -+ } -+ return sqlite3ReportError(SQLITE_CORRUPT, lineno, zCorruptMsg); - } - SQLITE_PRIVATE int sqlite3MisuseError(int lineno){ - testcase( sqlite3GlobalConfig.xLog!=0 ); --- -2.47.0.windows.2 - diff --git a/patch/0006-Add-extention-cksumvfs-and-check-page.patch b/patch/0006-Add-extention-cksumvfs-and-check-page.patch deleted file mode 100644 index 7e3b64f..0000000 --- a/patch/0006-Add-extention-cksumvfs-and-check-page.patch +++ /dev/null @@ -1,1079 +0,0 @@ -From 506b1d3f9ea38fd7abc841ebc41649723247c1ee Mon Sep 17 00:00:00 2001 -From: MartinChoo <214582617@qq.com> -Date: Wed, 26 Feb 2025 10:16:41 +0800 -Subject: [PATCH] Add extention:cksumvfs and check page - ---- - ext/misc/cksumvfs.c | 916 ++++++++++++++++++++++++++++++++++++++++++++ - src/sqlite3.c | 99 ++++- - 2 files changed, 1008 insertions(+), 7 deletions(-) - create mode 100644 ext/misc/cksumvfs.c - -diff --git a/ext/misc/cksumvfs.c b/ext/misc/cksumvfs.c -new file mode 100644 -index 0000000..6f4c55c ---- /dev/null -+++ b/ext/misc/cksumvfs.c -@@ -0,0 +1,916 @@ -+/* -+** 2020-04-20 -+** -+** The author disclaims copyright to this source code. In place of -+** a legal notice, here is a blessing: -+** -+** May you do good and not evil. -+** May you find forgiveness for yourself and forgive others. -+** May you share freely, never taking more than you give. -+** -+****************************************************************************** -+** -+** This file implements a VFS shim that writes a checksum on each page -+** of an SQLite database file. When reading pages, the checksum is verified -+** and an error is raised if the checksum is incorrect. -+** -+** COMPILING -+** -+** This extension requires SQLite 3.32.0 or later. It uses the -+** sqlite3_database_file_object() interface which was added in -+** version 3.32.0, so it will not link with an earlier version of -+** SQLite. -+** -+** To build this extension as a separately loaded shared library or -+** DLL, use compiler command-lines similar to the following: -+** -+** (linux) gcc -fPIC -shared cksumvfs.c -o cksumvfs.so -+** (mac) clang -fPIC -dynamiclib cksumvfs.c -o cksumvfs.dylib -+** (windows) cl cksumvfs.c -link -dll -out:cksumvfs.dll -+** -+** You may want to add additional compiler options, of course, -+** according to the needs of your project. -+** -+** If you want to statically link this extension with your product, -+** then compile it like any other C-language module but add the -+** "-DSQLITE_CKSUMVFS_STATIC" option so that this module knows that -+** it is being statically linked rather than dynamically linked -+** -+** LOADING -+** -+** To load this extension as a shared library, you first have to -+** bring up a dummy SQLite database connection to use as the argument -+** to the sqlite3_load_extension() API call. Then you invoke the -+** sqlite3_load_extension() API and shutdown the dummy database -+** connection. All subsequent database connections that are opened -+** will include this extension. For example: -+** -+** sqlite3 *db; -+** sqlite3_open(":memory:", &db); -+** sqlite3_load_extension(db, "./cksumvfs"); -+** sqlite3_close(db); -+** -+** If this extension is compiled with -DSQLITE_CKSUMVFS_STATIC and -+** statically linked against the application, initialize it using -+** a single API call as follows: -+** -+** sqlite3_register_cksumvfs(); -+** -+** Cksumvfs is a VFS Shim. When loaded, "cksmvfs" becomes the new -+** default VFS and it uses the prior default VFS as the next VFS -+** down in the stack. This is normally what you want. However, in -+** complex situations where multiple VFS shims are being loaded, -+** it might be important to ensure that cksumvfs is loaded in the -+** correct order so that it sequences itself into the default VFS -+** Shim stack in the right order. -+** -+** USING -+** -+** Open database connections using the sqlite3_open() or -+** sqlite3_open_v2() interfaces, as normal. Ordinary database files -+** (without a checksum) will operate normally. Databases with -+** checksums will return an SQLITE_IOERR_DATA error if a page is -+** encountered that contains an invalid checksum. -+** -+** Checksumming only works on databases that have a reserve-bytes -+** value of exactly 8. The default value for reserve-bytes is 0. -+** Hence, newly created database files will omit the checksum by -+** default. To create a database that includes a checksum, change -+** the reserve-bytes value to 8 by runing: -+** -+** int n = 8; -+** sqlite3_file_control(db, 0, SQLITE_FCNTL_RESERVE_BYTES, &n); -+** -+** If you do this immediately after creating a new database file, -+** before anything else has been written into the file, then that -+** might be all that you need to do. Otherwise, the API call -+** above should be followed by: -+** -+** sqlite3_exec(db, "VACUUM", 0, 0, 0); -+** -+** It never hurts to run the VACUUM, even if you don't need it. -+** If the database is in WAL mode, you should shutdown and -+** reopen all database connections before continuing. -+** -+** From the CLI, use the ".filectrl reserve_bytes 8" command, -+** followed by "VACUUM;". -+** -+** Note that SQLite allows the number of reserve-bytes to be -+** increased but not decreased. So if a database file already -+** has a reserve-bytes value greater than 8, there is no way to -+** activate checksumming on that database, other than to dump -+** and restore the database file. Note also that other extensions -+** might also make use of the reserve-bytes. Checksumming will -+** be incompatible with those other extensions. -+** -+** VERIFICATION OF CHECKSUMS -+** -+** If any checksum is incorrect, the "PRAGMA quick_check" command -+** will find it. To verify that checksums are actually enabled -+** and running, use the following query: -+** -+** SELECT count(*), verify_checksum(data) -+** FROM sqlite_dbpage -+** GROUP BY 2; -+** -+** There are three possible outputs form the verify_checksum() -+** function: 1, 0, and NULL. 1 is returned if the checksum is -+** correct. 0 is returned if the checksum is incorrect. NULL -+** is returned if the page is unreadable. If checksumming is -+** enabled, the read will fail if the checksum is wrong, so the -+** usual result from verify_checksum() on a bad checksum is NULL. -+** -+** If everything is OK, the query above should return a single -+** row where the second column is 1. Any other result indicates -+** either that there is a checksum error, or checksum validation -+** is disabled. -+** -+** CONTROLLING CHECKSUM VERIFICATION -+** -+** The cksumvfs extension implements a new PRAGMA statement that can -+** be used to disable, re-enable, or query the status of checksum -+** verification: -+** -+** PRAGMA checksum_verification; -- query status -+** PRAGMA checksum_verification=OFF; -- disable verification -+** PRAGMA checksum_verification=ON; -- re-enable verification -+** -+** The "checksum_verification" pragma will return "1" (true) or "0" -+** (false) if checksum verification is enabled or disabled, respectively. -+** "Verification" in this context means the feature that causes -+** SQLITE_IOERR_DATA errors if a checksum mismatch is detected while -+** reading. Checksums are always kept up-to-date as long as the -+** reserve-bytes value of the database is 8, regardless of the setting -+** of this pragma. Checksum verification can be disabled (for example) -+** to do forensic analysis of a database that has previously reported -+** a checksum error. -+** -+** The "checksum_verification" pragma will always respond with "0" if -+** the database file does not have a reserve-bytes value of 8. The -+** pragma will return no rows at all if the cksumvfs extension is -+** not loaded. -+** -+** IMPLEMENTATION NOTES -+** -+** The checksum is stored in the last 8 bytes of each page. This -+** module only operates if the "bytes of reserved space on each page" -+** value at offset 20 the SQLite database header is exactly 8. If -+** the reserved-space value is not 8, this module is a no-op. -+*/ -+#if defined(SQLITE_AMALGAMATION) && !defined(SQLITE_CKSUMVFS_STATIC) -+# define SQLITE_CKSUMVFS_STATIC -+#endif -+#ifdef SQLITE_CKSUMVFS_STATIC -+# include "sqlite3.h" -+#else -+# include "sqlite3ext.h" -+ SQLITE_EXTENSION_INIT1 -+#endif -+#include -+#include -+ -+// hw export the symbols -+#ifdef SQLITE_EXPORT_SYMBOLS -+#if defined(__GNUC__) -+# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) -+#elif defined(_MSC_VER) -+# define EXPORT_SYMBOLS __declspec(dllexport) -+#else -+# define EXPORT_SYMBOLS -+#endif -+#endif -+ -+/* -+** Forward declaration of objects used by this utility -+*/ -+typedef struct sqlite3_vfs CksmVfs; -+typedef struct CksmFile CksmFile; -+ -+/* -+** Useful datatype abbreviations -+*/ -+#if !defined(SQLITE_AMALGAMATION) -+ typedef unsigned char u8; -+ typedef unsigned int u32; -+#endif -+ -+/* Access to a lower-level VFS that (might) implement dynamic loading, -+** access to randomness, etc. -+*/ -+#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) -+#define ORIGFILE(p) ((sqlite3_file*)(((CksmFile*)(p))+1)) -+ -+/* An open file */ -+struct CksmFile { -+ sqlite3_file base; /* IO methods */ -+ const char *zFName; /* Original name of the file */ -+ char computeCksm; /* True to compute checksums. -+ ** Always true if reserve size is 8. */ -+ char verifyCksm; /* True to verify checksums */ -+ char isWal; /* True if processing a WAL file */ -+ char inCkpt; /* Currently doing a checkpoint */ -+ CksmFile *pPartner; /* Ptr from WAL to main-db, or from main-db to WAL */ -+}; -+ -+/* -+** Methods for CksmFile -+*/ -+static int cksmClose(sqlite3_file*); -+static int cksmRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); -+static int cksmWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); -+static int cksmTruncate(sqlite3_file*, sqlite3_int64 size); -+static int cksmSync(sqlite3_file*, int flags); -+static int cksmFileSize(sqlite3_file*, sqlite3_int64 *pSize); -+static int cksmLock(sqlite3_file*, int); -+static int cksmUnlock(sqlite3_file*, int); -+static int cksmCheckReservedLock(sqlite3_file*, int *pResOut); -+static int cksmFileControl(sqlite3_file*, int op, void *pArg); -+static int cksmSectorSize(sqlite3_file*); -+static int cksmDeviceCharacteristics(sqlite3_file*); -+static int cksmShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**); -+static int cksmShmLock(sqlite3_file*, int offset, int n, int flags); -+static void cksmShmBarrier(sqlite3_file*); -+static int cksmShmUnmap(sqlite3_file*, int deleteFlag); -+static int cksmFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); -+static int cksmUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p); -+ -+/* -+** Methods for CksmVfs -+*/ -+static int cksmOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); -+static int cksmDelete(sqlite3_vfs*, const char *zName, int syncDir); -+static int cksmAccess(sqlite3_vfs*, const char *zName, int flags, int *); -+static int cksmFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); -+static void *cksmDlOpen(sqlite3_vfs*, const char *zFilename); -+static void cksmDlError(sqlite3_vfs*, int nByte, char *zErrMsg); -+static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void); -+static void cksmDlClose(sqlite3_vfs*, void*); -+static int cksmRandomness(sqlite3_vfs*, int nByte, char *zOut); -+static int cksmSleep(sqlite3_vfs*, int microseconds); -+static int cksmCurrentTime(sqlite3_vfs*, double*); -+static int cksmGetLastError(sqlite3_vfs*, int, char *); -+static int cksmCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); -+static int cksmSetSystemCall(sqlite3_vfs*, const char*,sqlite3_syscall_ptr); -+static sqlite3_syscall_ptr cksmGetSystemCall(sqlite3_vfs*, const char *z); -+static const char *cksmNextSystemCall(sqlite3_vfs*, const char *zName); -+ -+static sqlite3_vfs cksm_vfs = { -+ 3, /* iVersion (set when registered) */ -+ 0, /* szOsFile (set when registered) */ -+ 1024, /* mxPathname */ -+ 0, /* pNext */ -+ "cksmvfs", /* zName */ -+ 0, /* pAppData (set when registered) */ -+ cksmOpen, /* xOpen */ -+ cksmDelete, /* xDelete */ -+ cksmAccess, /* xAccess */ -+ cksmFullPathname, /* xFullPathname */ -+ cksmDlOpen, /* xDlOpen */ -+ cksmDlError, /* xDlError */ -+ cksmDlSym, /* xDlSym */ -+ cksmDlClose, /* xDlClose */ -+ cksmRandomness, /* xRandomness */ -+ cksmSleep, /* xSleep */ -+ cksmCurrentTime, /* xCurrentTime */ -+ cksmGetLastError, /* xGetLastError */ -+ cksmCurrentTimeInt64, /* xCurrentTimeInt64 */ -+ cksmSetSystemCall, /* xSetSystemCall */ -+ cksmGetSystemCall, /* xGetSystemCall */ -+ cksmNextSystemCall /* xNextSystemCall */ -+}; -+ -+static const sqlite3_io_methods cksm_io_methods = { -+ 3, /* iVersion */ -+ cksmClose, /* xClose */ -+ cksmRead, /* xRead */ -+ cksmWrite, /* xWrite */ -+ cksmTruncate, /* xTruncate */ -+ cksmSync, /* xSync */ -+ cksmFileSize, /* xFileSize */ -+ cksmLock, /* xLock */ -+ cksmUnlock, /* xUnlock */ -+ cksmCheckReservedLock, /* xCheckReservedLock */ -+ cksmFileControl, /* xFileControl */ -+ cksmSectorSize, /* xSectorSize */ -+ cksmDeviceCharacteristics, /* xDeviceCharacteristics */ -+ cksmShmMap, /* xShmMap */ -+ cksmShmLock, /* xShmLock */ -+ cksmShmBarrier, /* xShmBarrier */ -+ cksmShmUnmap, /* xShmUnmap */ -+ cksmFetch, /* xFetch */ -+ cksmUnfetch /* xUnfetch */ -+}; -+ -+/* Do byte swapping on a unsigned 32-bit integer */ -+#define BYTESWAP32(x) ( \ -+ (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \ -+ + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \ -+) -+ -+/* Compute a checksum on a buffer */ -+static void cksmCompute( -+ u8 *a, /* Content to be checksummed */ -+ int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */ -+ u8 *aOut /* OUT: Final 8-byte checksum value output */ -+){ -+ u32 s1 = 0, s2 = 0; -+ u32 *aData = (u32*)a; -+ u32 *aEnd = (u32*)&a[nByte]; -+ u32 x = 1; -+ -+ assert( nByte>=8 ); -+ assert( (nByte&0x00000007)==0 ); -+ assert( nByte<=65536 ); -+ -+ if( 1 == *(u8*)&x ){ -+ /* Little-endian */ -+ do { -+ s1 += *aData++ + s2; -+ s2 += *aData++ + s1; -+ }while( aData65536 || (nByte & (nByte-1))!=0 ) return; -+ cksmCompute(data, nByte-8, cksum); -+ sqlite3_result_int(context, memcmp(data+nByte-8,cksum,8)==0); -+} -+ -+#ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME -+/* -+** SQL function: initialize_cksumvfs(SCHEMANAME) -+** -+** This SQL functions (whose name is actually determined at compile-time -+** by the value of the SQLITE_CKSUMVFS_INIT_FUNCNAME macro) invokes: -+** -+** sqlite3_file_control(db, SCHEMANAME, SQLITE_FCNTL_RESERVE_BYTE, &n); -+** -+** In order to set the reserve bytes value to 8, so that cksumvfs will -+** operation. This feature is provided (if and only if the -+** SQLITE_CKSUMVFS_INIT_FUNCNAME compile-time option is set to a string -+** which is the name of the SQL function) so as to provide the ability -+** to invoke the file-control in programming languages that lack -+** direct access to the sqlite3_file_control() interface (ex: Java). -+** -+** This interface is undocumented, apart from this comment. Usage -+** example: -+** -+** 1. Compile with -DSQLITE_CKSUMVFS_INIT_FUNCNAME="ckvfs_init" -+** 2. Run: "SELECT cksum_init('main'); VACUUM;" -+*/ -+static void cksmInitFunc( -+ sqlite3_context *context, -+ int argc, -+ sqlite3_value **argv -+){ -+ int nByte = 8; -+ const char *zSchemaName = (const char*)sqlite3_value_text(argv[0]); -+ sqlite3 *db = sqlite3_context_db_handle(context); -+ sqlite3_file_control(db, zSchemaName, SQLITE_FCNTL_RESERVE_BYTES, &nByte); -+ /* Return NULL */ -+} -+#endif /* SQLITE_CKSUMBFS_INIT_FUNCNAME */ -+ -+/* -+** Close a cksm-file. -+*/ -+static int cksmClose(sqlite3_file *pFile){ -+ CksmFile *p = (CksmFile *)pFile; -+ if( p->pPartner ){ -+ assert( p->pPartner->pPartner==p ); -+ p->pPartner->pPartner = 0; -+ p->pPartner = 0; -+ } -+ pFile = ORIGFILE(pFile); -+ return pFile->pMethods->xClose(pFile); -+} -+ -+/* -+** Set the computeCkSm and verifyCksm flags, if they need to be -+** changed. -+*/ -+static void cksmSetFlags(CksmFile *p, int hasCorrectReserveSize){ -+ if( hasCorrectReserveSize!=p->computeCksm ){ -+ p->computeCksm = p->verifyCksm = hasCorrectReserveSize; -+ if( p->pPartner ){ -+ p->pPartner->verifyCksm = hasCorrectReserveSize; -+ p->pPartner->computeCksm = hasCorrectReserveSize; -+ } -+ } -+} -+ -+static void EncodeReservedBytesIntoBase16(const u8 *reserved, int len, char *encodeStr, int maxLen){ -+ static const char baseCode[] = "0123456789ABCDEF"; -+ for(int i=0; i> 4) & 0x0F]; -+ *encodeStr++ = baseCode[reserved[i] & 0x0F]; -+ } -+ *encodeStr = '0'; -+} -+ -+/* -+** Read data from a cksm-file. -+*/ -+static int cksmRead( -+ sqlite3_file *pFile, -+ void *zBuf, -+ int iAmt, -+ sqlite_int64 iOfst -+){ -+ int rc; -+ CksmFile *p = (CksmFile *)pFile; -+ pFile = ORIGFILE(pFile); -+ rc = pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst); -+ if( rc==SQLITE_OK ){ -+ if( iOfst==0 && iAmt>=100 && ( -+ memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0 -+ )){ -+ u8 *d = (u8*)zBuf; -+ char hasCorrectReserveSize = (d[20]==8); -+ cksmSetFlags(p, hasCorrectReserveSize); -+ } -+ /* Verify the checksum if -+ ** (1) the size indicates that we are dealing with a complete -+ ** database page, only support pageSize:4K -+ ** (2) checksum verification is enabled -+ ** (3) we are not in the middle of checkpoint -+ */ -+ if( iAmt==4096 /* (1) */ -+ && p->verifyCksm /* (2) */ -+ && !p->inCkpt /* (3) */ -+ ){ -+ u8 cksum[8]; -+ cksmCompute((u8*)zBuf, iAmt-8, cksum); -+ if( memcmp((u8*)zBuf+iAmt-8, cksum, 8)!=0 ){ -+ char expect[18] = {0}; -+ char actual[18] = {0}; -+ EncodeReservedBytesIntoBase16((u8 *)zBuf+iAmt-8, 8, expect, 18); -+ EncodeReservedBytesIntoBase16(cksum, 8, actual, 18); -+ sqlite3_log(SQLITE_IOERR_DATA, "checksum fault offset %lld of \"%s\", amt:%d, expect:%s, actual:%s", -+ iOfst, p->zFName, iAmt, expect, actual); -+ rc = SQLITE_IOERR_DATA; -+ } -+ } -+ } -+ return rc; -+} -+ -+/* -+** Write data to a cksm-file. -+*/ -+static int cksmWrite( -+ sqlite3_file *pFile, -+ const void *zBuf, -+ int iAmt, -+ sqlite_int64 iOfst -+){ -+ CksmFile *p = (CksmFile *)pFile; -+ pFile = ORIGFILE(pFile); -+ if( iOfst==0 && iAmt>=100 && ( -+ memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0 -+ )){ -+ u8 *d = (u8*)zBuf; -+ char hasCorrectReserveSize = (d[20]==8); -+ cksmSetFlags(p, hasCorrectReserveSize); -+ } -+ /* If the write size is appropriate for a database page and if -+ ** checksums where ever enabled, then it will be safe to compute -+ ** the checksums. The reserve byte size might have increased, but -+ ** it will never decrease. And because it cannot decrease, the -+ ** checksum will not overwrite anything. -+ */ -+ if( iAmt==4096 -+ && p->computeCksm -+ && !p->inCkpt -+ ){ -+ cksmCompute((u8*)zBuf, iAmt-8, ((u8*)zBuf)+iAmt-8); -+ } -+ return pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst); -+} -+ -+/* -+** Truncate a cksm-file. -+*/ -+static int cksmTruncate(sqlite3_file *pFile, sqlite_int64 size){ -+ pFile = ORIGFILE(pFile); -+ return pFile->pMethods->xTruncate(pFile, size); -+} -+ -+/* -+** Sync a cksm-file. -+*/ -+static int cksmSync(sqlite3_file *pFile, int flags){ -+ pFile = ORIGFILE(pFile); -+ return pFile->pMethods->xSync(pFile, flags); -+} -+ -+/* -+** Return the current file-size of a cksm-file. -+*/ -+static int cksmFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ -+ CksmFile *p = (CksmFile *)pFile; -+ pFile = ORIGFILE(p); -+ return pFile->pMethods->xFileSize(pFile, pSize); -+} -+ -+/* -+** Lock a cksm-file. -+*/ -+static int cksmLock(sqlite3_file *pFile, int eLock){ -+ pFile = ORIGFILE(pFile); -+ return pFile->pMethods->xLock(pFile, eLock); -+} -+ -+/* -+** Unlock a cksm-file. -+*/ -+static int cksmUnlock(sqlite3_file *pFile, int eLock){ -+ pFile = ORIGFILE(pFile); -+ return pFile->pMethods->xUnlock(pFile, eLock); -+} -+ -+/* -+** Check if another file-handle holds a RESERVED lock on a cksm-file. -+*/ -+static int cksmCheckReservedLock(sqlite3_file *pFile, int *pResOut){ -+ pFile = ORIGFILE(pFile); -+ return pFile->pMethods->xCheckReservedLock(pFile, pResOut); -+} -+ -+/* -+** File control method. For custom operations on a cksm-file. -+*/ -+static int cksmFileControl(sqlite3_file *pFile, int op, void *pArg){ -+ int rc; -+ CksmFile *p = (CksmFile*)pFile; -+ pFile = ORIGFILE(pFile); -+ if( op==SQLITE_FCNTL_PRAGMA ){ -+ char **azArg = (char**)pArg; -+ assert( azArg[1]!=0 ); -+ if( sqlite3_stricmp(azArg[1],"checksum_verification")==0 ){ -+ char *zArg = azArg[2]; -+ if( zArg!=0 ){ -+ if( (zArg[0]>='1' && zArg[0]<='9') -+ || sqlite3_strlike("enable%",zArg,0)==0 -+ || sqlite3_stricmp("yes",zArg)==0 -+ || sqlite3_stricmp("on",zArg)==0 -+ ){ -+ p->verifyCksm = p->computeCksm; -+ }else{ -+ p->verifyCksm = 0; -+ } -+ if( p->pPartner ) p->pPartner->verifyCksm = p->verifyCksm; -+ } -+ azArg[0] = sqlite3_mprintf("%d",p->verifyCksm); -+ return SQLITE_OK; -+ }else if( p->computeCksm && azArg[2]!=0 -+ && sqlite3_stricmp(azArg[1], "page_size")==0 ){ -+ /* Do not allow page size changes on a checksum database */ -+ return SQLITE_OK; -+ } -+ }else if( op==SQLITE_FCNTL_CKPT_START || op==SQLITE_FCNTL_CKPT_DONE ){ -+ p->inCkpt = op==SQLITE_FCNTL_CKPT_START; -+ if( p->pPartner ) p->pPartner->inCkpt = p->inCkpt; -+ }else if( op==SQLITE_FCNTL_CKSM_FILE ){ -+ /* This VFS needs to obtain a pointer to the corresponding database -+ ** file handle from within xOpen() calls to open wal files. To do this, -+ ** it uses the sqlite3_database_file_object() API to obtain a pointer -+ ** to the file-handle used by SQLite to access the db file. This is -+ ** fine if cksmvfs happens to be the top-level VFS, but not if there -+ ** are one or more wrapper VFS. To handle this case, this file-control -+ ** is used to extract the cksmvfs file-handle from any wrapper file -+ ** handle. */ -+ sqlite3_file **ppFile = (sqlite3_file**)pArg; -+ *ppFile = (sqlite3_file*)p; -+ return SQLITE_OK; -+ } -+ rc = pFile->pMethods->xFileControl(pFile, op, pArg); -+ if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){ -+ *(char**)pArg = sqlite3_mprintf("cksm/%z", *(char**)pArg); -+ } -+ return rc; -+} -+ -+/* -+** Return the sector-size in bytes for a cksm-file. -+*/ -+static int cksmSectorSize(sqlite3_file *pFile){ -+ pFile = ORIGFILE(pFile); -+ return pFile->pMethods->xSectorSize(pFile); -+} -+ -+/* -+** Return the device characteristic flags supported by a cksm-file. -+*/ -+static int cksmDeviceCharacteristics(sqlite3_file *pFile){ -+ pFile = ORIGFILE(pFile); -+ return pFile->pMethods->xDeviceCharacteristics(pFile); -+} -+ -+/* Create a shared memory file mapping */ -+static int cksmShmMap( -+ sqlite3_file *pFile, -+ int iPg, -+ int pgsz, -+ int bExtend, -+ void volatile **pp -+){ -+ pFile = ORIGFILE(pFile); -+ return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp); -+} -+ -+/* Perform locking on a shared-memory segment */ -+static int cksmShmLock(sqlite3_file *pFile, int offset, int n, int flags){ -+ pFile = ORIGFILE(pFile); -+ return pFile->pMethods->xShmLock(pFile,offset,n,flags); -+} -+ -+/* Memory barrier operation on shared memory */ -+static void cksmShmBarrier(sqlite3_file *pFile){ -+ pFile = ORIGFILE(pFile); -+ pFile->pMethods->xShmBarrier(pFile); -+} -+ -+/* Unmap a shared memory segment */ -+static int cksmShmUnmap(sqlite3_file *pFile, int deleteFlag){ -+ pFile = ORIGFILE(pFile); -+ return pFile->pMethods->xShmUnmap(pFile,deleteFlag); -+} -+ -+/* Fetch a page of a memory-mapped file */ -+static int cksmFetch( -+ sqlite3_file *pFile, -+ sqlite3_int64 iOfst, -+ int iAmt, -+ void **pp -+){ -+ CksmFile *p = (CksmFile *)pFile; -+ if( p->computeCksm ){ -+ *pp = 0; -+ return SQLITE_OK; -+ } -+ pFile = ORIGFILE(pFile); -+ if( pFile->pMethods->iVersion>2 && pFile->pMethods->xFetch ){ -+ return pFile->pMethods->xFetch(pFile, iOfst, iAmt, pp); -+ } -+ *pp = 0; -+ return SQLITE_OK; -+} -+ -+/* Release a memory-mapped page */ -+static int cksmUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ -+ pFile = ORIGFILE(pFile); -+ if( pFile->pMethods->iVersion>2 && pFile->pMethods->xUnfetch ){ -+ return pFile->pMethods->xUnfetch(pFile, iOfst, pPage); -+ } -+ return SQLITE_OK; -+} -+ -+/* -+** Open a cksm file handle. -+*/ -+static int cksmOpen( -+ sqlite3_vfs *pVfs, -+ const char *zName, -+ sqlite3_file *pFile, -+ int flags, -+ int *pOutFlags -+){ -+ CksmFile *p; -+ sqlite3_file *pSubFile; -+ sqlite3_vfs *pSubVfs; -+ int rc; -+ pSubVfs = ORIGVFS(pVfs); -+ if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){ -+ return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags); -+ } -+ p = (CksmFile*)pFile; -+ memset(p, 0, sizeof(*p)); -+ pSubFile = ORIGFILE(pFile); -+ pFile->pMethods = &cksm_io_methods; -+ rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags); -+ if( rc ) goto cksm_open_done; -+ if( flags & SQLITE_OPEN_WAL ){ -+ sqlite3_file *pDb = sqlite3_database_file_object(zName); -+ rc = pDb->pMethods->xFileControl(pDb, SQLITE_FCNTL_CKSM_FILE, (void*)&pDb); -+ assert( rc==SQLITE_OK ); -+ p->pPartner = (CksmFile*)pDb; -+ assert( p->pPartner->pPartner==0 ); -+ p->pPartner->pPartner = p; -+ p->isWal = 1; -+ p->computeCksm = p->pPartner->computeCksm; -+ }else{ -+ p->isWal = 0; -+ p->computeCksm = 0; -+ } -+ p->zFName = zName; -+cksm_open_done: -+ if( rc ) pFile->pMethods = 0; -+ return rc; -+} -+ -+/* -+** All other VFS methods are pass-thrus. -+*/ -+static int cksmDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ -+ return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync); -+} -+static int cksmAccess( -+ sqlite3_vfs *pVfs, -+ const char *zPath, -+ int flags, -+ int *pResOut -+){ -+ return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut); -+} -+static int cksmFullPathname( -+ sqlite3_vfs *pVfs, -+ const char *zPath, -+ int nOut, -+ char *zOut -+){ -+ return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut); -+} -+static void *cksmDlOpen(sqlite3_vfs *pVfs, const char *zPath){ -+ return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath); -+} -+static void cksmDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ -+ ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg); -+} -+static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ -+ return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym); -+} -+static void cksmDlClose(sqlite3_vfs *pVfs, void *pHandle){ -+ ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle); -+} -+static int cksmRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ -+ return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut); -+} -+static int cksmSleep(sqlite3_vfs *pVfs, int nMicro){ -+ return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro); -+} -+static int cksmCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ -+ return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut); -+} -+static int cksmGetLastError(sqlite3_vfs *pVfs, int a, char *b){ -+ return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b); -+} -+static int cksmCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){ -+ sqlite3_vfs *pOrig = ORIGVFS(pVfs); -+ int rc; -+ assert( pOrig->iVersion>=2 ); -+ if( pOrig->xCurrentTimeInt64 ){ -+ rc = pOrig->xCurrentTimeInt64(pOrig, p); -+ }else{ -+ double r; -+ rc = pOrig->xCurrentTime(pOrig, &r); -+ *p = (sqlite3_int64)(r*86400000.0); -+ } -+ return rc; -+} -+static int cksmSetSystemCall( -+ sqlite3_vfs *pVfs, -+ const char *zName, -+ sqlite3_syscall_ptr pCall -+){ -+ return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall); -+} -+static sqlite3_syscall_ptr cksmGetSystemCall( -+ sqlite3_vfs *pVfs, -+ const char *zName -+){ -+ return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName); -+} -+static const char *cksmNextSystemCall(sqlite3_vfs *pVfs, const char *zName){ -+ return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName); -+} -+ -+/* Register the verify_checksum() SQL function. -+*/ -+static int cksmRegisterFunc( -+ sqlite3 *db, -+ char **pzErrMsg, -+ const sqlite3_api_routines *pApi -+){ -+ int rc; -+ if( db==0 ) return SQLITE_OK; -+ rc = sqlite3_create_function(db, "verify_checksum", 1, -+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, -+ 0, cksmVerifyFunc, 0, 0); -+#ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME -+ (void)sqlite3_create_function(db, SQLITE_CKSUMVFS_INIT_FUNCNAME, 1, -+ SQLITE_UTF8|SQLITE_DIRECTONLY, -+ 0, cksmInitFunc, 0, 0); -+#endif -+ return rc; -+} -+ -+/* -+** Register the cksum VFS as the default VFS for the system. -+** Also make arrangements to automatically register the "verify_checksum()" -+** SQL function on each new database connection. -+*/ -+static int cksmRegisterVfs(void){ -+ int rc = SQLITE_OK; -+ sqlite3_vfs *pOrig; -+ if( sqlite3_vfs_find("cksmvfs")!=0 ) return SQLITE_OK; -+ pOrig = sqlite3_vfs_find(0); -+ if( pOrig==0 ) return SQLITE_ERROR; -+ cksm_vfs.iVersion = pOrig->iVersion; -+ cksm_vfs.pAppData = pOrig; -+ cksm_vfs.szOsFile = pOrig->szOsFile + sizeof(CksmFile); -+ rc = sqlite3_vfs_register(&cksm_vfs, 1); -+ if( rc==SQLITE_OK ){ -+ rc = sqlite3_auto_extension((void(*)(void))cksmRegisterFunc); -+ } -+ return rc; -+} -+ -+#if defined(SQLITE_CKSUMVFS_STATIC) -+/* This variant of the initializer runs when the extension is -+** statically linked. -+*/ -+int sqlite3_register_cksumvfs(const char *NotUsed){ -+ (void)NotUsed; -+ return cksmRegisterVfs(); -+} -+int sqlite3_unregister_cksumvfs(void){ -+ if( sqlite3_vfs_find("cksmvfs") ){ -+ sqlite3_vfs_unregister(&cksm_vfs); -+ sqlite3_cancel_auto_extension((void(*)(void))cksmRegisterFunc); -+ } -+ return SQLITE_OK; -+} -+#endif /* defined(SQLITE_CKSUMVFS_STATIC */ -+ -+#if !defined(SQLITE_CKSUMVFS_STATIC) -+/* This variant of the initializer function is used when the -+** extension is shared library to be loaded at run-time. -+*/ -+#ifdef _WIN32 -+__declspec(dllexport) -+#endif -+/* -+** This routine is called by sqlite3_load_extension() when the -+** extension is first loaded. -+***/ -+int sqlite3_cksumvfs_init( -+ sqlite3 *db, -+ char **pzErrMsg, -+ const sqlite3_api_routines *pApi -+){ -+ int rc; -+ SQLITE_EXTENSION_INIT2(pApi); -+ (void)pzErrMsg; /* not used */ -+ rc = cksmRegisterFunc(db, 0, 0); -+ if( rc==SQLITE_OK ){ -+ rc = cksmRegisterVfs(); -+ } -+ if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; -+ return rc; -+} -+#endif /* !defined(SQLITE_CKSUMVFS_STATIC) */ -+ -+#ifdef SQLITE_CKSUMVFS_STATIC -+struct sqlite3_api_routines_cksumvfs { -+ int (*register_cksumvfs)(const char *); -+ int (*unregister_cksumvfs)(); -+}; -+typedef struct sqlite3_api_routines_cksumvfs sqlite3_api_routines_cksumvfs; -+static const sqlite3_api_routines_cksumvfs sqlite3CksumvfsApis = { -+ sqlite3_register_cksumvfs, -+ sqlite3_unregister_cksumvfs -+}; -+ -+EXPORT_SYMBOLS const sqlite3_api_routines_cksumvfs *sqlite3_export_cksumvfs_symbols = &sqlite3CksumvfsApis; -+#endif -diff --git a/src/sqlite3.c b/src/sqlite3.c -index 0666938..7e9dcbf 100644 ---- a/src/sqlite3.c -+++ b/src/sqlite3.c -@@ -58992,17 +58992,70 @@ static int jrnlBufferSize(Pager *pPager){ - ** and debugging only. - */ - #ifdef SQLITE_CHECK_PAGES --/* --** Return a 32-bit hash of the page data for pPage. --*/ --static u32 pager_datahash(int nByte, unsigned char *pData){ -+#if defined (__arm__) || defined (__aarch64__) -+#include -+u32 deep_fast_hash_arm(void *src, int srcLen){ -+ uint16_t chunkSize = srcLen/4; -+ uint8_t *u8p_src = (uint8_t *)src; -+ uint16x8_t m_prime = vdupq_n_u16(44497); -+ uint16x8_t m_res0 = vdupq_n_u16(0); -+ uint16x8_t m_res1 = vdupq_n_u16(0); -+ uint16x8_t m_res2 = vdupq_n_u16(0); -+ uint16x8_t m_res3 = vdupq_n_u16(0); -+ uint16x8_t m_res4 = vdupq_n_u16(0); -+ uint16x8_t m_res5 = vdupq_n_u16(0); -+ uint16x8_t m_res6 = vdupq_n_u16(0); -+ uint16x8_t m_res7 = vdupq_n_u16(0); -+ -+ for(int i=0; ipPager->pageSize, (unsigned char *)pPage->pData); - } -@@ -59018,8 +59071,15 @@ static void pager_set_pagehash(PgHdr *pPage){ - #define CHECK_PAGE(x) checkPage(x) - static void checkPage(PgHdr *pPg){ - Pager *pPager = pPg->pPager; -- assert( pPager->eState!=PAGER_ERROR ); -- assert( (pPg->flags&PGHDR_DIRTY) || pPg->pageHash==pager_pagehash(pPg) ); -+ if( pPager->eState==PAGER_ERROR ){ -+ return; -+ } -+ if( pPg->flags&PGHDR_DIRTY ) { -+ return; -+ } -+ if( pPg->pgno!=1 && pPg->pageHash!=pager_pagehash(pPg) ){ -+ sqlite3_log(SQLITE_CORRUPT, "cache corruption occurs through checking page(%u)", pPg->pgno); -+ } - } - - #else -@@ -185754,12 +185814,16 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo - *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager); - rc = SQLITE_OK; - }else if( op==SQLITE_FCNTL_RESERVE_BYTES ){ -+#ifndef SQLITE_CKSUMVFS_STATIC -+ rc = SQLITE_OK; -+#else - int iNew = *(int*)pArg; - *(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree); - if( iNew>=0 && iNew<=255 ){ - sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0); - } - rc = SQLITE_OK; -+#endif - }else if( op==SQLITE_FCNTL_RESET_CACHE ){ - sqlite3BtreeClearCache(pBtree); - rc = SQLITE_OK; -@@ -261521,6 +261585,27 @@ static void DumpLocksByPager(Pager *pPager) - - // hw export the symbols - #ifdef SQLITE_EXPORT_SYMBOLS -+#ifndef SQLITE_CKSUMVFS_STATIC -+int sqlite3_register_cksumvfs(const char *NotUsed){ -+ return SQLITE_MISUSE; -+} -+int sqlite3_unregister_cksumvfs(void){ -+ return SQLITE_MISUSE; -+} -+ -+struct sqlite3_api_routines_cksumvfs { -+ int (*register_cksumvfs)(const char *); -+ int (*unregister_cksumvfs)(); -+}; -+typedef struct sqlite3_api_routines_cksumvfs sqlite3_api_routines_cksumvfs; -+static const sqlite3_api_routines_cksumvfs sqlite3CksumvfsApis = { -+ sqlite3_register_cksumvfs, -+ sqlite3_unregister_cksumvfs -+}; -+ -+EXPORT_SYMBOLS const sqlite3_api_routines_cksumvfs *sqlite3_export_cksumvfs_symbols = &sqlite3CksumvfsApis; -+#endif -+ - struct sqlite3_api_routines_hw { - int (*initialize)(); - int (*config)(int,...); --- -2.47.0.windows.2 - diff --git a/patch/0007-BugFix-CurrVersion.patch b/patch/0007-BugFix-CurrVersion.patch deleted file mode 100644 index 021cc4b..0000000 --- a/patch/0007-BugFix-CurrVersion.patch +++ /dev/null @@ -1,301 +0,0 @@ -From d080b85d1c44549f5cbc2bd7c55198af193a955a Mon Sep 17 00:00:00 2001 -From: ryne3366 -Date: Tue, 1 Apr 2025 15:42:23 +0800 -Subject: [PATCH] Fix misreport db corruption - ---- - src/sqlite3.c | 149 ++++++++++++++++++++++++++++++++++++-------------- - 1 file changed, 109 insertions(+), 40 deletions(-) - -diff --git a/src/sqlite3.c b/src/sqlite3.c -index 7e9dcbf..2e8a676 100644 ---- a/src/sqlite3.c -+++ b/src/sqlite3.c -@@ -45151,7 +45151,7 @@ static int unixOpen( - flags |= SQLITE_OPEN_READONLY; - openFlags |= O_RDONLY; - isReadonly = 1; -- sqlite3_log(SQLITE_WARNING, "Try open file readonly"); -+ sqlite3_log(SQLITE_WARNING, "Try open file readonly sysno %d", errno); - pReadonly = findReusableFd(zName, flags); - if( pReadonly ){ - fd = pReadonly->fd; -@@ -70082,6 +70082,7 @@ SQLITE_PRIVATE int sqlite3WalFrames( - ** If parameter xBusy is not NULL, it is a pointer to a busy-handler - ** callback. In this case this function runs a blocking checkpoint. - */ -+static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime); - SQLITE_PRIVATE int sqlite3WalCheckpoint( - Wal *pWal, /* Wal connection */ - sqlite3 *db, /* Check this handle's interrupt flag */ -@@ -70177,7 +70178,12 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( - -1, 0, zMsg, NULL); - rc = SQLITE_CORRUPT_REPORT(&context); - }else{ -- rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags,zBuf); -+ sqlite3_int64 startTime; -+ sqlite3OsCurrentTimeInt64(db->pVfs, &startTime); -+ rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf); -+ if (rc == SQLITE_OK){ -+ walLogCheckpointInfo(pWal, db, startTime); -+ } - } - - /* If no error occurred, set the output variables. */ -@@ -83906,12 +83912,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ - } - } - } -- #ifdef SQLITE_META_DWR -- if (rc == SQLITE_OK && p->pDest->pBt->pPager->metaFd) { -- p->pDest->pBt->pPager->metaChanged = META_SCHEMA_CHANGED; -- (void)MetaDwrUpdateMetaPages(p->pDest); -- } -- #endif -+ - if( rc==SQLITE_OK ){ - rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1); - } -@@ -83942,15 +83943,14 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ - } - }else{ - sqlite3PagerTruncateImage(pDestPager, nDestTruncate); -- #ifdef SQLITE_META_DWR -- if (rc == SQLITE_OK && p->pDest->pBt->pPager->metaFd) { -- p->pDest->pBt->pPager->metaChanged = META_SCHEMA_CHANGED; -- (void)MetaDwrUpdateMetaPages(p->pDest); -- } -- #endif - rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0); - } -- -+#ifdef SQLITE_META_DWR -+ if (rc == SQLITE_OK && p->pDest->pBt->pPager->metaFd) { -+ p->pDest->pBt->pPager->metaChanged = META_SCHEMA_CHANGED; -+ (void)MetaDwrUpdateMetaPages(p->pDest); -+ } -+#endif - /* Finish committing the transaction to the destination database. */ - if( SQLITE_OK==rc - && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0)) -@@ -205751,6 +205751,39 @@ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){ - return rc; - } - -+/* -+** Expression node pExpr is an MSR phrase. This function restarts pExpr -+** so that it is a regular phrase query, not an MSR. SQLITE_OK is returned -+** if successful, or an SQLite error code otherwise. -+*/ -+int sqlite3Fts3MsrCancel(Fts3Cursor *pCsr, Fts3Expr *pExpr){ -+ int rc = SQLITE_OK; -+ if( pExpr->bEof==0 ){ -+ i64 iDocid = pExpr->iDocid; -+ fts3EvalRestart(pCsr, pExpr, &rc); -+ while( rc==SQLITE_OK && pExpr->iDocid!=iDocid ){ -+ fts3EvalNextRow(pCsr, pExpr, &rc); -+ if( pExpr->bEof ) rc = FTS_CORRUPT_VTAB; -+ } -+ } -+ return rc; -+} -+ -+/* -+** If expression pExpr is a phrase expression that uses an MSR query, -+** restart it as a regular, non-incremental query. Return SQLITE_OK -+** if successful, or an SQLite error code otherwise. -+*/ -+static int fts3ExprRestartIfCb(Fts3Expr *pExpr, int iPhrase, void *ctx){ -+ TermOffsetCtx *p = (TermOffsetCtx*)ctx; -+ int rc = SQLITE_OK; -+ if( pExpr->pPhrase && pExpr->pPhrase->bIncr ){ -+ rc = sqlite3Fts3MsrCancel(p->pCsr, pExpr); -+ pExpr->pPhrase->bIncr = 0; -+ } -+ return rc; -+} -+ - /* - ** Implementation of offsets() function. - */ -@@ -205787,6 +205820,12 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets( - sCtx.iDocid = pCsr->iPrevId; - sCtx.pCsr = pCsr; - -+ /* If a query restart will be required, do it here, rather than later of -+ ** after pointers to poslist buffers that may be invalidated by a restart -+ ** have been saved. */ -+ rc = sqlite3Fts3ExprIterate(pCsr->pExpr, fts3ExprRestartIfCb, (void*)&sCtx); -+ if( rc!=SQLITE_OK ) goto offsets_out; -+ - /* Loop through the table columns, appending offset information to - ** string-buffer res for each column. - */ -@@ -260390,7 +260429,7 @@ static int PragmaMetaDoubleWrie(sqlite3 *db, int iDb, Parse *parse, const char * - sqlite3_mutex_enter(db->mutex); - // only support enabled meta double write - int rc = MetaDwrOpenAndCheck(pBt); -- if (rc != SQLITE_OK) { -+ if (rc != SQLITE_OK && rc != SQLITE_PERM) { - parse->nErr++; - parse->rc = rc; - } -@@ -260453,11 +260492,13 @@ static SQLITE_NOINLINE int ScanOverflowPages( - nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1) / ovflPageSize; - assert(nOvfl > 0 || - (CORRUPT_DB && (pInfo->nPayload + ovflPageSize) < ovflPageSize)); -- while (nOvfl--) { -+ while (nOvfl > 0 && nOvfl--) { - Pgno iNext = 0; - MemPage *pOvfl = 0; - if (ovflPgno < 2 || ovflPgno > btreePagecount(pBt)) { -- return SQLITE_CORRUPT_BKPT; -+ sqlite3_log(SQLITE_WARNING_DUMP, "Ignore for ovfl page not as expect, pgno %u ovflPgno %u novfl %d payload %u local %u", -+ pPage->pgno, ovflPgno, nOvfl, pInfo->nPayload, pInfo->nLocal); -+ return SQLITE_MISUSE; - } - rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext); - if (rc) -@@ -260508,7 +260549,7 @@ static int ScanBtreePage( - } - } - pPage->xParseCell(pPage, pCell, &info); -- if (info.nLocal != info.nPayload) { -+ if (info.nLocal < info.nPayload) { - rc = ScanOverflowPages(pPage, pCell, &info, fn, args); - if (rc) { - goto SCAN_PAGE_OUT; -@@ -260833,6 +260874,7 @@ static int MetaDwrRestoreAllPages(Btree *pBt, const ScanPages *metaPages, MetaDw - return rc; - } - } -+ hdr->pageCnt = metaPages->pageCnt; - MetaDwrUpdateHeaderDbInfo(pBt->pBt); - return rc; - } -@@ -260842,6 +260884,29 @@ static inline const char *GetMetaFilePath(Pager *pPager) - return pPager->metaFd == NULL ? NULL : ((const char *)pPager->metaFd + ROUND8(pPager->pVfs->szOsFile)); - } - -+static int MetaDwrCheckPerm(sqlite3_vfs *pVfs, u8 openCreate, char *metaPath) { -+ int exists = 0; -+ int rc = sqlite3OsAccess(pVfs, metaPath, SQLITE_ACCESS_EXISTS, &exists); -+ if (rc != SQLITE_OK) { -+ return rc; -+ } -+ if (!exists && !openCreate) { -+ return SQLITE_PERM; -+ } -+#ifdef HARMONY_OS -+ // check if the path have enough permission -+ rc = osAccess(metaPath, W_OK|R_OK); -+ if (rc == 0 || errno == ENOENT) { -+ return SQLITE_OK; -+ } -+ rc = SQLITE_PERM; -+ if (openCreate) { -+ sqlite3_log(SQLITE_WARNING_DUMP, "Meta double write disabled, sysno %d", errno); -+ } -+#endif -+ return rc; -+} -+ - static int MetaDwrOpenFile(Pager *pPager, u8 openCreate) { - if (pPager->metaFd || pPager->zFilename == NULL) { - return SQLITE_OK; -@@ -260858,15 +260923,10 @@ static int MetaDwrOpenFile(Pager *pPager, u8 openCreate) { - return SQLITE_NOMEM_BKPT; - } - sqlite3_snprintf(size, metaPath, "%s-dwr", pPager->zFilename); -- int exists = 0; -- int rc = sqlite3OsAccess(pVfs, metaPath, SQLITE_ACCESS_EXISTS, &exists); -+ int rc = MetaDwrCheckPerm(pVfs, openCreate, metaPath); - if (rc != SQLITE_OK) { - goto INIT_META_OUT; - } -- if (!exists && !openCreate) { -- sqlite3_free(metaFd); -- goto INIT_META_OUT; -- } - u32 flags = (SQLITE_OPEN_READWRITE | SQLITE_OPEN_SUPER_JOURNAL); - if (openCreate) { - flags |= SQLITE_OPEN_CREATE; -@@ -261425,16 +261485,6 @@ static inline void MarkLockStatusByRc(int rc, u32 lockIdx, u32 lockLen, u8 lockT - } - } - --static inline const char *TrxLockName(int eLock) --{ -- return eLock == NO_LOCK ? "NO_LOCK" : -- eLock == RESERVED_LOCK ? "RESERVED" : -- eLock == EXCLUSIVE_LOCK ? "EXCLUSIVE" : -- eLock == SHARED_LOCK ? "SHARED" : -- eLock == PENDING_LOCK ? "PENDING": -- eLock == UNKNOWN_LOCK ? "UNKNOWN" : "UNKNOWN_LOCK"; --} -- - static inline const char *IdxToLockName(u32 idx) - { - const char *lockName[MAX_LOCK_NUM] = {"write", "ckpt", "recover", "read0", -@@ -261451,7 +261501,7 @@ static void DumpHandleLock(char *dumpBuf, int dumpBufLen) - for (int i = 0; i < MAX_LOCK_NUM && availLen > DUMP_MAX_STR_LEN; i++) { - if (lockStatus[i] != NO_LOCK) { - tmp[0] = '\0'; -- sqlite3_snprintf(availLen, tmp, "<%s, %s>", IdxToLockName((u32)i), TrxLockName(lockStatus[i])); -+ sqlite3_snprintf(availLen, tmp, "<%s, %d>", IdxToLockName((u32)i), lockStatus[i]); - int len = strlen(tmp); - tmp += len; - availLen -= len; -@@ -261490,8 +261540,8 @@ static void DumpTrxProcessLocks(unixFile *file, char *dumpBuf, int dumpBufLen) - sqlite3_log(SQLITE_ERROR, "[SQLite]Inode is null!"); - return; - } -- sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]acqLock:%s, dbRef:%d, lockCnt:%d, curLock:%s, processLock:%d", -- TrxLockName(file->eFileLock), inode->nRef, inode->nLock, TrxLockName(inode->eFileLock), inode->bProcessLock); -+ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]acqLock:%d, dbRef:%d, lockCnt:%d, curLock:%d, processLock:%d", -+ file->eFileLock, inode->nRef, inode->nLock, inode->eFileLock, inode->bProcessLock); - const char *lockName[DB_LOCK_NUM] = {"pending", "reserved", "shared_first"}; - char *tmp = dumpBuf; - int availLen = dumpBufLen - 1; -@@ -261511,10 +261561,13 @@ static void DumpTrxProcessLocks(unixFile *file, char *dumpBuf, int dumpBufLen) - - static void DumpWalLocks(unixFile *file, u8 walEnabled, char *dumpBuf, int dumpBufLen) - { -- if (!walEnabled || file->pShm == NULL || file->pShm->pShmNode == NULL) { -- sqlite3_log(SQLITE_ERROR, "[SQLite]Wal mode disabled!"); -+ if (file->pShm == NULL || file->pShm->pShmNode == NULL) { -+ sqlite3_log(SQLITE_ERROR, "[SQLite]Wal mode disabled! pShm or pShmNode is NULL"); - return; - } -+ if (!walEnabled) { -+ sqlite3_log(SQLITE_ERROR, "[SQLite] walEnabled false"); -+ } - unixShmNode *pShmNode = file->pShm->pShmNode; - char *tmp = dumpBuf; - int availLen = dumpBufLen - 1; -@@ -261583,6 +261636,22 @@ static void DumpLocksByPager(Pager *pPager) - } - #endif /* SQLITE_OS_UNIX */ - -+static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime) { -+ sqlite3_int64 endTime; -+ sqlite3OsCurrentTimeInt64(db->pVfs, &endTime); -+ sqlite3_int64 timeUse = endTime - startTime; -+ static sqlite3_int64 lastDumpTime = 0; -+ static sqlite3_int64 ckptCnt = 0; -+ /* Only when timeUse > 1500ms or wal size > 50MB, default pageSize 4K, 50*1024/4 = 12800 */ -+ if (timeUse > 1500 || (pWal->hdr.mxFrame > 12800 && (lastDumpTime - endTime) > 2000)) { -+ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]Wal try ckpt count %d use time: %lld(ms), wal frame: %u", -+ ckptCnt, timeUse, pWal->hdr.mxFrame); -+ lastDumpTime = endTime; -+ ckptCnt = 0; -+ } -+ ckptCnt++; -+} -+ - // hw export the symbols - #ifdef SQLITE_EXPORT_SYMBOLS - #ifndef SQLITE_CKSUMVFS_STATIC --- -2.34.1 - diff --git a/src/shell.c b/src/shell.c index b08671e..a951b27 100644 --- a/src/shell.c +++ b/src/shell.c @@ -39,7 +39,7 @@ typedef unsigned short int u16; /* ** Optionally #include a user-defined header, whereby compilation options -** may be set prior to where they take effect, but after platform setup. +** may be set prior to where they take effect, but after platform setup. ** If SQLITE_CUSTOM_INCLUDE=? is defined, its value names the #include ** file. Note that this macro has a like effect on sqlite3.c compilation. */ @@ -117,7 +117,6 @@ typedef unsigned short int u16; #include #include #include -#include #include "sqlite3.h" typedef sqlite3_int64 i64; typedef sqlite3_uint64 u64; @@ -130,7 +129,7 @@ typedef unsigned char u8; #if !defined(_WIN32) && !defined(WIN32) # include -# if !defined(__RTP__) && !defined(_WRS_KERNEL) && !defined(SQLITE_WASI) +# if !defined(__RTP__) && !defined(_WRS_KERNEL) # include # endif #endif @@ -185,14 +184,6 @@ typedef unsigned char u8; # define SHELL_USE_LOCAL_GETLINE 1 #endif -#ifndef deliberate_fall_through -/* Quiet some compilers about some of our intentional code. */ -# if defined(GCC_VERSION) && GCC_VERSION>=7000000 -# define deliberate_fall_through __attribute__((fallthrough)); -# else -# define deliberate_fall_through -# endif -#endif #if defined(_WIN32) || defined(WIN32) # if SQLITE_OS_WINRT @@ -219,7 +210,7 @@ typedef unsigned char u8; /* Make sure isatty() has a prototype. */ extern int isatty(int); -# if !defined(__RTP__) && !defined(_WRS_KERNEL) && !defined(SQLITE_WASI) +# if !defined(__RTP__) && !defined(_WRS_KERNEL) /* popen and pclose are not C89 functions and so are ** sometimes omitted from the header */ extern FILE *popen(const char*,const char*); @@ -246,1942 +237,1185 @@ typedef unsigned char u8; #if SQLITE_OS_WINRT #include #endif -#undef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN #include /* string conversion routines only needed on Win32 */ extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR); +extern char *sqlite3_win32_mbcs_to_utf8_v2(const char *, int); +extern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int); extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText); #endif -/* Use console I/O package as a direct INCLUDE. */ -#define SQLITE_INTERNAL_LINKAGE static - -#ifdef SQLITE_SHELL_FIDDLE -/* Deselect most features from the console I/O package for Fiddle. */ -# define SQLITE_CIO_NO_REDIRECT -# define SQLITE_CIO_NO_CLASSIFY -# define SQLITE_CIO_NO_TRANSLATE -# define SQLITE_CIO_NO_SETMODE -#endif -/************************* Begin ../ext/consio/console_io.h ******************/ -/* -** 2023 November 1 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -******************************************************************************** -** This file exposes various interfaces used for console and other I/O -** by the SQLite project command-line tools. These interfaces are used -** at either source conglomeration time, compilation time, or run time. -** This source provides for either inclusion into conglomerated, -** "single-source" forms or separate compilation then linking. -** -** Platform dependencies are "hidden" here by various stratagems so -** that, provided certain conditions are met, the programs using this -** source or object code compiled from it need no explicit conditional -** compilation in their source for their console and stream I/O. -** -** The symbols and functionality exposed here are not a public API. -** This code may change in tandem with other project code as needed. -** -** When this .h file and its companion .c are directly incorporated into -** a source conglomeration (such as shell.c), the preprocessor symbol -** CIO_WIN_WC_XLATE is defined as 0 or 1, reflecting whether console I/O -** translation for Windows is effected for the build. -*/ -#define HAVE_CONSOLE_IO_H 1 -#ifndef SQLITE_INTERNAL_LINKAGE -# define SQLITE_INTERNAL_LINKAGE extern /* external to translation unit */ -# include +/* On Windows, we normally run with output mode of TEXT so that \n characters +** are automatically translated into \r\n. However, this behavior needs +** to be disabled in some cases (ex: when generating CSV output and when +** rendering quoted strings that contain \n characters). The following +** routines take care of that. +*/ +#if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT +static void setBinaryMode(FILE *file, int isOutput){ + if( isOutput ) fflush(file); + _setmode(_fileno(file), _O_BINARY); +} +static void setTextMode(FILE *file, int isOutput){ + if( isOutput ) fflush(file); + _setmode(_fileno(file), _O_TEXT); +} #else -# define SHELL_NO_SYSINC /* Better yet, modify mkshellc.tcl for this. */ +# define setBinaryMode(X,Y) +# define setTextMode(X,Y) #endif -#ifndef SQLITE3_H -/* # include "sqlite3.h" */ +/* True if the timer is enabled */ +static int enableTimer = 0; + +/* A version of strcmp() that works with NULL values */ +static int cli_strcmp(const char *a, const char *b){ + if( a==0 ) a = ""; + if( b==0 ) b = ""; + return strcmp(a,b); +} +static int cli_strncmp(const char *a, const char *b, size_t n){ + if( a==0 ) a = ""; + if( b==0 ) b = ""; + return strncmp(a,b,n); +} + +/* Return the current wall-clock time */ +static sqlite3_int64 timeOfDay(void){ + static sqlite3_vfs *clockVfs = 0; + sqlite3_int64 t; + if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); + if( clockVfs==0 ) return 0; /* Never actually happens */ + if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){ + clockVfs->xCurrentTimeInt64(clockVfs, &t); + }else{ + double r; + clockVfs->xCurrentTime(clockVfs, &r); + t = (sqlite3_int64)(r*86400000.0); + } + return t; +} + +#if !defined(_WIN32) && !defined(WIN32) && !defined(__minux) +#include +#include + +/* VxWorks does not support getrusage() as far as we can determine */ +#if defined(_WRS_KERNEL) || defined(__RTP__) +struct rusage { + struct timeval ru_utime; /* user CPU time used */ + struct timeval ru_stime; /* system CPU time used */ +}; +#define getrusage(A,B) memset(B,0,sizeof(*B)) #endif -#ifndef SQLITE_CIO_NO_CLASSIFY +/* Saved resource information for the beginning of an operation */ +static struct rusage sBegin; /* CPU time at start */ +static sqlite3_int64 iBegin; /* Wall-clock time at start */ + +/* +** Begin timing an operation +*/ +static void beginTimer(void){ + if( enableTimer ){ + getrusage(RUSAGE_SELF, &sBegin); + iBegin = timeOfDay(); + } +} -/* Define enum for use with following function. */ -typedef enum StreamsAreConsole { - SAC_NoConsole = 0, - SAC_InConsole = 1, SAC_OutConsole = 2, SAC_ErrConsole = 4, - SAC_AnyConsole = 0x7 -} StreamsAreConsole; +/* Return the difference of two time_structs in seconds */ +static double timeDiff(struct timeval *pStart, struct timeval *pEnd){ + return (pEnd->tv_usec - pStart->tv_usec)*0.000001 + + (double)(pEnd->tv_sec - pStart->tv_sec); +} /* -** Classify the three standard I/O streams according to whether -** they are connected to a console attached to the process. -** -** Returns the bit-wise OR of SAC_{In,Out,Err}Console values, -** or SAC_NoConsole if none of the streams reaches a console. -** -** This function should be called before any I/O is done with -** the given streams. As a side-effect, the given inputs are -** recorded so that later I/O operations on them may be done -** differently than the C library FILE* I/O would be done, -** iff the stream is used for the I/O functions that follow, -** and to support the ones that use an implicit stream. -** -** On some platforms, stream or console mode alteration (aka -** "Setup") may be made which is undone by consoleRestore(). +** Print the timing results. */ -SQLITE_INTERNAL_LINKAGE StreamsAreConsole -consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ); -/* A usual call for convenience: */ -#define SQLITE_STD_CONSOLE_INIT() consoleClassifySetup(stdin,stdout,stderr) +static void endTimer(void){ + if( enableTimer ){ + sqlite3_int64 iEnd = timeOfDay(); + struct rusage sEnd; + getrusage(RUSAGE_SELF, &sEnd); + printf("Run Time: real %.3f user %f sys %f\n", + (iEnd - iBegin)*0.001, + timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), + timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); + } +} + +#define BEGIN_TIMER beginTimer() +#define END_TIMER endTimer() +#define HAS_TIMER 1 + +#elif (defined(_WIN32) || defined(WIN32)) + +/* Saved resource information for the beginning of an operation */ +static HANDLE hProcess; +static FILETIME ftKernelBegin; +static FILETIME ftUserBegin; +static sqlite3_int64 ftWallBegin; +typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, + LPFILETIME, LPFILETIME); +static GETPROCTIMES getProcessTimesAddr = NULL; /* -** After an initial call to consoleClassifySetup(...), renew -** the same setup it effected. (A call not after is an error.) -** This will restore state altered by consoleRestore(); -** -** Applications which run an inferior (child) process which -** inherits the same I/O streams may call this function after -** such a process exits to guard against console mode changes. +** Check to see if we have timer support. Return 1 if necessary +** support found (or found previously). */ -SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void); +static int hasTimer(void){ + if( getProcessTimesAddr ){ + return 1; + } else { +#if !SQLITE_OS_WINRT + /* GetProcessTimes() isn't supported in WIN95 and some other Windows + ** versions. See if the version we are running on has it, and if it + ** does, save off a pointer to it and the current process handle. + */ + hProcess = GetCurrentProcess(); + if( hProcess ){ + HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll")); + if( NULL != hinstLib ){ + getProcessTimesAddr = + (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes"); + if( NULL != getProcessTimesAddr ){ + return 1; + } + FreeLibrary(hinstLib); + } + } +#endif + } + return 0; +} /* -** Undo any side-effects left by consoleClassifySetup(...). -** -** This should be called after consoleClassifySetup() and -** before the process terminates normally. It is suitable -** for use with the atexit() C library procedure. After -** this call, no console I/O should be done until one of -** console{Classify or Renew}Setup(...) is called again. -** -** Applications which run an inferior (child) process that -** inherits the same I/O streams might call this procedure -** before so that said process will have a console setup -** however users have configured it or come to expect. +** Begin timing an operation */ -SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void ); +static void beginTimer(void){ + if( enableTimer && getProcessTimesAddr ){ + FILETIME ftCreation, ftExit; + getProcessTimesAddr(hProcess,&ftCreation,&ftExit, + &ftKernelBegin,&ftUserBegin); + ftWallBegin = timeOfDay(); + } +} -#else /* defined(SQLITE_CIO_NO_CLASSIFY) */ -# define consoleClassifySetup(i,o,e) -# define consoleRenewSetup() -# define consoleRestore() -#endif /* defined(SQLITE_CIO_NO_CLASSIFY) */ +/* Return the difference of two FILETIME structs in seconds */ +static double timeDiff(FILETIME *pStart, FILETIME *pEnd){ + sqlite_int64 i64Start = *((sqlite_int64 *) pStart); + sqlite_int64 i64End = *((sqlite_int64 *) pEnd); + return (double) ((i64End - i64Start) / 10000000.0); +} -#ifndef SQLITE_CIO_NO_REDIRECT /* -** Set stream to be used for the functions below which write -** to "the designated X stream", where X is Output or Error. -** Returns the previous value. -** -** Alternatively, pass the special value, invalidFileStream, -** to get the designated stream value without setting it. -** -** Before the designated streams are set, they default to -** those passed to consoleClassifySetup(...), and before -** that is called they default to stdout and stderr. -** -** It is error to close a stream so designated, then, without -** designating another, use the corresponding {o,e}Emit(...). +** Print the timing results. */ -SQLITE_INTERNAL_LINKAGE FILE *invalidFileStream; -SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf); -# ifdef CONSIO_SET_ERROR_STREAM -SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf); -# endif +static void endTimer(void){ + if( enableTimer && getProcessTimesAddr){ + FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd; + sqlite3_int64 ftWallEnd = timeOfDay(); + getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd); + printf("Run Time: real %.3f user %f sys %f\n", + (ftWallEnd - ftWallBegin)*0.001, + timeDiff(&ftUserBegin, &ftUserEnd), + timeDiff(&ftKernelBegin, &ftKernelEnd)); + } +} + +#define BEGIN_TIMER beginTimer() +#define END_TIMER endTimer() +#define HAS_TIMER hasTimer() + #else -# define setOutputStream(pf) -# define setErrorStream(pf) -#endif /* !defined(SQLITE_CIO_NO_REDIRECT) */ +#define BEGIN_TIMER +#define END_TIMER +#define HAS_TIMER 0 +#endif -#ifndef SQLITE_CIO_NO_TRANSLATE /* -** Emit output like fprintf(). If the output is going to the -** console and translation from UTF-8 is necessary, perform -** the needed translation. Otherwise, write formatted output -** to the provided stream almost as-is, possibly with newline -** translation as specified by set{Binary,Text}Mode(). +** Used to prevent warnings about unused parameters */ -SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...); -/* Like fPrintfUtf8 except stream is always the designated output. */ -SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...); -/* Like fPrintfUtf8 except stream is always the designated error. */ -SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...); +#define UNUSED_PARAMETER(x) (void)(x) /* -** Emit output like fputs(). If the output is going to the -** console and translation from UTF-8 is necessary, perform -** the needed translation. Otherwise, write given text to the -** provided stream almost as-is, possibly with newline -** translation as specified by set{Binary,Text}Mode(). +** Number of elements in an array */ -SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO); -/* Like fPutsUtf8 except stream is always the designated output. */ -SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z); -/* Like fPutsUtf8 except stream is always the designated error. */ -SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z); +#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0])) /* -** Emit output like fPutsUtf8(), except that the length of the -** accepted char or character sequence is limited by nAccept. -** -** Returns the number of accepted char values. +** If the following flag is set, then command execution stops +** at an error if we are not interactive. */ -#ifdef CONSIO_SPUTB -SQLITE_INTERNAL_LINKAGE int -fPutbUtf8(FILE *pfOut, const char *cBuf, int nAccept); -/* Like fPutbUtf8 except stream is always the designated output. */ -#endif -SQLITE_INTERNAL_LINKAGE int -oPutbUtf8(const char *cBuf, int nAccept); -/* Like fPutbUtf8 except stream is always the designated error. */ -#ifdef CONSIO_EPUTB -SQLITE_INTERNAL_LINKAGE int -ePutbUtf8(const char *cBuf, int nAccept); -#endif +static int bail_on_error = 0; /* -** Collect input like fgets(...) with special provisions for input -** from the console on platforms that require same. Defers to the -** C library fgets() when input is not from the console. Newline -** translation may be done as set by set{Binary,Text}Mode(). As a -** convenience, pfIn==NULL is treated as stdin. +** Threat stdin as an interactive input if the following variable +** is true. Otherwise, assume stdin is connected to a file or pipe. */ -SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn); -/* Like fGetsUtf8 except stream is always the designated input. */ -/* SQLITE_INTERNAL_LINKAGE char* iGetsUtf8(char *cBuf, int ncMax); */ - -#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */ +static int stdin_is_interactive = 1; -#ifndef SQLITE_CIO_NO_SETMODE /* -** Set given stream for binary mode, where newline translation is -** not done, or for text mode where, for some platforms, newlines -** are translated to the platform's conventional char sequence. -** If bFlush true, flush the stream. -** -** An additional side-effect is that if the stream is one passed -** to consoleClassifySetup() as an output, it is flushed first. -** -** Note that binary/text mode has no effect on console I/O -** translation. On all platforms, newline to the console starts -** a new line and CR,LF chars from the console become a newline. +** On Windows systems we have to know if standard output is a console +** in order to translate UTF-8 into MBCS. The following variable is +** true if translation is required. */ -SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *, short bFlush); -SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *, short bFlush); -#endif - -#ifdef SQLITE_CIO_PROMPTED_IN -typedef struct Prompts { - int numPrompts; - const char **azPrompts; -} Prompts; +static int stdout_is_console = 1; /* -** Macros for use of a line editor. -** -** The following macros define operations involving use of a -** line-editing library or simple console interaction. -** A "T" argument is a text (char *) buffer or filename. -** A "N" argument is an integer. -** -** SHELL_ADD_HISTORY(T) // Record text as line(s) of history. -** SHELL_READ_HISTORY(T) // Read history from file named by T. -** SHELL_WRITE_HISTORY(T) // Write history to file named by T. -** SHELL_STIFLE_HISTORY(N) // Limit history to N entries. -** -** A console program which does interactive console input is -** expected to call: -** SHELL_READ_HISTORY(T) before collecting such input; -** SHELL_ADD_HISTORY(T) as record-worthy input is taken; -** SHELL_STIFLE_HISTORY(N) after console input ceases; then -** SHELL_WRITE_HISTORY(T) before the program exits. +** The following is the open SQLite database. We make a pointer +** to this database a static variable so that it can be accessed +** by the SIGINT handler to interrupt database processing. */ +static sqlite3 *globalDb = 0; /* -** Retrieve a single line of input text from an input stream. -** -** If pfIn is the input stream passed to consoleClassifySetup(), -** and azPrompt is not NULL, then a prompt is issued before the -** line is collected, as selected by the isContinuation flag. -** Array azPrompt[{0,1}] holds the {main,continuation} prompt. -** -** If zBufPrior is not NULL then it is a buffer from a prior -** call to this routine that can be reused, or will be freed. -** -** The result is stored in space obtained from malloc() and -** must either be freed by the caller or else passed back to -** this function as zBufPrior for reuse. -** -** This function may call upon services of a line-editing -** library to interactively collect line edited input. +** True if an interrupt (Control-C) has been received. */ -SQLITE_INTERNAL_LINKAGE char * -shellGetLine(FILE *pfIn, char *zBufPrior, int nLen, - short isContinuation, Prompts azPrompt); -#endif /* defined(SQLITE_CIO_PROMPTED_IN) */ +static volatile int seenInterrupt = 0; + /* -** TBD: Define an interface for application(s) to generate -** completion candidates for use by the line-editor. -** -** This may be premature; the CLI is the only application -** that does this. Yet, getting line-editing melded into -** console I/O is desirable because a line-editing library -** may have to establish console operating mode, possibly -** in a way that interferes with the above functionality. +** This is the name of our program. It is set in main(), used +** in a number of other places, mostly for error messages. */ +static char *Argv0; -#if !(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE)) -/* Skip over as much z[] input char sequence as is valid UTF-8, -** limited per nAccept char's or whole characters and containing -** no char cn such that ((1<=0 => char count, nAccept<0 => character - */ -SQLITE_INTERNAL_LINKAGE const char* -zSkipValidUtf8(const char *z, int nAccept, long ccm); - -#endif - -/************************* End ../ext/consio/console_io.h ********************/ -/************************* Begin ../ext/consio/console_io.c ******************/ /* -** 2023 November 4 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -******************************************************************************** -** This file implements various interfaces used for console and stream I/O -** by the SQLite project command-line tools, as explained in console_io.h . -** Functions prefixed by "SQLITE_INTERNAL_LINKAGE" behave as described there. +** Prompt strings. Initialized in main. Settable with +** .prompt main continue */ +static char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/ +static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */ -#ifndef SQLITE_CDECL -# define SQLITE_CDECL +/* +** Render output like fprintf(). Except, if the output is going to the +** console and if this is running on a Windows machine, translate the +** output from UTF-8 into MBCS. +*/ +#if defined(_WIN32) || defined(WIN32) +void utf8_printf(FILE *out, const char *zFormat, ...){ + va_list ap; + va_start(ap, zFormat); + if( stdout_is_console && (out==stdout || out==stderr) ){ + char *z1 = sqlite3_vmprintf(zFormat, ap); + char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0); + sqlite3_free(z1); + fputs(z2, out); + sqlite3_free(z2); + }else{ + vfprintf(out, zFormat, ap); + } + va_end(ap); +} +#elif !defined(utf8_printf) +# define utf8_printf fprintf #endif -#ifndef SHELL_NO_SYSINC -# include -# include -# include -# include -# include -/* # include "sqlite3.h" */ -#endif -#ifndef HAVE_CONSOLE_IO_H -# include "console_io.h" -#endif -#if defined(_MSC_VER) -# pragma warning(disable : 4204) +/* +** Render output like fprintf(). This should not be used on anything that +** includes string formatting (e.g. "%s"). +*/ +#if !defined(raw_printf) +# define raw_printf fprintf #endif -#ifndef SQLITE_CIO_NO_TRANSLATE -# if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT -# ifndef SHELL_NO_SYSINC -# include -# include -# undef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# include -# endif -# define CIO_WIN_WC_XLATE 1 /* Use WCHAR Windows APIs for console I/O */ -# else -# ifndef SHELL_NO_SYSINC -# include -# endif -# define CIO_WIN_WC_XLATE 0 /* Use plain C library stream I/O at console */ -# endif -#else -# define CIO_WIN_WC_XLATE 0 /* Not exposing translation routines at all */ -#endif +/* Indicate out-of-memory and exit. */ +static void shell_out_of_memory(void){ + raw_printf(stderr,"Error: out of memory\n"); + exit(1); +} -#if CIO_WIN_WC_XLATE -static HANDLE handleOfFile(FILE *pf){ - int fileDesc = _fileno(pf); - union { intptr_t osfh; HANDLE fh; } fid = { - (fileDesc>=0)? _get_osfhandle(fileDesc) : (intptr_t)INVALID_HANDLE_VALUE - }; - return fid.fh; +/* Check a pointer to see if it is NULL. If it is NULL, exit with an +** out-of-memory error. +*/ +static void shell_check_oom(void *p){ + if( p==0 ) shell_out_of_memory(); } + +/* +** Write I/O traces to the following stream. +*/ +#ifdef SQLITE_ENABLE_IOTRACE +static FILE *iotrace = 0; #endif -#ifndef SQLITE_CIO_NO_TRANSLATE -typedef struct PerStreamTags { -# if CIO_WIN_WC_XLATE - HANDLE hx; - DWORD consMode; - char acIncomplete[4]; -# else - short reachesConsole; -# endif - FILE *pf; -} PerStreamTags; - -/* Define NULL-like value for things which can validly be 0. */ -# define SHELL_INVALID_FILE_PTR ((FILE *)~0) -# if CIO_WIN_WC_XLATE -# define SHELL_INVALID_CONS_MODE 0xFFFF0000 -# endif - -# if CIO_WIN_WC_XLATE -# define PST_INITIALIZER { INVALID_HANDLE_VALUE, SHELL_INVALID_CONS_MODE, \ - {0,0,0,0}, SHELL_INVALID_FILE_PTR } -# else -# define PST_INITIALIZER { 0, SHELL_INVALID_FILE_PTR } -# endif - -/* Quickly say whether a known output is going to the console. */ -# if CIO_WIN_WC_XLATE -static short pstReachesConsole(PerStreamTags *ppst){ - return (ppst->hx != INVALID_HANDLE_VALUE); -} -# else -# define pstReachesConsole(ppst) 0 -# endif - -# if CIO_WIN_WC_XLATE -static void restoreConsoleArb(PerStreamTags *ppst){ - if( pstReachesConsole(ppst) ) SetConsoleMode(ppst->hx, ppst->consMode); -} -# else -# define restoreConsoleArb(ppst) -# endif - -/* Say whether FILE* appears to be a console, collect associated info. */ -static short streamOfConsole(FILE *pf, /* out */ PerStreamTags *ppst){ -# if CIO_WIN_WC_XLATE - short rv = 0; - DWORD dwCM = SHELL_INVALID_CONS_MODE; - HANDLE fh = handleOfFile(pf); - ppst->pf = pf; - if( INVALID_HANDLE_VALUE != fh ){ - rv = (GetFileType(fh) == FILE_TYPE_CHAR && GetConsoleMode(fh,&dwCM)); - } - ppst->hx = (rv)? fh : INVALID_HANDLE_VALUE; - ppst->consMode = dwCM; - return rv; -# else - ppst->pf = pf; - ppst->reachesConsole = ( (short)isatty(fileno(pf)) ); - return ppst->reachesConsole; -# endif +/* +** This routine works like printf in that its first argument is a +** format string and subsequent arguments are values to be substituted +** in place of % fields. The result of formatting this string +** is written to iotrace. +*/ +#ifdef SQLITE_ENABLE_IOTRACE +static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){ + va_list ap; + char *z; + if( iotrace==0 ) return; + va_start(ap, zFormat); + z = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + utf8_printf(iotrace, "%s", z); + sqlite3_free(z); } +#endif -# ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING -# define ENABLE_VIRTUAL_TERMINAL_PROCESSING (0x4) -# endif - -# if CIO_WIN_WC_XLATE -/* Define console modes for use with the Windows Console API. */ -# define SHELL_CONI_MODE \ - (ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | 0x80 \ - | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_PROCESSED_INPUT) -# define SHELL_CONO_MODE (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT \ - | ENABLE_VIRTUAL_TERMINAL_PROCESSING) -# endif - -typedef struct ConsoleInfo { - PerStreamTags pstSetup[3]; - PerStreamTags pstDesignated[3]; - StreamsAreConsole sacSetup; -} ConsoleInfo; - -static short isValidStreamInfo(PerStreamTags *ppst){ - return (ppst->pf != SHELL_INVALID_FILE_PTR); +/* +** Output string zUtf to stream pOut as w characters. If w is negative, +** then right-justify the text. W is the width in UTF-8 characters, not +** in bytes. This is different from the %*.*s specification in printf +** since with %*.*s the width is measured in bytes, not characters. +*/ +static void utf8_width_print(FILE *pOut, int w, const char *zUtf){ + int i; + int n; + int aw = w<0 ? -w : w; + if( zUtf==0 ) zUtf = ""; + for(i=n=0; zUtf[i]; i++){ + if( (zUtf[i]&0xc0)!=0x80 ){ + n++; + if( n==aw ){ + do{ i++; }while( (zUtf[i]&0xc0)==0x80 ); + break; + } + } + } + if( n>=aw ){ + utf8_printf(pOut, "%.*s", i, zUtf); + }else if( w<0 ){ + utf8_printf(pOut, "%*s%s", aw-n, "", zUtf); + }else{ + utf8_printf(pOut, "%s%*s", zUtf, aw-n, ""); + } } -static ConsoleInfo consoleInfo = { - { /* pstSetup */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER }, - { /* pstDesignated[] */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER }, - SAC_NoConsole /* sacSetup */ -}; - -SQLITE_INTERNAL_LINKAGE FILE* invalidFileStream = (FILE *)~0; -# if CIO_WIN_WC_XLATE -static void maybeSetupAsConsole(PerStreamTags *ppst, short odir){ - if( pstReachesConsole(ppst) ){ - DWORD cm = odir? SHELL_CONO_MODE : SHELL_CONI_MODE; - SetConsoleMode(ppst->hx, cm); +/* +** Determines if a string is a number of not. +*/ +static int isNumber(const char *z, int *realnum){ + if( *z=='-' || *z=='+' ) z++; + if( !IsDigit(*z) ){ + return 0; } -} -# else -# define maybeSetupAsConsole(ppst,odir) -# endif - -SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void){ -# if CIO_WIN_WC_XLATE - int ix = 0; - while( ix < 6 ){ - PerStreamTags *ppst = (ix<3)? - &consoleInfo.pstSetup[ix] : &consoleInfo.pstDesignated[ix-3]; - maybeSetupAsConsole(ppst, (ix % 3)>0); - ++ix; + z++; + if( realnum ) *realnum = 0; + while( IsDigit(*z) ){ z++; } + if( *z=='.' ){ + z++; + if( !IsDigit(*z) ) return 0; + while( IsDigit(*z) ){ z++; } + if( realnum ) *realnum = 1; } -# endif -} - -SQLITE_INTERNAL_LINKAGE StreamsAreConsole -consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ){ - StreamsAreConsole rv = SAC_NoConsole; - FILE* apf[3] = { pfIn, pfOut, pfErr }; - int ix; - for( ix = 2; ix >= 0; --ix ){ - PerStreamTags *ppst = &consoleInfo.pstSetup[ix]; - if( streamOfConsole(apf[ix], ppst) ){ - rv |= (SAC_InConsole< 0 ) fflush(apf[ix]); + if( *z=='e' || *z=='E' ){ + z++; + if( *z=='+' || *z=='-' ) z++; + if( !IsDigit(*z) ) return 0; + while( IsDigit(*z) ){ z++; } + if( realnum ) *realnum = 1; } - consoleInfo.sacSetup = rv; - consoleRenewSetup(); - return rv; + return *z==0; } -SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void ){ -# if CIO_WIN_WC_XLATE - static ConsoleInfo *pci = &consoleInfo; - if( pci->sacSetup ){ - int ix; - for( ix=0; ix<3; ++ix ){ - if( pci->sacSetup & (SAC_InConsole<pstSetup[ix]; - SetConsoleMode(ppst->hx, ppst->consMode); - } - } - } -# endif +/* +** Compute a string length that is limited to what can be stored in +** lower 30 bits of a 32-bit signed integer. +*/ +static int strlen30(const char *z){ + const char *z2 = z; + while( *z2 ){ z2++; } + return 0x3fffffff & (int)(z2 - z); } -#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */ -#ifdef SQLITE_CIO_INPUT_REDIR -/* Say whether given FILE* is among those known, via either -** consoleClassifySetup() or set{Output,Error}Stream, as -** readable, and return an associated PerStreamTags pointer -** if so. Otherwise, return 0. +/* +** Return the length of a string in characters. Multibyte UTF8 characters +** count as a single character. */ -static PerStreamTags * isKnownReadable(FILE *pf){ - static PerStreamTags *apst[] = { - &consoleInfo.pstDesignated[0], &consoleInfo.pstSetup[0], 0 - }; - int ix = 0; - do { - if( apst[ix]->pf == pf ) break; - } while( apst[++ix] != 0 ); - return apst[ix]; +static int strlenChar(const char *z){ + int n = 0; + while( *z ){ + if( (0xc0&*(z++))!=0x80 ) n++; + } + return n; } -#endif -#ifndef SQLITE_CIO_NO_TRANSLATE -/* Say whether given FILE* is among those known, via either -** consoleClassifySetup() or set{Output,Error}Stream, as -** writable, and return an associated PerStreamTags pointer -** if so. Otherwise, return 0. +/* +** Return open FILE * if zFile exists, can be opened for read +** and is an ordinary file or a character stream source. +** Otherwise return 0. */ -static PerStreamTags * isKnownWritable(FILE *pf){ - static PerStreamTags *apst[] = { - &consoleInfo.pstDesignated[1], &consoleInfo.pstDesignated[2], - &consoleInfo.pstSetup[1], &consoleInfo.pstSetup[2], 0 - }; - int ix = 0; - do { - if( apst[ix]->pf == pf ) break; - } while( apst[++ix] != 0 ); - return apst[ix]; -} - -static FILE *designateEmitStream(FILE *pf, unsigned chix){ - FILE *rv = consoleInfo.pstDesignated[chix].pf; - if( pf == invalidFileStream ) return rv; - else{ - /* Setting a possibly new output stream. */ - PerStreamTags *ppst = isKnownWritable(pf); - if( ppst != 0 ){ - PerStreamTags pst = *ppst; - consoleInfo.pstDesignated[chix] = pst; - }else streamOfConsole(pf, &consoleInfo.pstDesignated[chix]); +static FILE * openChrSource(const char *zFile){ +#ifdef _WIN32 + struct _stat x = {0}; +# define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0) + /* On Windows, open first, then check the stream nature. This order + ** is necessary because _stat() and sibs, when checking a named pipe, + ** effectively break the pipe as its supplier sees it. */ + FILE *rv = fopen(zFile, "rb"); + if( rv==0 ) return 0; + if( _fstat(_fileno(rv), &x) != 0 + || !STAT_CHR_SRC(x.st_mode)){ + fclose(rv); + rv = 0; } return rv; +#else + struct stat x = {0}; + int rc = stat(zFile, &x); +# define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode)) + if( rc!=0 ) return 0; + if( STAT_CHR_SRC(x.st_mode) ){ + return fopen(zFile, "rb"); + }else{ + return 0; + } +#endif +#undef STAT_CHR_SRC } -SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf){ - return designateEmitStream(pf, 1); -} -# ifdef CONSIO_SET_ERROR_STREAM -SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf){ - return designateEmitStream(pf, 2); -} -# endif -#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */ - -#ifndef SQLITE_CIO_NO_SETMODE -# if CIO_WIN_WC_XLATE -static void setModeFlushQ(FILE *pf, short bFlush, int mode){ - if( bFlush ) fflush(pf); - _setmode(_fileno(pf), mode); -} -# else -# define setModeFlushQ(f, b, m) if(b) fflush(f) -# endif +/* +** This routine reads a line of text from FILE in, stores +** the text in memory obtained from malloc() and returns a pointer +** to the text. NULL is returned at end of file, or if malloc() +** fails. +** +** If zLine is not NULL then it is a malloced buffer returned from +** a previous call to this routine that may be reused. +*/ +static char *local_getline(char *zLine, FILE *in){ + int nLine = zLine==0 ? 0 : 100; + int n = 0; -SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *pf, short bFlush){ - setModeFlushQ(pf, bFlush, _O_BINARY); -} -SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *pf, short bFlush){ - setModeFlushQ(pf, bFlush, _O_TEXT); -} -# undef setModeFlushQ - -#else /* defined(SQLITE_CIO_NO_SETMODE) */ -# define setBinaryMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0) -# define setTextMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0) -#endif /* defined(SQLITE_CIO_NO_SETMODE) */ - -#ifndef SQLITE_CIO_NO_TRANSLATE -# if CIO_WIN_WC_XLATE -/* Write buffer cBuf as output to stream known to reach console, -** limited to ncTake char's. Return ncTake on success, else 0. */ -static int conZstrEmit(PerStreamTags *ppst, const char *z, int ncTake){ - int rv = 0; - if( z!=NULL ){ - int nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, 0,0); - if( nwc > 0 ){ - WCHAR *zw = sqlite3_malloc64(nwc*sizeof(WCHAR)); - if( zw!=NULL ){ - nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, zw,nwc); - if( nwc > 0 ){ - /* Translation from UTF-8 to UTF-16, then WCHARs out. */ - if( WriteConsoleW(ppst->hx, zw,nwc, 0, NULL) ){ - rv = ncTake; - } - } - sqlite3_free(zw); + while( 1 ){ + if( n+100>nLine ){ + nLine = nLine*2 + 100; + zLine = realloc(zLine, nLine); + shell_check_oom(zLine); + } + if( fgets(&zLine[n], nLine - n, in)==0 ){ + if( n==0 ){ + free(zLine); + return 0; } + zLine[n] = 0; + break; + } + while( zLine[n] ) n++; + if( n>0 && zLine[n-1]=='\n' ){ + n--; + if( n>0 && zLine[n-1]=='\r' ) n--; + zLine[n] = 0; + break; } } - return rv; -} - -/* For {f,o,e}PrintfUtf8() when stream is known to reach console. */ -static int conioVmPrintf(PerStreamTags *ppst, const char *zFormat, va_list ap){ - char *z = sqlite3_vmprintf(zFormat, ap); - if( z ){ - int rv = conZstrEmit(ppst, z, (int)strlen(z)); - sqlite3_free(z); - return rv; - }else return 0; -} -# endif /* CIO_WIN_WC_XLATE */ - -# ifdef CONSIO_GET_EMIT_STREAM -static PerStreamTags * getDesignatedEmitStream(FILE *pf, unsigned chix, - PerStreamTags *ppst){ - PerStreamTags *rv = isKnownWritable(pf); - short isValid = (rv!=0)? isValidStreamInfo(rv) : 0; - if( rv != 0 && isValid ) return rv; - streamOfConsole(pf, ppst); - return ppst; +#if defined(_WIN32) || defined(WIN32) + /* For interactive input on Windows systems, translate the + ** multi-byte characterset characters into UTF-8. */ + if( stdin_is_interactive && in==stdin ){ + char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0); + if( zTrans ){ + i64 nTrans = strlen(zTrans)+1; + if( nTrans>nLine ){ + zLine = realloc(zLine, nTrans); + shell_check_oom(zLine); + } + memcpy(zLine, zTrans, nTrans); + sqlite3_free(zTrans); + } + } +#endif /* defined(_WIN32) || defined(WIN32) */ + return zLine; } -# endif -/* Get stream info, either for designated output or error stream when -** chix equals 1 or 2, or for an arbitrary stream when chix == 0. -** In either case, ppst references a caller-owned PerStreamTags -** struct which may be filled in if none of the known writable -** streams is being held by consoleInfo. The ppf parameter is a -** byref output when chix!=0 and a byref input when chix==0. - */ -static PerStreamTags * -getEmitStreamInfo(unsigned chix, PerStreamTags *ppst, - /* in/out */ FILE **ppf){ - PerStreamTags *ppstTry; - FILE *pfEmit; - if( chix > 0 ){ - ppstTry = &consoleInfo.pstDesignated[chix]; - if( !isValidStreamInfo(ppstTry) ){ - ppstTry = &consoleInfo.pstSetup[chix]; - pfEmit = ppst->pf; - }else pfEmit = ppstTry->pf; - if( !isValidStreamInfo(ppstTry) ){ - pfEmit = (chix > 1)? stderr : stdout; - ppstTry = ppst; - streamOfConsole(pfEmit, ppstTry); - } - *ppf = pfEmit; +/* +** Retrieve a single line of input text. +** +** If in==0 then read from standard input and prompt before each line. +** If isContinuation is true, then a continuation prompt is appropriate. +** If isContinuation is zero, then the main prompt should be used. +** +** If zPrior is not NULL then it is a buffer from a prior call to this +** routine that can be reused. +** +** The result is stored in space obtained from malloc() and must either +** be freed by the caller or else passed back into this routine via the +** zPrior argument for reuse. +*/ +#ifndef SQLITE_SHELL_FIDDLE +static char *one_input_line(FILE *in, char *zPrior, int isContinuation){ + char *zPrompt; + char *zResult; + if( in!=0 ){ + zResult = local_getline(zPrior, in); }else{ - ppstTry = isKnownWritable(*ppf); - if( ppstTry != 0 ) return ppstTry; - streamOfConsole(*ppf, ppst); - return ppst; + zPrompt = isContinuation ? continuePrompt : mainPrompt; +#if SHELL_USE_LOCAL_GETLINE + printf("%s", zPrompt); + fflush(stdout); + zResult = local_getline(zPrior, stdin); +#else + free(zPrior); + zResult = shell_readline(zPrompt); + if( zResult && *zResult ) shell_add_history(zResult); +#endif } - return ppstTry; + return zResult; } +#endif /* !SQLITE_SHELL_FIDDLE */ -SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...){ - va_list ap; - int rv; - FILE *pfOut; - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ -# if CIO_WIN_WC_XLATE - PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut); -# else - getEmitStreamInfo(1, &pst, &pfOut); -# endif - assert(zFormat!=0); - va_start(ap, zFormat); -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ){ - rv = conioVmPrintf(ppst, zFormat, ap); - }else{ -# endif - rv = vfprintf(pfOut, zFormat, ap); -# if CIO_WIN_WC_XLATE - } -# endif - va_end(ap); - return rv; +/* +** Return the value of a hexadecimal digit. Return -1 if the input +** is not a hex digit. +*/ +static int hexDigitValue(char c){ + if( c>='0' && c<='9' ) return c - '0'; + if( c>='a' && c<='f' ) return c - 'a' + 10; + if( c>='A' && c<='F' ) return c - 'A' + 10; + return -1; } -SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...){ - va_list ap; - int rv; - FILE *pfErr; - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ -# if CIO_WIN_WC_XLATE - PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr); -# else - getEmitStreamInfo(2, &pst, &pfErr); -# endif - assert(zFormat!=0); - va_start(ap, zFormat); -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ){ - rv = conioVmPrintf(ppst, zFormat, ap); - }else{ -# endif - rv = vfprintf(pfErr, zFormat, ap); -# if CIO_WIN_WC_XLATE +/* +** Interpret zArg as an integer value, possibly with suffixes. +*/ +static sqlite3_int64 integerValue(const char *zArg){ + sqlite3_int64 v = 0; + static const struct { char *zSuffix; int iMult; } aMult[] = { + { "KiB", 1024 }, + { "MiB", 1024*1024 }, + { "GiB", 1024*1024*1024 }, + { "KB", 1000 }, + { "MB", 1000000 }, + { "GB", 1000000000 }, + { "K", 1000 }, + { "M", 1000000 }, + { "G", 1000000000 }, + }; + int i; + int isNeg = 0; + if( zArg[0]=='-' ){ + isNeg = 1; + zArg++; + }else if( zArg[0]=='+' ){ + zArg++; } -# endif - va_end(ap); - return rv; -} - -SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...){ - va_list ap; - int rv; - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ -# if CIO_WIN_WC_XLATE - PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO); -# else - getEmitStreamInfo(0, &pst, &pfO); -# endif - assert(zFormat!=0); - va_start(ap, zFormat); -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ){ - maybeSetupAsConsole(ppst, 1); - rv = conioVmPrintf(ppst, zFormat, ap); - if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst); + if( zArg[0]=='0' && zArg[1]=='x' ){ + int x; + zArg += 2; + while( (x = hexDigitValue(zArg[0]))>=0 ){ + v = (v<<4) + x; + zArg++; + } }else{ -# endif - rv = vfprintf(pfO, zFormat, ap); -# if CIO_WIN_WC_XLATE + while( IsDigit(zArg[0]) ){ + v = v*10 + zArg[0] - '0'; + zArg++; + } } -# endif - va_end(ap); - return rv; -} - -SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO){ - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ -# if CIO_WIN_WC_XLATE - PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO); -# else - getEmitStreamInfo(0, &pst, &pfO); -# endif - assert(z!=0); -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ){ - int rv; - maybeSetupAsConsole(ppst, 1); - rv = conZstrEmit(ppst, z, (int)strlen(z)); - if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst); - return rv; - }else { -# endif - return (fputs(z, pfO)<0)? 0 : (int)strlen(z); -# if CIO_WIN_WC_XLATE + for(i=0; iz); + initText(p); } -#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */ +/* zIn is either a pointer to a NULL-terminated string in memory obtained +** from malloc(), or a NULL pointer. The string pointed to by zAppend is +** added to zIn, and the result returned in memory obtained from malloc(). +** zIn, if it was not NULL, is freed. +** +** If the third argument, quote, is not '\0', then it is used as a +** quote character for zAppend. +*/ +static void appendText(ShellText *p, const char *zAppend, char quote){ + i64 len; + i64 i; + i64 nAppend = strlen30(zAppend); -#if !(defined(SQLITE_CIO_NO_UTF8SCAN) && defined(SQLITE_CIO_NO_TRANSLATE)) -/* Skip over as much z[] input char sequence as is valid UTF-8, -** limited per nAccept char's or whole characters and containing -** no char cn such that ((1<=0 => char count, nAccept<0 => character - */ -SQLITE_INTERNAL_LINKAGE const char* -zSkipValidUtf8(const char *z, int nAccept, long ccm){ - int ng = (nAccept<0)? -nAccept : 0; - const char *pcLimit = (nAccept>=0)? z+nAccept : 0; - assert(z!=0); - while( (pcLimit)? (z= pcLimit ) return z; - else{ - char ct = *zt++; - if( ct==0 || (zt-z)>4 || (ct & 0xC0)!=0x80 ){ - /* Trailing bytes are too few, too many, or invalid. */ - return z; - } - } - } while( ((c <<= 1) & 0x40) == 0x40 ); /* Eat lead byte's count. */ - z = zt; + len = nAppend+p->n+1; + if( quote ){ + len += 2; + for(i=0; ipf) ) restoreConsoleArb(ppst); - return rv; - }else { -# endif - return (int)fwrite(cBuf, 1, nAccept, pfO); -# if CIO_WIN_WC_XLATE - } -# endif -} -# endif - -SQLITE_INTERNAL_LINKAGE int -oPutbUtf8(const char *cBuf, int nAccept){ - FILE *pfOut; - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ -# if CIO_WIN_WC_XLATE - PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut); -# else - getEmitStreamInfo(1, &pst, &pfOut); -# endif -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ){ - return conZstrEmit(ppst, cBuf, nAccept); - }else { -# endif - return (int)fwrite(cBuf, 1, nAccept, pfOut); -# if CIO_WIN_WC_XLATE - } -# endif -} -# ifdef CONSIO_EPUTB -SQLITE_INTERNAL_LINKAGE int -ePutbUtf8(const char *cBuf, int nAccept){ - FILE *pfErr; - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ - PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr); -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ){ - return conZstrEmit(ppst, cBuf, nAccept); - }else { -# endif - return (int)fwrite(cBuf, 1, nAccept, pfErr); -# if CIO_WIN_WC_XLATE - } -# endif -} -# endif /* defined(CONSIO_EPUTB) */ - -SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn){ - if( pfIn==0 ) pfIn = stdin; -# if CIO_WIN_WC_XLATE - if( pfIn == consoleInfo.pstSetup[0].pf - && (consoleInfo.sacSetup & SAC_InConsole)!=0 ){ -# if CIO_WIN_WC_XLATE==1 -# define SHELL_GULP 150 /* Count of WCHARS to be gulped at a time */ - WCHAR wcBuf[SHELL_GULP+1]; - int lend = 0, noc = 0; - if( ncMax > 0 ) cBuf[0] = 0; - while( noc < ncMax-8-1 && !lend ){ - /* There is room for at least 2 more characters and a 0-terminator. */ - int na = (ncMax > SHELL_GULP*4+1 + noc)? SHELL_GULP : (ncMax-1 - noc)/4; -# undef SHELL_GULP - DWORD nbr = 0; - BOOL bRC = ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf, na, &nbr, 0); - if( bRC && nbr>0 && (wcBuf[nbr-1]&0xF800)==0xD800 ){ - /* Last WHAR read is first of a UTF-16 surrogate pair. Grab its mate. */ - DWORD nbrx; - bRC &= ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf+nbr, 1, &nbrx, 0); - if( bRC ) nbr += nbrx; - } - if( !bRC || (noc==0 && nbr==0) ) return 0; - if( nbr > 0 ){ - int nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,0,0,0,0); - if( nmb != 0 && noc+nmb <= ncMax ){ - int iseg = noc; - nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,cBuf+noc,nmb,0,0); - noc += nmb; - /* Fixup line-ends as coded by Windows for CR (or "Enter".) - ** This is done without regard for any setMode{Text,Binary}() - ** call that might have been done on the interactive input. - */ - if( noc > 0 ){ - if( cBuf[noc-1]=='\n' ){ - lend = 1; - if( noc > 1 && cBuf[noc-2]=='\r' ) cBuf[--noc-1] = '\n'; - } - } - /* Check for ^Z (anywhere in line) too, to act as EOF. */ - while( iseg < noc ){ - if( cBuf[iseg]=='\x1a' ){ - noc = iseg; /* Chop ^Z and anything following. */ - lend = 1; /* Counts as end of line too. */ - break; - } - ++iseg; - } - }else break; /* Drop apparent garbage in. (Could assert.) */ - }else break; - } - /* If got nothing, (after ^Z chop), must be at end-of-file. */ - if( noc > 0 ){ - cBuf[noc] = 0; - return cBuf; - }else return 0; -# endif - }else{ -# endif - return fgets(cBuf, ncMax, pfIn); -# if CIO_WIN_WC_XLATE + if( p->z==0 || p->n+len>=p->nAlloc ){ + p->nAlloc = p->nAlloc*2 + len + 20; + p->z = realloc(p->z, p->nAlloc); + shell_check_oom(p->z); } -# endif -} -#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */ - -#if defined(_MSC_VER) -# pragma warning(default : 4204) -#endif - -#undef SHELL_INVALID_FILE_PTR - -/************************* End ../ext/consio/console_io.c ********************/ - -#ifndef SQLITE_SHELL_FIDDLE - -/* From here onward, fgets() is redirected to the console_io library. */ -# define fgets(b,n,f) fGetsUtf8(b,n,f) -/* - * Define macros for emitting output text in various ways: - * sputz(s, z) => emit 0-terminated string z to given stream s - * sputf(s, f, ...) => emit varargs per format f to given stream s - * oputz(z) => emit 0-terminated string z to default stream - * oputf(f, ...) => emit varargs per format f to default stream - * eputz(z) => emit 0-terminated string z to error stream - * eputf(f, ...) => emit varargs per format f to error stream - * oputb(b, n) => emit char buffer b[0..n-1] to default stream - * - * Note that the default stream is whatever has been last set via: - * setOutputStream(FILE *pf) - * This is normally the stream that CLI normal output goes to. - * For the stand-alone CLI, it is stdout with no .output redirect. - * - * The ?putz(z) forms are required for the Fiddle builds for string literal - * output, in aid of enforcing format string to argument correspondence. - */ -# define sputz(s,z) fPutsUtf8(z,s) -# define sputf fPrintfUtf8 -# define oputz(z) oPutsUtf8(z) -# define oputf oPrintfUtf8 -# define eputz(z) ePutsUtf8(z) -# define eputf ePrintfUtf8 -# define oputb(buf,na) oPutbUtf8(buf,na) - -#else -/* For Fiddle, all console handling and emit redirection is omitted. */ -/* These next 3 macros are for emitting formatted output. When complaints - * from the WASM build are issued for non-formatted output, (when a mere - * string literal is to be emitted, the ?putz(z) forms should be used. - * (This permits compile-time checking of format string / argument mismatch.) - */ -# define oputf(fmt, ...) printf(fmt,__VA_ARGS__) -# define eputf(fmt, ...) fprintf(stderr,fmt,__VA_ARGS__) -# define sputf(fp,fmt, ...) fprintf(fp,fmt,__VA_ARGS__) -/* These next 3 macros are for emitting simple string literals. */ -# define oputz(z) fputs(z,stdout) -# define eputz(z) fputs(z,stderr) -# define sputz(fp,z) fputs(z,fp) -# define oputb(buf,na) fwrite(buf,1,na,stdout) -#endif - -/* True if the timer is enabled */ -static int enableTimer = 0; -/* A version of strcmp() that works with NULL values */ -static int cli_strcmp(const char *a, const char *b){ - if( a==0 ) a = ""; - if( b==0 ) b = ""; - return strcmp(a,b); -} -static int cli_strncmp(const char *a, const char *b, size_t n){ - if( a==0 ) a = ""; - if( b==0 ) b = ""; - return strncmp(a,b,n); -} - -/* Return the current wall-clock time */ -static sqlite3_int64 timeOfDay(void){ - static sqlite3_vfs *clockVfs = 0; - sqlite3_int64 t; - if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); - if( clockVfs==0 ) return 0; /* Never actually happens */ - if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){ - clockVfs->xCurrentTimeInt64(clockVfs, &t); + if( quote ){ + char *zCsr = p->z+p->n; + *zCsr++ = quote; + for(i=0; in = (int)(zCsr - p->z); + *zCsr = '\0'; }else{ - double r; - clockVfs->xCurrentTime(clockVfs, &r); - t = (sqlite3_int64)(r*86400000.0); + memcpy(p->z+p->n, zAppend, nAppend); + p->n += nAppend; + p->z[p->n] = '\0'; } - return t; } -#if !defined(_WIN32) && !defined(WIN32) && !defined(__minux) -#include -#include - -/* VxWorks does not support getrusage() as far as we can determine */ -#if defined(_WRS_KERNEL) || defined(__RTP__) -struct rusage { - struct timeval ru_utime; /* user CPU time used */ - struct timeval ru_stime; /* system CPU time used */ -}; -#define getrusage(A,B) memset(B,0,sizeof(*B)) -#endif - -/* Saved resource information for the beginning of an operation */ -static struct rusage sBegin; /* CPU time at start */ -static sqlite3_int64 iBegin; /* Wall-clock time at start */ - /* -** Begin timing an operation +** Attempt to determine if identifier zName needs to be quoted, either +** because it contains non-alphanumeric characters, or because it is an +** SQLite keyword. Be conservative in this estimate: When in doubt assume +** that quoting is required. +** +** Return '"' if quoting is required. Return 0 if no quoting is required. */ -static void beginTimer(void){ - if( enableTimer ){ - getrusage(RUSAGE_SELF, &sBegin); - iBegin = timeOfDay(); +static char quoteChar(const char *zName){ + int i; + if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"'; + for(i=0; zName[i]; i++){ + if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"'; } -} - -/* Return the difference of two time_structs in seconds */ -static double timeDiff(struct timeval *pStart, struct timeval *pEnd){ - return (pEnd->tv_usec - pStart->tv_usec)*0.000001 + - (double)(pEnd->tv_sec - pStart->tv_sec); + return sqlite3_keyword_check(zName, i) ? '"' : 0; } /* -** Print the timing results. +** Construct a fake object name and column list to describe the structure +** of the view, virtual table, or table valued function zSchema.zName. */ -static void endTimer(void){ - if( enableTimer ){ - sqlite3_int64 iEnd = timeOfDay(); - struct rusage sEnd; - getrusage(RUSAGE_SELF, &sEnd); - sputf(stdout, "Run Time: real %.3f user %f sys %f\n", - (iEnd - iBegin)*0.001, - timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), - timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); - } -} - -#define BEGIN_TIMER beginTimer() -#define END_TIMER endTimer() -#define HAS_TIMER 1 - -#elif (defined(_WIN32) || defined(WIN32)) - -/* Saved resource information for the beginning of an operation */ -static HANDLE hProcess; -static FILETIME ftKernelBegin; -static FILETIME ftUserBegin; -static sqlite3_int64 ftWallBegin; -typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, - LPFILETIME, LPFILETIME); -static GETPROCTIMES getProcessTimesAddr = NULL; +static char *shellFakeSchema( + sqlite3 *db, /* The database connection containing the vtab */ + const char *zSchema, /* Schema of the database holding the vtab */ + const char *zName /* The name of the virtual table */ +){ + sqlite3_stmt *pStmt = 0; + char *zSql; + ShellText s; + char cQuote; + char *zDiv = "("; + int nRow = 0; -/* -** Check to see if we have timer support. Return 1 if necessary -** support found (or found previously). -*/ -static int hasTimer(void){ - if( getProcessTimesAddr ){ - return 1; - } else { -#if !SQLITE_OS_WINRT - /* GetProcessTimes() isn't supported in WIN95 and some other Windows - ** versions. See if the version we are running on has it, and if it - ** does, save off a pointer to it and the current process handle. - */ - hProcess = GetCurrentProcess(); - if( hProcess ){ - HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll")); - if( NULL != hinstLib ){ - getProcessTimesAddr = - (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes"); - if( NULL != getProcessTimesAddr ){ - return 1; - } - FreeLibrary(hinstLib); - } - } -#endif + zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;", + zSchema ? zSchema : "main", zName); + shell_check_oom(zSql); + sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + initText(&s); + if( zSchema ){ + cQuote = quoteChar(zSchema); + if( cQuote && sqlite3_stricmp(zSchema,"temp")==0 ) cQuote = 0; + appendText(&s, zSchema, cQuote); + appendText(&s, ".", 0); } - return 0; + cQuote = quoteChar(zName); + appendText(&s, zName, cQuote); + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + const char *zCol = (const char*)sqlite3_column_text(pStmt, 1); + nRow++; + appendText(&s, zDiv, 0); + zDiv = ","; + if( zCol==0 ) zCol = ""; + cQuote = quoteChar(zCol); + appendText(&s, zCol, cQuote); + } + appendText(&s, ")", 0); + sqlite3_finalize(pStmt); + if( nRow==0 ){ + freeText(&s); + s.z = 0; + } + return s.z; } /* -** Begin timing an operation +** SQL function: shell_module_schema(X) +** +** Return a fake schema for the table-valued function or eponymous virtual +** table X. */ -static void beginTimer(void){ - if( enableTimer && getProcessTimesAddr ){ - FILETIME ftCreation, ftExit; - getProcessTimesAddr(hProcess,&ftCreation,&ftExit, - &ftKernelBegin,&ftUserBegin); - ftWallBegin = timeOfDay(); +static void shellModuleSchema( + sqlite3_context *pCtx, + int nVal, + sqlite3_value **apVal +){ + const char *zName; + char *zFake; + UNUSED_PARAMETER(nVal); + zName = (const char*)sqlite3_value_text(apVal[0]); + zFake = zName ? shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName) : 0; + if( zFake ){ + sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake), + -1, sqlite3_free); + free(zFake); } } -/* Return the difference of two FILETIME structs in seconds */ -static double timeDiff(FILETIME *pStart, FILETIME *pEnd){ - sqlite_int64 i64Start = *((sqlite_int64 *) pStart); - sqlite_int64 i64End = *((sqlite_int64 *) pEnd); - return (double) ((i64End - i64Start) / 10000000.0); -} - /* -** Print the timing results. +** SQL function: shell_add_schema(S,X) +** +** Add the schema name X to the CREATE statement in S and return the result. +** Examples: +** +** CREATE TABLE t1(x) -> CREATE TABLE xyz.t1(x); +** +** Also works on +** +** CREATE INDEX +** CREATE UNIQUE INDEX +** CREATE VIEW +** CREATE TRIGGER +** CREATE VIRTUAL TABLE +** +** This UDF is used by the .schema command to insert the schema name of +** attached databases into the middle of the sqlite_schema.sql field. */ -static void endTimer(void){ - if( enableTimer && getProcessTimesAddr){ - FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd; - sqlite3_int64 ftWallEnd = timeOfDay(); - getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd); - sputf(stdout, "Run Time: real %.3f user %f sys %f\n", - (ftWallEnd - ftWallBegin)*0.001, - timeDiff(&ftUserBegin, &ftUserEnd), - timeDiff(&ftKernelBegin, &ftKernelEnd)); +static void shellAddSchemaName( + sqlite3_context *pCtx, + int nVal, + sqlite3_value **apVal +){ + static const char *aPrefix[] = { + "TABLE", + "INDEX", + "UNIQUE INDEX", + "VIEW", + "TRIGGER", + "VIRTUAL TABLE" + }; + int i = 0; + const char *zIn = (const char*)sqlite3_value_text(apVal[0]); + const char *zSchema = (const char*)sqlite3_value_text(apVal[1]); + const char *zName = (const char*)sqlite3_value_text(apVal[2]); + sqlite3 *db = sqlite3_context_db_handle(pCtx); + UNUSED_PARAMETER(nVal); + if( zIn!=0 && cli_strncmp(zIn, "CREATE ", 7)==0 ){ + for(i=0; i +#include +#include +#include +#include +#include +#include /* -** Prompt strings. Initialized in main. Settable with -** .prompt main continue +** We may need several defines that should have been in "sys/stat.h". */ -#define PROMPT_LEN_MAX 20 -/* First line prompt. default: "sqlite> " */ -static char mainPrompt[PROMPT_LEN_MAX]; -/* Continuation prompt. default: " ...> " */ -static char continuePrompt[PROMPT_LEN_MAX]; - -/* This is variant of the standard-library strncpy() routine with the -** one change that the destination string is always zero-terminated, even -** if there is no zero-terminator in the first n-1 characters of the source -** string. -*/ -static char *shell_strncpy(char *dest, const char *src, size_t n){ - size_t i; - for(i=0; iinParenLevel += ni; - if( ni==0 ) p->inParenLevel = 0; - p->zScannerAwaits = 0; -} - -/* Record that a lexeme is opened, or closed with args==0. */ -static void setLexemeOpen(struct DynaPrompt *p, char *s, char c){ - if( s!=0 || c==0 ){ - p->zScannerAwaits = s; - p->acAwait[0] = 0; - }else{ - p->acAwait[0] = c; - p->zScannerAwaits = p->acAwait; - } -} -/* Upon demand, derive the continuation prompt to display. */ -static char *dynamicContinuePrompt(void){ - if( continuePrompt[0]==0 - || (dynPrompt.zScannerAwaits==0 && dynPrompt.inParenLevel == 0) ){ - return continuePrompt; - }else{ - if( dynPrompt.zScannerAwaits ){ - size_t ncp = strlen(continuePrompt); - size_t ndp = strlen(dynPrompt.zScannerAwaits); - if( ndp > ncp-3 ) return continuePrompt; - strcpy(dynPrompt.dynamicPrompt, dynPrompt.zScannerAwaits); - while( ndp<3 ) dynPrompt.dynamicPrompt[ndp++] = ' '; - shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3, - PROMPT_LEN_MAX-4); - }else{ - if( dynPrompt.inParenLevel>9 ){ - shell_strncpy(dynPrompt.dynamicPrompt, "(..", 4); - }else if( dynPrompt.inParenLevel<0 ){ - shell_strncpy(dynPrompt.dynamicPrompt, ")x!", 4); - }else{ - shell_strncpy(dynPrompt.dynamicPrompt, "(x.", 4); - dynPrompt.dynamicPrompt[2] = (char)('0'+dynPrompt.inParenLevel); - } - shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3, - PROMPT_LEN_MAX-4); - } - } - return dynPrompt.dynamicPrompt; -} -#endif /* !defined(SQLITE_OMIT_DYNAPROMPT) */ +#ifndef S_ISREG +#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#endif -/* Indicate out-of-memory and exit. */ -static void shell_out_of_memory(void){ - eputz("Error: out of memory\n"); - exit(1); -} +#ifndef S_ISDIR +#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#endif -/* Check a pointer to see if it is NULL. If it is NULL, exit with an -** out-of-memory error. -*/ -static void shell_check_oom(const void *p){ - if( p==0 ) shell_out_of_memory(); -} +#ifndef S_ISLNK +#define S_ISLNK(mode) (0) +#endif /* -** Write I/O traces to the following stream. +** We may need to provide the "mode_t" type. */ -#ifdef SQLITE_ENABLE_IOTRACE -static FILE *iotrace = 0; + +#ifndef MODE_T_DEFINED + #define MODE_T_DEFINED + typedef unsigned short mode_t; #endif /* -** This routine works like printf in that its first argument is a -** format string and subsequent arguments are values to be substituted -** in place of % fields. The result of formatting this string -** is written to iotrace. +** We may need to provide the "ino_t" type. */ -#ifdef SQLITE_ENABLE_IOTRACE -static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){ - va_list ap; - char *z; - if( iotrace==0 ) return; - va_start(ap, zFormat); - z = sqlite3_vmprintf(zFormat, ap); - va_end(ap); - sputf(iotrace, "%s", z); - sqlite3_free(z); -} + +#ifndef INO_T_DEFINED + #define INO_T_DEFINED + typedef unsigned short ino_t; #endif /* -** Output string zUtf to Out stream as w characters. If w is negative, -** then right-justify the text. W is the width in UTF-8 characters, not -** in bytes. This is different from the %*.*s specification in printf -** since with %*.*s the width is measured in bytes, not characters. +** We need to define "NAME_MAX" if it was not present in "limits.h". */ -static void utf8_width_print(int w, const char *zUtf){ - int i; - int n; - int aw = w<0 ? -w : w; - if( zUtf==0 ) zUtf = ""; - for(i=n=0; zUtf[i]; i++){ - if( (zUtf[i]&0xc0)!=0x80 ){ - n++; - if( n==aw ){ - do{ i++; }while( (zUtf[i]&0xc0)==0x80 ); - break; - } - } - } - if( n>=aw ){ - oputf("%.*s", i, zUtf); - }else if( w<0 ){ - oputf("%*s%s", aw-n, "", zUtf); - }else{ - oputf("%s%*s", zUtf, aw-n, ""); - } -} +#ifndef NAME_MAX +# ifdef FILENAME_MAX +# define NAME_MAX (FILENAME_MAX) +# else +# define NAME_MAX (260) +# endif +#endif /* -** Determines if a string is a number of not. +** We need to define "NULL_INTPTR_T" and "BAD_INTPTR_T". */ -static int isNumber(const char *z, int *realnum){ - if( *z=='-' || *z=='+' ) z++; - if( !IsDigit(*z) ){ - return 0; - } - z++; - if( realnum ) *realnum = 0; - while( IsDigit(*z) ){ z++; } - if( *z=='.' ){ - z++; - if( !IsDigit(*z) ) return 0; - while( IsDigit(*z) ){ z++; } - if( realnum ) *realnum = 1; - } - if( *z=='e' || *z=='E' ){ - z++; - if( *z=='+' || *z=='-' ) z++; - if( !IsDigit(*z) ) return 0; - while( IsDigit(*z) ){ z++; } - if( realnum ) *realnum = 1; - } - return *z==0; -} + +#ifndef NULL_INTPTR_T +# define NULL_INTPTR_T ((intptr_t)(0)) +#endif + +#ifndef BAD_INTPTR_T +# define BAD_INTPTR_T ((intptr_t)(-1)) +#endif /* -** Compute a string length that is limited to what can be stored in -** lower 30 bits of a 32-bit signed integer. +** We need to provide the necessary structures and related types. */ -static int strlen30(const char *z){ - const char *z2 = z; - while( *z2 ){ z2++; } - return 0x3fffffff & (int)(z2 - z); -} + +#ifndef DIRENT_DEFINED +#define DIRENT_DEFINED +typedef struct DIRENT DIRENT; +typedef DIRENT *LPDIRENT; +struct DIRENT { + ino_t d_ino; /* Sequence number, do not use. */ + unsigned d_attributes; /* Win32 file attributes. */ + char d_name[NAME_MAX + 1]; /* Name within the directory. */ +}; +#endif + +#ifndef DIR_DEFINED +#define DIR_DEFINED +typedef struct DIR DIR; +typedef DIR *LPDIR; +struct DIR { + intptr_t d_handle; /* Value returned by "_findfirst". */ + DIRENT d_first; /* DIRENT constructed based on "_findfirst". */ + DIRENT d_next; /* DIRENT constructed based on "_findnext". */ +}; +#endif /* -** Return the length of a string in characters. Multibyte UTF8 characters -** count as a single character. +** Provide a macro, for use by the implementation, to determine if a +** particular directory entry should be skipped over when searching for +** the next directory entry that should be returned by the readdir() or +** readdir_r() functions. */ -static int strlenChar(const char *z){ - int n = 0; - while( *z ){ - if( (0xc0&*(z++))!=0x80 ) n++; - } - return n; -} + +#ifndef is_filtered +# define is_filtered(a) ((((a).attrib)&_A_HIDDEN) || (((a).attrib)&_A_SYSTEM)) +#endif /* -** Return open FILE * if zFile exists, can be opened for read -** and is an ordinary file or a character stream source. -** Otherwise return 0. +** Provide the function prototype for the POSIX compatiable getenv() +** function. This function is not thread-safe. */ -static FILE * openChrSource(const char *zFile){ -#if defined(_WIN32) || defined(WIN32) - struct __stat64 x = {0}; -# define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0) - /* On Windows, open first, then check the stream nature. This order - ** is necessary because _stat() and sibs, when checking a named pipe, - ** effectively break the pipe as its supplier sees it. */ - FILE *rv = fopen(zFile, "rb"); - if( rv==0 ) return 0; - if( _fstat64(_fileno(rv), &x) != 0 - || !STAT_CHR_SRC(x.st_mode)){ - fclose(rv); - rv = 0; - } - return rv; -#else - struct stat x = {0}; - int rc = stat(zFile, &x); -# define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode)) - if( rc!=0 ) return 0; - if( STAT_CHR_SRC(x.st_mode) ){ - return fopen(zFile, "rb"); - }else{ - return 0; - } -#endif -#undef STAT_CHR_SRC -} + +extern const char *windirent_getenv(const char *name); /* -** This routine reads a line of text from FILE in, stores -** the text in memory obtained from malloc() and returns a pointer -** to the text. NULL is returned at end of file, or if malloc() -** fails. -** -** If zLine is not NULL then it is a malloced buffer returned from -** a previous call to this routine that may be reused. +** Finally, we can provide the function prototypes for the opendir(), +** readdir(), readdir_r(), and closedir() POSIX functions. */ -static char *local_getline(char *zLine, FILE *in){ - int nLine = zLine==0 ? 0 : 100; - int n = 0; - while( 1 ){ - if( n+100>nLine ){ - nLine = nLine*2 + 100; - zLine = realloc(zLine, nLine); - shell_check_oom(zLine); - } - if( fgets(&zLine[n], nLine - n, in)==0 ){ - if( n==0 ){ - free(zLine); - return 0; - } - zLine[n] = 0; - break; - } - while( zLine[n] ) n++; - if( n>0 && zLine[n-1]=='\n' ){ - n--; - if( n>0 && zLine[n-1]=='\r' ) n--; - zLine[n] = 0; - break; - } - } - return zLine; -} +extern LPDIR opendir(const char *dirname); +extern LPDIRENT readdir(LPDIR dirp); +extern INT readdir_r(LPDIR dirp, LPDIRENT entry, LPDIRENT *result); +extern INT closedir(LPDIR dirp); +#endif /* defined(WIN32) && defined(_MSC_VER) */ + +/************************* End test_windirent.h ********************/ +/************************* Begin test_windirent.c ******************/ /* -** Retrieve a single line of input text. +** 2015 November 30 ** -** If in==0 then read from standard input and prompt before each line. -** If isContinuation is true, then a continuation prompt is appropriate. -** If isContinuation is zero, then the main prompt should be used. +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: ** -** If zPrior is not NULL then it is a buffer from a prior call to this -** routine that can be reused. +** 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. ** -** The result is stored in space obtained from malloc() and must either -** be freed by the caller or else passed back into this routine via the -** zPrior argument for reuse. -*/ -#ifndef SQLITE_SHELL_FIDDLE -static char *one_input_line(FILE *in, char *zPrior, int isContinuation){ - char *zPrompt; - char *zResult; - if( in!=0 ){ - zResult = local_getline(zPrior, in); - }else{ - zPrompt = isContinuation ? CONTINUATION_PROMPT : mainPrompt; -#if SHELL_USE_LOCAL_GETLINE - sputz(stdout, zPrompt); - fflush(stdout); - do{ - zResult = local_getline(zPrior, stdin); - zPrior = 0; - /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */ - if( zResult==0 ) sqlite3_sleep(50); - }while( zResult==0 && seenInterrupt>0 ); -#else - free(zPrior); - zResult = shell_readline(zPrompt); - while( zResult==0 ){ - /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */ - sqlite3_sleep(50); - if( seenInterrupt==0 ) break; - zResult = shell_readline(""); - } - if( zResult && *zResult ) shell_add_history(zResult); -#endif - } - return zResult; -} -#endif /* !SQLITE_SHELL_FIDDLE */ - -/* -** Return the value of a hexadecimal digit. Return -1 if the input -** is not a hex digit. +************************************************************************* +** This file contains code to implement most of the opendir() family of +** POSIX functions on Win32 using the MSVCRT. */ -static int hexDigitValue(char c){ - if( c>='0' && c<='9' ) return c - '0'; - if( c>='a' && c<='f' ) return c - 'a' + 10; - if( c>='A' && c<='F' ) return c - 'A' + 10; - return -1; -} + +#if defined(_WIN32) && defined(_MSC_VER) +/* #include "test_windirent.h" */ /* -** Interpret zArg as an integer value, possibly with suffixes. +** Implementation of the POSIX getenv() function using the Win32 API. +** This function is not thread-safe. */ -static sqlite3_int64 integerValue(const char *zArg){ - sqlite3_int64 v = 0; - static const struct { char *zSuffix; int iMult; } aMult[] = { - { "KiB", 1024 }, - { "MiB", 1024*1024 }, - { "GiB", 1024*1024*1024 }, - { "KB", 1000 }, - { "MB", 1000000 }, - { "GB", 1000000000 }, - { "K", 1000 }, - { "M", 1000000 }, - { "G", 1000000000 }, - }; - int i; - int isNeg = 0; - if( zArg[0]=='-' ){ - isNeg = 1; - zArg++; - }else if( zArg[0]=='+' ){ - zArg++; - } - if( zArg[0]=='0' && zArg[1]=='x' ){ - int x; - zArg += 2; - while( (x = hexDigitValue(zArg[0]))>=0 ){ - v = (v<<4) + x; - zArg++; - } +const char *windirent_getenv( + const char *name +){ + static char value[32768]; /* Maximum length, per MSDN */ + DWORD dwSize = sizeof(value) / sizeof(char); /* Size in chars */ + DWORD dwRet; /* Value returned by GetEnvironmentVariableA() */ + + memset(value, 0, sizeof(value)); + dwRet = GetEnvironmentVariableA(name, value, dwSize); + if( dwRet==0 || dwRet>dwSize ){ + /* + ** The function call to GetEnvironmentVariableA() failed -OR- + ** the buffer is not large enough. Either way, return NULL. + */ + return 0; }else{ - while( IsDigit(zArg[0]) ){ - v = v*10 + zArg[0] - '0'; - zArg++; - } - } - for(i=0; iz); - initText(p); -} +LPDIR opendir( + const char *dirname +){ + struct _finddata_t data; + LPDIR dirp = (LPDIR)sqlite3_malloc(sizeof(DIR)); + SIZE_T namesize = sizeof(data.name) / sizeof(data.name[0]); -/* zIn is either a pointer to a NULL-terminated string in memory obtained -** from malloc(), or a NULL pointer. The string pointed to by zAppend is -** added to zIn, and the result returned in memory obtained from malloc(). -** zIn, if it was not NULL, is freed. -** -** If the third argument, quote, is not '\0', then it is used as a -** quote character for zAppend. -*/ -static void appendText(ShellText *p, const char *zAppend, char quote){ - i64 len; - i64 i; - i64 nAppend = strlen30(zAppend); + if( dirp==NULL ) return NULL; + memset(dirp, 0, sizeof(DIR)); - len = nAppend+p->n+1; - if( quote ){ - len += 2; - for(i=0; iz==0 || p->n+len>=p->nAlloc ){ - p->nAlloc = p->nAlloc*2 + len + 20; - p->z = realloc(p->z, p->nAlloc); - shell_check_oom(p->z); + memset(&data, 0, sizeof(struct _finddata_t)); + _snprintf(data.name, namesize, "%s\\*", dirname); + dirp->d_handle = _findfirst(data.name, &data); + + if( dirp->d_handle==BAD_INTPTR_T ){ + closedir(dirp); + return NULL; } - if( quote ){ - char *zCsr = p->z+p->n; - *zCsr++ = quote; - for(i=0; i
  • The application must not modify the SQL statement text passed into ** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running. -**
  • The application must not dereference the arrays or string pointers -** passed as the 3rd and 4th callback parameters after it returns. ** */ SQLITE_API int sqlite3_exec( @@ -843,7 +834,6 @@ SQLITE_API int 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)) @@ -879,7 +869,6 @@ SQLITE_API int 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)) @@ -1077,11 +1066,11 @@ struct sqlite3_file { ** ** 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 +** xLock() is always on 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, @@ -1492,6 +1481,7 @@ struct 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. +** ** **
  • [[SQLITE_FCNTL_EXTERNAL_READER]] ** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect @@ -1504,16 +1494,16 @@ struct 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. +** ** **
  • [[SQLITE_FCNTL_CKSM_FILE]] -** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use internally by the -** [checksum VFS shim] only. +** Used by the cksmvfs VFS module only. ** **
  • [[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. +** database is not a temp db, then this 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, it is a no-op, not an error. ** */ #define SQLITE_FCNTL_LOCKSTATE 1 @@ -1971,23 +1961,20 @@ SQLITE_API int sqlite3_os_end(void); ** must ensure that no other SQLite interfaces are invoked by other ** threads while sqlite3_config() is running. ** -** The first argument to 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 sqlite3_config() interface +** The sqlite3_config() interface ** may only be invoked prior to library initialization using ** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()]. -** The exceptional configuration options that may be invoked at any time -** are called "anytime configuration options". ** ^If sqlite3_config() is called after [sqlite3_initialize()] and before -** [sqlite3_shutdown()] with a first argument that is not an anytime -** configuration option, then the sqlite3_config() call will return SQLITE_MISUSE. +** [sqlite3_shutdown()] then it will return SQLITE_MISUSE. ** Note, however, that ^sqlite3_config() can be called as part of the ** implementation of an application-defined [sqlite3_os_init()]. ** +** The first argument to 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. +** ** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. ** ^If the option is unknown or SQLite is unable to set the option ** then this routine returns a non-zero [error code]. @@ -2095,23 +2082,6 @@ struct sqlite3_mem_methods { ** These constants are the available integer configuration options that ** can be passed as the first argument to the [sqlite3_config()] interface. ** -** Most of the configuration options for sqlite3_config() -** will only work if invoked prior to [sqlite3_initialize()] or after -** [sqlite3_shutdown()]. The few exceptions to this rule are called -** "anytime configuration options". -** ^Calling [sqlite3_config()] with a first argument that is not an -** anytime configuration option in between calls to [sqlite3_initialize()] and -** [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: -**
      -**
    • SQLITE_CONFIG_LOG -**
    • SQLITE_CONFIG_PCACHE_HDRSZ -**
    -** ** New configuration options may be added in future releases of SQLite. ** Existing configuration options might be discontinued. Applications ** should check the return code from [sqlite3_config()] to make sure that @@ -2442,7 +2412,7 @@ struct 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 behavior. +** negative value for this option restores the default behaviour. ** This option is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option. ** @@ -2456,46 +2426,30 @@ struct 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]] -**
    SQLITE_CONFIG_ROWID_IN_VIEW -**
    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. ** */ -#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ -#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ -#define SQLITE_CONFIG_SERIALIZED 3 /* nil */ -#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ -#define SQLITE_CONFIG_GETMALLOC 5 /* 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 /* sqlite3_mutex_methods* */ -#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */ -/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ -#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ -#define SQLITE_CONFIG_PCACHE 14 /* no-op */ -#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */ -#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ -#define SQLITE_CONFIG_URI 17 /* int */ -#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ -#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ +#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ +#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ +#define SQLITE_CONFIG_SERIALIZED 3 /* nil */ +#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ +#define SQLITE_CONFIG_GETMALLOC 5 /* 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 /* sqlite3_mutex_methods* */ +#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */ +/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ +#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ +#define SQLITE_CONFIG_PCACHE 14 /* no-op */ +#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */ +#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ +#define SQLITE_CONFIG_URI 17 /* int */ +#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ +#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ -#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ -#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ +#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ +#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, 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 */ @@ -2503,7 +2457,6 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ -#define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */ /* ** CAPI3REF: Database Connection Configuration Options @@ -2537,7 +2490,7 @@ struct 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 -** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero. +** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero. ** Any attempt to change the lookaside memory configuration when lookaside ** memory is in use leaves the configuration unchanged and returns ** [SQLITE_BUSY].)^
    @@ -2634,7 +2587,7 @@ struct 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 behavior. The first parameter passed to this operation +** override this behaviour. 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 @@ -2687,12 +2640,8 @@ struct sqlite3_mem_methods { **
  • sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0); ** ** 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. 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. +** process requires the use of this obscure API and multiple steps to help +** ensure that it does not happen by accident. ** ** [[SQLITE_DBCONFIG_DEFENSIVE]]
    SQLITE_DBCONFIG_DEFENSIVE
    **
    The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the @@ -2731,7 +2680,7 @@ struct sqlite3_mem_methods { **
    ** ** [[SQLITE_DBCONFIG_DQS_DML]] -**
    SQLITE_DBCONFIG_DQS_DML
    +**
    SQLITE_DBCONFIG_DQS_DML **
    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 @@ -2740,7 +2689,7 @@ struct sqlite3_mem_methods { **
    ** ** [[SQLITE_DBCONFIG_DQS_DDL]] -**
    SQLITE_DBCONFIG_DQS_DDL
    +**
    SQLITE_DBCONFIG_DQS_DDL **
    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 @@ -2749,7 +2698,7 @@ struct sqlite3_mem_methods { **
    ** ** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]] -**
    SQLITE_DBCONFIG_TRUSTED_SCHEMA
    +**
    SQLITE_DBCONFIG_TRUSTED_SCHEMA **
    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 @@ -2769,7 +2718,7 @@ struct sqlite3_mem_methods { **
    ** ** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]] -**
    SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
    +**
    SQLITE_DBCONFIG_LEGACY_FILE_FORMAT **
    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 @@ -2778,7 +2727,7 @@ struct 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 generate database files that are compatible +** is now scarcely any need to generated 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 @@ -2787,40 +2736,8 @@ struct 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 descending indexes. -**
    -** -** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]] -**
    SQLITE_DBCONFIG_STMT_SCANSTATUS
    -**
    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 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. -**
    -** -** [[SQLITE_DBCONFIG_REVERSE_SCANORDER]] -**
    SQLITE_DBCONFIG_REVERSE_SCANORDER
    -**
    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. +** either generated columns or decending indexes. **
    -** ** */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ @@ -2841,9 +2758,7 @@ struct 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_STMT_SCANSTATUS 1018 /* int int* */ -#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */ -#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */ +#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes @@ -3065,13 +2980,8 @@ SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3*); ** ^A call to 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 sqlite3_interrupt() call returns. -** -** ^The [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 sqlite3_interrupt(sqlite3*); -SQLITE_API int sqlite3_is_interrupted(sqlite3*); /* ** CAPI3REF: Determine If An SQL Statement Is Complete @@ -3618,8 +3528,8 @@ SQLITE_API int sqlite3_set_authorizer( #define SQLITE_RECURSIVE 33 /* NULL NULL */ /* -** CAPI3REF: Deprecated Tracing And Profiling Functions -** DEPRECATED +** CAPI3REF: Tracing And Profiling Functions +** METHOD: sqlite3 ** ** These routines are deprecated. Use the [sqlite3_trace_v2()] interface ** instead of the routines described here. @@ -3689,8 +3599,8 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, **
    ^An SQLITE_TRACE_PROFILE callback provides approximately the same ** information as is provided by the [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 approximately -** the number of nanoseconds that the prepared statement took to run. +** X argument points to a 64-bit integer which is the estimated of +** the number of nanosecond that the prepared statement took to run. ** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes. ** ** [[SQLITE_TRACE_ROW]]
    SQLITE_TRACE_ROW
    @@ -3722,10 +3632,8 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, ** M argument should be the bitwise OR-ed combination of ** zero or more [SQLITE_TRACE] constants. ** -** ^Each call to either sqlite3_trace(D,X,P) or sqlite3_trace_v2(D,M,X,P) -** overrides (cancels) all prior calls to sqlite3_trace(D,X,P) or -** sqlite3_trace_v2(D,M,X,P) for the [database connection] D. Each -** database connection may have at most one trace callback. +** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides +** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2(). ** ** ^The X callback is invoked whenever any of the events identified by ** mask M occur. ^The integer return value from the callback is currently @@ -3755,7 +3663,7 @@ SQLITE_API int sqlite3_trace_v2( ** ** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback ** function X to be invoked periodically during long running calls to -** [sqlite3_step()] and [sqlite3_prepare()] and similar for +** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for ** database connection D. An example use for this ** interface is to keep a GUI updated during a large query. ** @@ -3780,13 +3688,6 @@ SQLITE_API int sqlite3_trace_v2( ** Note that [sqlite3_prepare_v2()] and [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 [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 [sqlite3_prepare()] while analyzing and generating -** code for complex queries. */ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); @@ -3823,18 +3724,13 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** **
    ** ^(
    [SQLITE_OPEN_READONLY]
    -**
    The database is opened in read-only mode. If the database does -** not already exist, an error is returned.
    )^ +**
    The database is opened in read-only mode. If the database does not +** already exist, an error is returned.
    )^ ** ** ^(
    [SQLITE_OPEN_READWRITE]
    -**
    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. [sqlite3_db_readonly()] can be -** used to determine whether the database is actually -** read-write.
    )^ +**
    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.
    )^ ** ** ^(
    [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]
    **
    The database is opened for reading and writing, and is created if @@ -4094,7 +3990,7 @@ SQLITE_API int sqlite3_open_v2( ** as F) must be one of: **
      **
    • A database filename pointer created by the SQLite core and -** passed into the xOpen() method of a VFS implementation, or +** passed into the xOpen() method of a VFS implemention, or **
    • A filename obtained from [sqlite3_db_filename()], or **
    • A new filename constructed using [sqlite3_create_filename()]. **
    @@ -4207,7 +4103,7 @@ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*); /* ** CAPI3REF: Create and Destroy VFS Filenames ** -** These interfaces are provided for use by [VFS shim] implementations and +** These interfces are provided for use by [VFS shim] implementations and ** are not useful outside of that context. ** ** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of @@ -4286,17 +4182,14 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename); ** ** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language -** 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.) +** text that describes the error, as either UTF-8 or UTF-16 respectively. ** ^(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 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. +** ^The sqlite3_errstr() interface returns the English-language text +** that describes the [result code], as UTF-8. ** ^(Memory to hold the error message string is managed internally ** and must not be freed by the application)^. ** @@ -4757,41 +4650,6 @@ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); */ SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt); -/* -** CAPI3REF: Change The EXPLAIN Setting For A Prepared Statement -** METHOD: sqlite3_stmt -** -** The 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 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 -** sqlite3_stmt_explain(S,E) will fail with SQLITE_ERROR if S cannot be -** reprepared because it was created using [sqlite3_prepare()] instead of -** the newer [sqlite3_prepare_v2()] or [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 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 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 [sqlite3_reset(S)] -** immediately prior to calling sqlite3_stmt_explain(S,E). -*/ -SQLITE_API int sqlite3_stmt_explain(sqlite3_stmt *pStmt, int eMode); - /* ** CAPI3REF: Determine If A Prepared Statement Has Been Reset ** METHOD: sqlite3_stmt @@ -4955,7 +4813,7 @@ typedef struct sqlite3_context 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 passed to indicate that +** ^ (2) The special constant, [SQLITE_STATIC], may be passsed 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 @@ -5634,33 +5492,20 @@ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt); ** ^The [sqlite3_reset(S)] interface resets the [prepared statement] S ** back to the beginning of its program. ** -** ^The return code from [sqlite3_reset(S)] indicates whether or not -** the previous evaluation of prepared statement S completed successfully. -** ^If [sqlite3_step(S)] has never before been called on S or if -** [sqlite3_step(S)] has not been called since the previous call -** to [sqlite3_reset(S)], then [sqlite3_reset(S)] will return -** [SQLITE_OK]. +** ^If the most recent call to [sqlite3_step(S)] for the +** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE], +** or if [sqlite3_step(S)] has never before been called on S, +** then [sqlite3_reset(S)] returns [SQLITE_OK]. ** ** ^If the most recent call to [sqlite3_step(S)] for the ** [prepared statement] S indicated an error, then ** [sqlite3_reset(S)] returns an appropriate [error code]. -** ^The [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 [sqlite3_step(S)] might return SQLITE_ROW but -** the overall statement might still fail and the [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 [sqlite3_reset(S)] even if -** no prior call to [sqlite3_step(S)] indicated a problem. ** ** ^The [sqlite3_reset(S)] interface does not change the values ** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S. */ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); - /* ** CAPI3REF: Create Or Redefine SQL Functions ** KEYWORDS: {function creation routines} @@ -5866,21 +5711,10 @@ SQLITE_API int 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 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. -**

    -** 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. +** 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. **

    ** ** [[SQLITE_INNOCUOUS]]
    SQLITE_INNOCUOUS
    @@ -5907,27 +5741,13 @@ SQLITE_API int sqlite3_create_window_function( **
    ** ** [[SQLITE_SUBTYPE]]
    SQLITE_SUBTYPE
    -** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call +** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call ** [sqlite3_value_subtype()] to inspect the sub-types of its arguments. -** This flag instructs SQLite to omit some corner-case optimizations that -** might disrupt the operation of the [sqlite3_value_subtype()] function, -** causing it to return zero rather than the correct subtype(). -** SQL functions that invokes [sqlite3_value_subtype()] should have this -** property. If the SQLITE_SUBTYPE property is omitted, then the return -** value from [sqlite3_value_subtype()] might sometimes be zero even though -** a non-zero subtype was specified by the function argument expression. -** -** [[SQLITE_RESULT_SUBTYPE]]
    SQLITE_RESULT_SUBTYPE
    -** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call -** [sqlite3_result_subtype()] to cause a sub-type to be associated with its -** result. -** Every function that invokes [sqlite3_result_subtype()] should have this -** property. If it does not, then the call to [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 -** [sqlite3_result_subtype()] should avoid setting this property, as the -** purpose of this property is to disable certain optimizations that are -** incompatible with subtypes. +** 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. +** sqlite3_value_subtype() will always return 0). **
    **
    */ @@ -5935,7 +5755,6 @@ SQLITE_API int sqlite3_create_window_function( #define SQLITE_DIRECTONLY 0x000080000 #define SQLITE_SUBTYPE 0x000100000 #define SQLITE_INNOCUOUS 0x000200000 -#define SQLITE_RESULT_SUBTYPE 0x001000000 /* ** CAPI3REF: Deprecated Functions @@ -6036,6 +5855,16 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** then the conversion is performed. Otherwise no conversion occurs. ** The [SQLITE_INTEGER | datatype] after conversion is returned.)^ ** +** ^(The sqlite3_value_encoding(X) interface returns one of [SQLITE_UTF8], +** [SQLITE_UTF16BE], or [SQLITE_UTF16LE] according to the current encoding +** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X) +** returns something other than SQLITE_TEXT, then the return value from +** sqlite3_value_encoding(X) is meaningless. ^Calls to +** sqlite3_value_text(X), sqlite3_value_text16(X), sqlite3_value_text16be(X), +** sqlite3_value_text16le(X), sqlite3_value_bytes(X), or +** sqlite3_value_bytes16(X) might change the encoding of the value X and +** thus change the return from subsequent calls to sqlite3_value_encoding(X). +** ** ^Within the [xUpdate] method of a [virtual table], the ** sqlite3_value_nochange(X) interface returns true if and only if ** the column corresponding to X is unchanged by the UPDATE operation @@ -6100,27 +5929,6 @@ SQLITE_API int sqlite3_value_type(sqlite3_value*); SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); SQLITE_API int sqlite3_value_nochange(sqlite3_value*); SQLITE_API int sqlite3_value_frombind(sqlite3_value*); - -/* -** CAPI3REF: Report the internal text encoding state of an sqlite3_value object -** METHOD: sqlite3_value -** -** ^(The 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 sqlite3_value_type(X) -** returns something other than SQLITE_TEXT, then the return value from -** sqlite3_value_encoding(X) is meaningless. ^Calls to -** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], [sqlite3_value_text16be(X)], -** [sqlite3_value_text16le(X)], [sqlite3_value_bytes(X)], or -** [sqlite3_value_bytes16(X)] might change the encoding of the value X and -** thus change the return from subsequent calls to 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 [sqlite3_value] object. Ordinary applications should -** not need to know what the internal state of an sqlite3_value object is and -** hence should not need to use this interface. -*/ SQLITE_API int sqlite3_value_encoding(sqlite3_value*); /* @@ -6132,12 +5940,6 @@ SQLITE_API int sqlite3_value_encoding(sqlite3_value*); ** information can be used to pass a limited amount of context from ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. -** -** Every [application-defined SQL function] that invoke this interface -** should include the [SQLITE_SUBTYPE] property in the text -** encoding argument when the function is [sqlite3_create_function|registered]. -** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype() -** might return zero instead of the upstream subtype in some corner cases. */ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); @@ -6236,56 +6038,48 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** METHOD: sqlite3_context ** ** These functions may be used by (non-aggregate) SQL functions to -** 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. +** 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. ** 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 sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data +** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata ** associated by the 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 auxiliary data +** function argument. ^If there is no metadata ** associated with the function argument, the sqlite3_get_auxdata(C,N) interface ** returns a NULL pointer. ** -** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the -** N-th argument of the application-defined function. ^Subsequent +** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th +** argument of the application-defined function. ^Subsequent ** calls to sqlite3_get_auxdata(C,N) return P from the most recent -** sqlite3_set_auxdata(C,N,P,X) call if the auxiliary data is still valid or -** NULL if the auxiliary data has been discarded. +** sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or +** NULL if the metadata has been discarded. ** ^After each call to 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 auxiliary data is discarded. -** SQLite is free to discard the auxiliary data at any time, including:
      +** once, when the metadata is discarded. +** SQLite is free to discard the metadata at any time, including:
        **
      • ^(when the corresponding function parameter changes)^, or **
      • ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the ** SQL statement)^, or **
      • ^(when sqlite3_set_auxdata() is invoked again on the same ** parameter)^, or **
      • ^(during the original sqlite3_set_auxdata() call when a memory -** allocation error occurs.)^ -**
      • ^(during the original sqlite3_set_auxdata() call if the function -** is evaluated during query planning instead of during query execution, -** as sometimes happens with [SQLITE_ENABLE_STAT4].)^
      +** allocation error occurs.)^
    ** -** Note the last two bullets in particular. The destructor X in +** Note the last bullet in particular. The destructor X in ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the ** sqlite3_set_auxdata() interface even returns. Hence 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 -** sqlite3_set_auxdata() has been called. Furthermore, a call to -** sqlite3_get_auxdata() that occurs immediately after a corresponding call -** to sqlite3_set_auxdata() might still return NULL if an out-of-memory -** condition occurred during the 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 +** sqlite3_set_auxdata() has been called. +** +** ^(In practice, metadata is preserved between function calls for ** function parameters that are compile-time constants, including literal ** values and [parameters] and expressions composed from the same.)^ ** @@ -6295,67 +6089,10 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** ** These routines must be called from the same thread in which ** the SQL function is running. -** -** See also: [sqlite3_get_clientdata()] and [sqlite3_set_clientdata()]. */ SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N); SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); -/* -** CAPI3REF: Database Connection Client Data -** METHOD: sqlite3 -** -** These functions are used to associate one or more named pointers -** with a [database connection]. -** A call to sqlite3_set_clientdata(D,N,P,X) causes the pointer P -** to be attached to [database connection] D using name N. Subsequent -** calls to sqlite3_get_clientdata(D,N) will return a copy of pointer P -** or a NULL pointer if there were no prior calls to -** 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: -**
      -**
    • An out-of-memory error occurs during the call to -** sqlite3_set_clientdata() which attempts to register pointer P. -**
    • A subsequent call to sqlite3_set_clientdata(D,N,P,X) is made -** with the same D and N parameters. -**
    • 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. -**
    -** -** 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: [sqlite3_set_auxdata()] and [sqlite3_get_auxdata()]. -*/ -SQLITE_API void *sqlite3_get_clientdata(sqlite3*,const char*); -SQLITE_API int sqlite3_set_clientdata(sqlite3*, const char*, void*, void(*)(void*)); /* ** CAPI3REF: Constants Defining Special Destructor Behavior @@ -6557,20 +6294,6 @@ SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); ** 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 -** [sqlite3_create_function|registered]. If the [SQLITE_RESULT_SUBTYPE] -** property is omitted from the function that invokes sqlite3_result_subtype(), -** then in some cases the 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 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 sqlite3_result_subtype(sqlite3_context*,unsigned int); @@ -6742,13 +6465,6 @@ SQLITE_API void sqlite3_activate_cerod( ** of the default VFS is not implemented correctly, or not implemented at ** all, then the behavior of sqlite3_sleep() may deviate from the description ** in the previous paragraphs. -** -** If a negative argument is passed to 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 sqlite3_sleep() is changed to zero before it is relayed -** down into the xSleep method of the VFS. */ SQLITE_API int sqlite3_sleep(int); @@ -7002,7 +6718,7 @@ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema); /* -** CAPI3REF: Allowed return values from sqlite3_txn_state() +** CAPI3REF: Allowed return values from [sqlite3_txn_state()] ** KEYWORDS: {transaction state} ** ** These constants define the current transaction state of a database file. @@ -7134,7 +6850,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); ** ^Each call to the sqlite3_autovacuum_pages() interface overrides all ** previous invocations for that database connection. ^If the callback ** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer, -** then the autovacuum steps callback is canceled. The return value +** then the autovacuum steps callback is cancelled. The return value ** from 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 @@ -7200,12 +6916,6 @@ SQLITE_API int 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 @@ -7599,6 +7309,15 @@ SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void)); */ SQLITE_API void 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 */ @@ -7659,10 +7378,6 @@ struct 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)(sqlite3_vtab *pVTab, const char *zSchema, - const char *zTabName, int mFlags, char **pzErr); }; /* @@ -7721,10 +7436,10 @@ struct 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 idxStr values are recorded and passed into the +** ^The idxNum and idxPtr values are recorded and passed into the ** [xFilter] method. -** ^[sqlite3_free()] is used to free idxStr if and only if -** needToFreeIdxStr is true. +** ^[sqlite3_free()] is used to free idxPtr if and only if +** needToFreeIdxPtr 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 @@ -7844,7 +7559,7 @@ struct sqlite3_index_info { ** the [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 sqlite3_vtab_collation() -** interface is not commonly needed. +** interface is no commonly needed. */ #define SQLITE_INDEX_CONSTRAINT_EQ 2 #define SQLITE_INDEX_CONSTRAINT_GT 4 @@ -8003,6 +7718,16 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL); */ SQLITE_API int sqlite3_overload_function(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} @@ -8150,7 +7875,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, 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 behavior. ^Calling this routine +** open blob handle results in undefined behaviour. ^Calling this routine ** with a null pointer (such as would be returned by a failed call to ** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function ** is passed a valid open blob handle, the values returned by the @@ -8377,20 +8102,18 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); ** ** ^(Some systems (for example, Windows 95) do not support the operation ** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() -** will always return SQLITE_BUSY. In most cases the SQLite core only uses -** 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 -** sqlite3_mutex_try() is required.)^ +** will always return SQLITE_BUSY. The SQLite core only ever uses +** sqlite3_mutex_try() as an optimization so this is acceptable +** behavior.)^ ** ** ^The 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 sqlite3_mutex_enter(), sqlite3_mutex_try(), -** sqlite3_mutex_leave(), or sqlite3_mutex_free() is a NULL pointer, -** then any of the four routines behaves as a no-op. +** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or +** sqlite3_mutex_leave() is a NULL pointer, then all three routines +** behave as no-ops. ** ** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()]. */ @@ -8632,7 +8355,6 @@ SQLITE_API int 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 @@ -8640,7 +8362,6 @@ SQLITE_API int 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 */ @@ -8662,8 +8383,7 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_TRACEFLAGS 31 #define SQLITE_TESTCTRL_TUNE 32 #define SQLITE_TESTCTRL_LOGEST 33 -#define SQLITE_TESTCTRL_USELONGDOUBLE 34 -#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */ +#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking @@ -8676,7 +8396,7 @@ SQLITE_API int sqlite3_test_control(int op, ...); ** The sqlite3_keyword_count() interface returns the number of distinct ** keywords understood by SQLite. ** -** The sqlite3_keyword_name(N,Z,L) interface finds the 0-based N-th keyword and +** The sqlite3_keyword_name(N,Z,L) interface finds the 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 sqlite3_keyword_name(N,Z,L) routine returns @@ -10119,7 +9839,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); ** [[SQLITE_VTAB_DIRECTONLY]]
    SQLITE_VTAB_DIRECTONLY
    **
    Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the -** the [xConnect] or [xCreate] methods of a [virtual table] implementation +** the [xConnect] or [xCreate] methods of a [virtual table] implmentation ** prohibits that virtual table from being used from within triggers and ** views. **
    @@ -10127,28 +9847,18 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); ** [[SQLITE_VTAB_INNOCUOUS]]
    SQLITE_VTAB_INNOCUOUS
    **
    Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the -** the [xConnect] or [xCreate] methods of a [virtual table] implementation +** the [xConnect] or [xCreate] methods of a [virtual table] implmentation ** 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. **
    -** -** [[SQLITE_VTAB_USES_ALL_SCHEMAS]]
    SQLITE_VTAB_USES_ALL_SCHEMAS
    -**
    Calls of the form -** [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. -**
    ** */ #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 @@ -10221,7 +9931,7 @@ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*); **
  • Otherwise, "BINARY" is returned. ** */ -SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); +SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int); /* ** CAPI3REF: Determine if a virtual table query is DISTINCT @@ -10255,45 +9965,24 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); **

  • ** ^(If the 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 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. +** 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. ** This mode is used for a DISTINCT query. **

  • -** ^(If the sqlite3_vtab_distinct() interface returns 3, that means the -** virtual table must return rows in the order defined by "aOrderBy" as -** if the 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 +** ^(If the 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 ** that have both DISTINCT and ORDER BY clauses. ** ** -**

    The following table summarizes the conditions under which the -** virtual table is allowed to set the "orderByConsumed" flag based on -** the value returned by sqlite3_vtab_distinct(). This table is a -** restatement of the previous four paragraphs: -** -** -** -**
    sqlite3_vtab_distinct() return value -** Rows are returned in aOrderBy order -** Rows with the same value in all aOrderBy columns are adjacent -** Duplicates over all colUsed columns may be omitted -**
    0yesyesno -**
    1noyesno -**
    2noyesyes -**
    3yesyesyes -**
    -** ** ^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" @@ -10330,7 +10019,7 @@ SQLITE_API int sqlite3_vtab_distinct(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 positive integer. ^(Then, under +** aConstraintUsage[].argvIndex to a postive 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 @@ -10399,20 +10088,21 @@ SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle); ** is undefined and probably harmful. ** ** The X parameter in a call to sqlite3_vtab_in_first(X,P) or -** sqlite3_vtab_in_next(X,P) should be one of the parameters to the +** sqlite3_vtab_in_next(X,P) must 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 [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_ERROR].)^ +** processing, then these routines return [SQLITE_MISUSE])^ or perhaps +** exhibit some other undefined or harmful behavior. ** ** ^(Use these routines to access all values on the right-hand side ** of the IN constraint using code like the following: ** **

     **    for(rc=sqlite3_vtab_in_first(pList, &pVal);
    -**        rc==SQLITE_OK && pVal;
    +**        rc==SQLITE_OK && pVal
     **        rc=sqlite3_vtab_in_next(pList, &pVal)
     **    ){
     **      // do something with pVal
    @@ -10510,10 +10200,6 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **
     ** 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).
    -**
     ** 
    ** [[SQLITE_SCANSTAT_NLOOP]]
    SQLITE_SCANSTAT_NLOOP
    **
    ^The [sqlite3_int64] variable pointed to by the V parameter will be @@ -10541,24 +10227,12 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN] ** description for the X-th loop. ** -** [[SQLITE_SCANSTAT_SELECTID]]
    SQLITE_SCANSTAT_SELECTID
    +** [[SQLITE_SCANSTAT_SELECTID]]
    SQLITE_SCANSTAT_SELECT
    **
    ^The "int" variable pointed to by the V parameter will be set to the -** 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]]
    SQLITE_SCANSTAT_PARENTID
    -**
    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]]
    SQLITE_SCANSTAT_NCYCLE
    -**
    The 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. +** "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. **
    */ #define SQLITE_SCANSTAT_NLOOP 0 @@ -10567,14 +10241,12 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** #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: sqlite3_stmt ** -** These interfaces return information about the predicted and measured +** This interface returns 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. @@ -10585,25 +10257,19 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** ** 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. -** -** 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 -** sqlite3_stmt_scanstatus() is equivalent to calling -** 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. +** 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. ** ** See also: [sqlite3_stmt_scanstatus_reset()] */ @@ -10613,19 +10279,6 @@ SQLITE_API int sqlite3_stmt_scanstatus( int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ void *pOut /* Result written here */ ); -SQLITE_API int sqlite3_stmt_scanstatus_v2( - 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 @@ -10716,10 +10369,6 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); ** function is not defined for operations on WITHOUT ROWID tables, or for ** DELETE operations on rowid tables. ** -** ^The 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 [sqlite3_preupdate_old()], [sqlite3_preupdate_new()], ** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces ** provide additional information about a preupdate event. These routines @@ -10759,7 +10408,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); ** When the [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 actually a write using the +** callback made with op==SQLITE_DELETE is actuall a write using the ** sqlite3_blob_write() API, the [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 @@ -11020,13 +10669,6 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const 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 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. @@ -11075,9 +10717,6 @@ SQLITE_API unsigned char *sqlite3_serialize( ** SQLite will try to increase the buffer size using 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 sqlite3_deserialize() interface will fail with SQLITE_BUSY if the ** database is currently in a read transaction or is involved in a backup ** operation. @@ -11086,13 +10725,6 @@ SQLITE_API unsigned char *sqlite3_serialize( ** S argument to 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 sqlite3_deserialize(D,S,P,N,M,F) to force the -** database file into rollback mode and work around this limitation. -** ** If 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 ** [sqlite3_free()] is invoked on argument P prior to returning. @@ -11142,19 +10774,6 @@ SQLITE_API int 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 @@ -11361,20 +10980,16 @@ SQLITE_API int sqlite3session_create( SQLITE_API void sqlite3session_delete(sqlite3_session *pSession); /* -** CAPI3REF: Configure a Session Object +** CAPIREF: Conigure a Session Object ** METHOD: sqlite3_session ** ** This method is used to configure a session object after it has been -** created. At present the only valid values for the second parameter are -** [SQLITE_SESSION_OBJCONFIG_SIZE] and [SQLITE_SESSION_OBJCONFIG_ROWID]. +** created. At present the only valid value for the second parameter is +** [SQLITE_SESSION_OBJCONFIG_SIZE]. ** -*/ -SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg); - -/* -** CAPI3REF: Options for sqlite3session_object_config +** Arguments for sqlite3session_object_config() ** -** The following values may passed as the the 2nd parameter to +** The following values may passed as the the 4th parameter to ** sqlite3session_object_config(). ** **
    SQLITE_SESSION_OBJCONFIG_SIZE
    @@ -11390,21 +11005,12 @@ SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg ** ** It is an error (SQLITE_MISUSE) to attempt to modify this setting after ** the first table has been attached to the session object. -** -**
    SQLITE_SESSION_OBJCONFIG_ROWID
    -** 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. */ -#define SQLITE_SESSION_OBJCONFIG_SIZE 1 -#define SQLITE_SESSION_OBJCONFIG_ROWID 2 +SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg); + +/* +*/ +#define SQLITE_SESSION_OBJCONFIG_SIZE 1 /* ** CAPI3REF: Enable Or Disable A Session Object @@ -12165,18 +11771,6 @@ SQLITE_API int sqlite3changeset_concat( ); -/* -** CAPI3REF: Upgrade the Schema of a Changeset/Patchset -*/ -SQLITE_API int sqlite3changeset_upgrade( - sqlite3 *db, - const char *zDb, - int nIn, const void *pIn, /* Input changeset */ - int *pnOut, void **ppOut /* OUT: Inverse of input */ -); - - - /* ** CAPI3REF: Changegroup Handle ** @@ -12223,38 +11817,6 @@ typedef struct sqlite3_changegroup sqlite3_changegroup; */ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp); -/* -** CAPI3REF: Add a Schema to a Changegroup -** METHOD: 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 -** 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 sqlite3changeset_apply(). Specifically, for each -** table in the changeset, there exists a database table with: -** -**
      -**
    • The name identified by the changeset, and -**
    • at least as many columns as recorded in the changeset, and -**
    • the primary key columns in the same position as recorded in -** the changeset. -**
    -** -** The output of the changegroup object always has the same schema as the -** database nominated using this function. In cases where changesets passed -** to 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 sqlite3changegroup_schema(sqlite3_changegroup*, sqlite3*, const char *zDb); - /* ** CAPI3REF: Add A Changeset To A Changegroup ** METHOD: sqlite3_changegroup @@ -12323,45 +11885,16 @@ SQLITE_API int sqlite3changegroup_schema(sqlite3_changegroup*, sqlite3*, const c ** 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. Except, if the changegroup -** object has been configured with a database schema using the -** 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. +** 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. ** -** 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. +** If no error occurs, SQLITE_OK is returned. */ SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); -/* -** CAPI3REF: Add A Single Change To A Changegroup -** METHOD: 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 [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 sqlite3changegroup_add_change( - sqlite3_changegroup*, - sqlite3_changeset_iter* -); - - - /* ** CAPI3REF: Obtain A Composite Changeset From A Changegroup ** METHOD: sqlite3_changegroup @@ -12610,30 +12143,9 @@ SQLITE_API int sqlite3changeset_apply_v2( ** Invert the changeset before applying it. This is equivalent to inverting ** a changeset using sqlite3changeset_invert() before applying it. It is ** an error to specify this flag with a patchset. -** -**
    SQLITE_CHANGESETAPPLY_IGNORENOOP
    -** 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: -**
      -**
    • a delete change if the row being deleted cannot be found, -**
    • an update change if the modified fields are already set to -** their new values in the conflicting row, or -**
    • an insert change if all fields of the conflicting row match -** the row being inserted. -**
    -** -**
    SQLITE_CHANGESETAPPLY_FKNOACTION
    -** 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 @@ -13166,8 +12678,8 @@ struct Fts5PhraseIter { ** EXTENSION API FUNCTIONS ** ** xUserData(pFts): -** Return a copy of the pUserData pointer passed to the xCreateFunction() -** API when the extension function was registered. +** Return a copy of the context pointer the extension function was +** registered with. ** ** xColumnTotalSize(pFts, iCol, pnToken): ** If parameter iCol is less than zero, set output variable *pnToken @@ -13199,11 +12711,8 @@ struct Fts5PhraseIter { ** created with the "columnsize=0" option. ** ** xColumnText: -** 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 +** 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 @@ -13213,10 +12722,8 @@ struct Fts5PhraseIter { ** Returns the number of phrases in the current query expression. ** ** xPhraseSize: -** 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. +** 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 @@ -13232,13 +12739,12 @@ 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(). If iIdx is less than zero or greater than -** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned. +** output by xInstCount(). ** -** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol +** Usually, output parameter *piPhrase is set to the phrase number, *piCol ** to the column in which it occurs and *piOff the token offset of the -** first token of the phrase. SQLITE_OK is returned if successful, or an -** error code (i.e. SQLITE_NOMEM) if an error occurs. +** first token of the phrase. Returns SQLITE_OK if successful, or an error +** code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. @@ -13264,10 +12770,6 @@ 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. @@ -13382,39 +12884,6 @@ 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 */ @@ -13452,13 +12921,6 @@ 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*); }; /* @@ -13653,8 +13115,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 (3)) or query -** text (method (2)), not both. Doing so will not cause any errors, but is +** provide synonyms when tokenizing document text (method (2)) or query +** text (method (3)), not both. Doing so will not cause any errors, but is ** inefficient. */ typedef struct Fts5Tokenizer Fts5Tokenizer; @@ -13702,7 +13164,7 @@ struct fts5_api { int (*xCreateTokenizer)( fts5_api *pApi, const char *zName, - void *pUserData, + void *pContext, fts5_tokenizer *pTokenizer, void (*xDestroy)(void*) ); @@ -13711,7 +13173,7 @@ struct fts5_api { int (*xFindTokenizer)( fts5_api *pApi, const char *zName, - void **ppUserData, + void **ppContext, fts5_tokenizer *pTokenizer ); @@ -13719,7 +13181,7 @@ struct fts5_api { int (*xCreateFunction)( fts5_api *pApi, const char *zName, - void *pUserData, + void *pContext, fts5_extension_function xFunction, void (*xDestroy)(void*) ); @@ -13830,7 +13292,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 compound SELECT. +** any limit on the number of terms in a compount SELECT. */ #ifndef SQLITE_MAX_COMPOUND_SELECT # define SQLITE_MAX_COMPOUND_SELECT 500 @@ -13945,7 +13407,7 @@ struct fts5_api { ** max_page_count macro. */ #ifndef SQLITE_MAX_PAGE_COUNT -# define SQLITE_MAX_PAGE_COUNT 0xfffffffe /* 4294967294 */ +# define SQLITE_MAX_PAGE_COUNT 1073741823 #endif /* @@ -13980,8 +13442,8 @@ struct fts5_api { #endif /* -** A few places in the code require atomic load/store of aligned -** integer values. +** WAL mode depends on atomic aligned 32-bit loads and stores in a few +** places. The following macros try to make this explicit. */ #ifndef __has_extension # define __has_extension(x) 0 /* compatibility with non-clang compilers */ @@ -14037,22 +13499,15 @@ struct fts5_api { #endif /* -** Macros to hint to the compiler that a function should or should not be +** A macro to hint to the compiler that a function 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 /* @@ -14074,29 +13529,6 @@ struct fts5_api { # endif #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 @@ -14365,8 +13797,6 @@ 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() @@ -14659,8 +14089,8 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #define TK_TRUEFALSE 170 #define TK_ISNOT 171 #define TK_FUNCTION 172 -#define TK_UPLUS 173 -#define TK_UMINUS 174 +#define TK_UMINUS 173 +#define TK_UPLUS 174 #define TK_TRUTH 175 #define TK_REGISTER 176 #define TK_VECTOR 177 @@ -14669,9 +14099,8 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #define TK_ASTERISK 180 #define TK_SPAN 181 #define TK_ERROR 182 -#define TK_QNUMBER 183 -#define TK_SPACE 184 -#define TK_ILLEGAL 185 +#define TK_SPACE 183 +#define TK_ILLEGAL 184 /************** End of parse.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ @@ -14896,9 +14325,15 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */ /* ** The datatype used to store estimates of the number of rows in a -** table or index. +** 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. */ -typedef u64 tRowcnt; +#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 /* ** Estimated quantities used for query planning are stored as 16-bit @@ -14933,7 +14368,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(__ppc__)) || \ + (defined(__APPLE__) && defined(__POWERPC__)) || \ (defined(__TOS_AIX__) && !defined(__64BIT__)) # define SQLITE_PTRSIZE 4 # else @@ -14959,31 +14394,8 @@ 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, @@ -14993,33 +14405,16 @@ 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 /* 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) || \ +#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(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64) -# define SQLITE_BYTEORDER 1234 -# elif defined(sparc) || defined(__ARMEB__) || defined(__AARCH64EB__) -# define SQLITE_BYTEORDER 4321 +# define SQLITE_BYTEORDER 1234 +# elif defined(sparc) || defined(__ppc__) || \ + defined(__ARMEB__) || defined(__AARCH64EB__) +# define SQLITE_BYTEORDER 4321 # else # define SQLITE_BYTEORDER 0 # endif @@ -15084,9 +14479,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) ((((uptr)(X) - (uptr)0)&3)==0) +# define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&3)==0) #else -# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0) +# define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&7)==0) #endif /* @@ -15140,39 +14535,15 @@ SQLITE_PRIVATE u32 sqlite3TreeTrace; && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_SELECTTRACE) \ || defined(SQLITE_ENABLE_TREETRACE)) # define TREETRACE_ENABLED 1 -# define TREETRACE(K,P,S,X) \ +# define SELECTTRACE(K,P,S,X) \ if(sqlite3TreeTrace&(K)) \ sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\ sqlite3DebugPrintf X #else -# define TREETRACE(K,P,S,X) +# define SELECTTRACE(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" */ @@ -15185,36 +14556,6 @@ SQLITE_PRIVATE u32 sqlite3WhereTrace; # define WHERETRACE(K,X) #endif -/* -** Bits for the 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 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 @@ -15235,7 +14576,7 @@ struct BusyHandler { /* ** Name of table that holds the database schema. ** -** The PREFERRED names are used wherever possible. But LEGACY is also +** The PREFERRED names are used whereever possible. But LEGACY is also ** used for backwards compatibility. ** ** 1. Queries can use either the PREFERRED or the LEGACY names @@ -15344,13 +14685,11 @@ 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; @@ -15369,7 +14708,6 @@ 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; @@ -15983,7 +15321,7 @@ SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*); SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*); SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*); SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*); -SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, u64*); +SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *); SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*); SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *); @@ -16007,10 +15345,6 @@ SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*); # define enable_simulated_io_errors() #endif -#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL) -SQLITE_PRIVATE int sqlite3PagerWalSystemErrno(Pager*); -#endif - #endif /* SQLITE_PAGER_H */ /************** End of pager.h ***********************************************/ @@ -16202,7 +15536,7 @@ SQLITE_PRIVATE int 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 extensions that use +** standard SQLite. The other hints are provided for extentions that use ** the SQLite parser and code generator but substitute their own storage ** engine. */ @@ -16340,22 +15674,15 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int flags); SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeCursorPin(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeCursorUnpin(BtCursor*); +#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor*); +#endif SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*); SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt); SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*); SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*); -SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( - 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 */ - 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 char *sqlite3BtreeIntegrityCheck(sqlite3*,Btree*,Pgno*aRoot,int nRoot,int,int*); SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*); SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor*); @@ -16512,14 +15839,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; @@ -16571,7 +15898,6 @@ 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 sqlite3_context object */ -#define P4_TABLEREF (-16) /* Like P4_TABLE, but reference counted */ /* Error message codes for OP_Halt */ #define P5_ConstraintNotNull 1 @@ -16621,12 +15947,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 /* jump0, synopsis: Start at P2 */ +#define OP_Init 8 /* jump, 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_InitCoroutine 11 /* jump */ +#define OP_Yield 12 /* jump */ +#define OP_MustBeInt 13 /* jump */ #define OP_Jump 14 /* jump */ #define OP_Once 15 /* jump */ #define OP_If 16 /* jump */ @@ -16634,22 +15960,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 /* 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_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_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_SeekRowid 30 /* jump, 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_Last 32 /* jump */ +#define OP_IfSmaller 33 /* jump */ #define OP_SorterSort 34 /* jump */ #define OP_Sort 35 /* jump */ -#define OP_Rewind 36 /* jump0 */ +#define OP_Rewind 36 /* jump */ #define OP_SorterNext 37 /* jump */ #define OP_Prev 38 /* jump */ #define OP_Next 39 /* jump */ @@ -16661,7 +15987,7 @@ 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 /* jump0 */ +#define OP_Program 48 /* jump */ #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 */ @@ -16691,7 +16017,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) */ +#define OP_Variable 78 /* synopsis: r[P2]=parameter(P1,P4) */ #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] */ @@ -16787,22 +16113,19 @@ typedef struct VdbeOpList VdbeOpList; #define OP_VCreate 171 #define OP_VDestroy 172 #define OP_VOpen 173 -#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 +#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 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c @@ -16814,33 +16137,31 @@ 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, 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,\ +/* 0 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,\ +/* 8 */ 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01,\ +/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x09, 0x09, 0x09,\ +/* 24 */ 0x09, 0x01, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,\ +/* 32 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\ +/* 40 */ 0x01, 0x01, 0x01, 0x26, 0x26, 0x01, 0x23, 0x0b,\ +/* 48 */ 0x01, 0x01, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\ +/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x03, 0x01, 0x01,\ /* 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,\ +/* 88 */ 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20, 0x00, 0x00,\ +/* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x26, 0x26,\ /* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\ -/* 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,\ +/* 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,\ /* 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, 0x40, 0x10, 0x50,\ -/* 176 */ 0x40, 0x00, 0x10, 0x10, 0x02, 0x12, 0x12, 0x00,\ -/* 184 */ 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,} /* The resolve3P2Values() routine is able to run faster if it knows ** the value of the largest JUMP opcode. The smaller the maximum @@ -16893,20 +16214,14 @@ SQLITE_PRIVATE void sqlite3VdbeNoJumpsOutsideSubrtn(Vdbe*,int,int,int); #endif SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno); #ifndef SQLITE_OMIT_EXPLAIN -SQLITE_PRIVATE int sqlite3VdbeExplain(Parse*,u8,const char*,...); +SQLITE_PRIVATE void sqlite3VdbeExplain(Parse*,u8,const char*,...); SQLITE_PRIVATE void sqlite3VdbeExplainPop(Parse*); SQLITE_PRIVATE int sqlite3VdbeExplainParent(Parse*); # define ExplainQueryPlan(P) sqlite3VdbeExplain P -# ifdef SQLITE_ENABLE_STMT_SCANSTATUS -# define ExplainQueryPlan2(V,P) (V = sqlite3VdbeExplain P) -# else -# define ExplainQueryPlan2(V,P) ExplainQueryPlan(P) -# endif # define ExplainQueryPlanPop(P) sqlite3VdbeExplainPop(P) # define ExplainQueryPlanParent(P) sqlite3VdbeExplainParent(P) #else # define ExplainQueryPlan(P) -# define ExplainQueryPlan2(V,P) # define ExplainQueryPlanPop(P) # define ExplainQueryPlanParent(P) 0 # define sqlite3ExplainBreakpoint(A,B) /*no-op*/ @@ -16983,8 +16298,6 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); SQLITE_PRIVATE int sqlite3VdbeHasSubProgram(Vdbe*); -SQLITE_PRIVATE void sqlite3MemSetArrayInt64(sqlite3_value *aMem, int iIdx, i64 val); - SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context*); #ifdef SQLITE_ENABLE_BYTECODE_VTAB SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3*); @@ -17017,7 +16330,7 @@ SQLITE_PRIVATE void 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 sqlite3.c source file. VDBE branch coverage testing -** only works with an amalgamation build. That's ok since a VDBE branch +** only works with an amalagmation 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. ** @@ -17035,7 +16348,7 @@ SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe*, const char*, ...); ** // NULL option is not possible ** ** VdbeCoverageEqNe(v) // Previous OP_Jump is only interested -** // in distinguishing equal and not-equal. +** // in distingishing 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 @@ -17045,7 +16358,7 @@ SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe*, const char*, ...); ** During testing, the test application will invoke ** 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 sqlite3.c source line number of the VdbeCoverage macro and +** contains the sqlite3.c source line number ov 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. @@ -17081,22 +16394,14 @@ SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe*,int); #ifdef SQLITE_ENABLE_STMT_SCANSTATUS SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*); -SQLITE_PRIVATE void sqlite3VdbeScanStatusRange(Vdbe*, int, int, int); -SQLITE_PRIVATE void sqlite3VdbeScanStatusCounters(Vdbe*, int, int, int); #else -# define sqlite3VdbeScanStatus(a,b,c,d,e,f) -# define sqlite3VdbeScanStatusRange(a,b,c,d) -# define sqlite3VdbeScanStatusCounters(a,b,c,d) +# define sqlite3VdbeScanStatus(a,b,c,d,e) #endif #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, VdbeOp*); #endif -#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG) -SQLITE_PRIVATE int sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr); -#endif - #endif /* SQLITE_VDBE_H */ /************** End of vdbe.h ************************************************/ @@ -17145,7 +16450,7 @@ struct PgHdr { ** private to pcache.c and should not be accessed by other modules. ** pCache is grouped with the public elements for efficiency. */ - i64 nRef; /* Number of users of this page */ + i16 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 @@ -17226,12 +16531,12 @@ SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *); SQLITE_PRIVATE void sqlite3PcacheClear(PCache*); /* Return the total number of outstanding page references */ -SQLITE_PRIVATE i64 sqlite3PcacheRefCount(PCache*); +SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache*); /* Increment the reference count of an existing page */ SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr*); -SQLITE_PRIVATE i64 sqlite3PcachePageRefcount(PgHdr*); +SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr*); /* Return the total number of pages stored in the cache */ SQLITE_PRIVATE int sqlite3PcachePagecount(PCache*); @@ -17384,7 +16689,7 @@ SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*); /* ** Default synchronous levels. ** -** Note that (for historical reasons) the PAGER_SYNCHRONOUS_* macros differ +** Note that (for historcal reasons) the PAGER_SYNCHRONOUS_* macros differ ** from the SQLITE_DEFAULT_SYNCHRONOUS value by 1. ** ** PAGER_SYNCHRONOUS DEFAULT_SYNCHRONOUS @@ -17423,7 +16728,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 database (sqlite3.aDb[1]) which is free-standing. +** the Schema for the TEMP databaes (sqlite3.aDb[1]) which is free-standing. ** In shared cache mode, a single Schema object can be shared by multiple ** Btrees that refer to the same underlying BtShared object. ** @@ -17534,7 +16839,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 previously used */ + LookasideSlot *pSmallInit; /* List of small buffers not prediously 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 */ @@ -17551,7 +16856,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 lookaside */ +/* Size of the smaller allocations in two-size lookside */ #ifdef SQLITE_OMIT_TWOSIZE_LOOKASIDE # define LOOKASIDE_SMALL 0 #else @@ -17572,10 +16877,6 @@ 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 "sqlite3" database connection object and used @@ -17755,7 +17056,6 @@ struct 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; /* sqlite3_set_clientdata() content */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY /* The following variables are all protected by the STATIC_MAIN ** mutex, not by sqlite3.mutex. They are used by code in notify.c. @@ -17811,7 +17111,7 @@ struct 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_StmtScanStatus 0x00000400 /* Enable stmt_scanstats() counters */ +#define SQLITE_ReadUncommit 0x00000400 /* READ UNCOMMITTED in shared-cache */ #define SQLITE_NoCkptOnClose 0x00000800 /* No checkpoint on close()/DETACH */ #define SQLITE_ReverseOrder 0x00001000 /* Reverse unordered SELECTs */ #define SQLITE_RecTriggers 0x00002000 /* Enable recursive triggers */ @@ -17837,8 +17137,6 @@ struct 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 @@ -17879,7 +17177,7 @@ struct 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 /* WHERE-clause push-down opt */ +#define SQLITE_PushDown 0x00001000 /* The push-down optimization */ #define SQLITE_SimplifyJoin 0x00002000 /* Convert LEFT JOIN to JOIN */ #define SQLITE_SkipScan 0x00004000 /* Skip-scans */ #define SQLITE_PropagateConst 0x00008000 /* The constant propagation opt */ @@ -17894,9 +17192,6 @@ struct sqlite3 { #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 */ /* @@ -17979,17 +17274,10 @@ 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!!! +** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS ** 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 */ @@ -17998,7 +17286,6 @@ struct FuncDestructor { #define SQLITE_FUNC_NEEDCOLL 0x0020 /* sqlite3GetFuncCollSeq() might be called*/ #define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */ #define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */ -#define SQLITE_FUNC_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 */ @@ -18007,15 +17294,14 @@ 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 */ -#define SQLITE_FUNC_RUNONLY 0x8000 /* Cannot be used by valueFromFunction */ +/* 0x8000 -- available for reuse */ #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 */ -/* SQLITE_SUBTYPE 0x00100000 // Consumer of subtypes */ +#define SQLITE_FUNC_SUBTYPE 0x00100000 /* Result likely to have sub-type */ #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 */ @@ -18107,11 +17393,10 @@ 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, 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 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 INLINE_FUNC(zName, nArg, iArg, mFlags) \ {nArg, SQLITE_FUNC_BUILTIN|\ SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \ @@ -18301,7 +17586,6 @@ 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 sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC) @@ -18372,7 +17656,6 @@ struct VTable { 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) */ @@ -18452,7 +17735,8 @@ 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_MaybeReanalyze 0x00000100 /* Maybe run ANALYZE on this table */ +#define TF_StatsUsed 0x00000100 /* Query planner decisions affected by + ** Index.aiRowLogEst[] values */ #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 */ @@ -18508,15 +17792,6 @@ 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 (sqlite3Config.mNoVisibleRowid==0) -#endif - /* ** Each foreign key constraint is an instance of the following structure. ** @@ -18588,7 +17863,7 @@ struct FKey { ** foreign key. ** ** The OE_Default value is a place holder that means to use whatever -** conflict resolution algorithm is required from context. +** conflict resolution algorthm is required from context. ** ** The following symbolic values are used to record which type ** of conflict resolution action to take. @@ -18754,7 +18029,6 @@ 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 */ @@ -18762,7 +18036,6 @@ 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 */ @@ -18844,15 +18117,16 @@ 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 iFirstReg; /* First register in range for aCol[] and aFunc[] */ + int nSortingColumn; /* Number of columns in the sorting index */ + int mnReg, mxReg; /* Range of registers allocated 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; @@ -18863,31 +18137,14 @@ 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 @@ -19007,7 +18264,7 @@ struct Expr { ** TK_REGISTER: register number ** TK_TRIGGER: 1 -> new, 0 -> old ** EP_Unlikely: 134217728 times likelihood - ** TK_IN: ephemeral table holding RHS + ** TK_IN: ephemerial 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. @@ -19053,7 +18310,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_FullSize 0x020000 /* Expr structure must remain full sized */ + /* 0x020000 // Available for reuse */ #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 */ @@ -19083,15 +18340,12 @@ 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) @@ -19201,7 +18455,6 @@ 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, @@ -19252,12 +18505,10 @@ struct IdList { ** ** Union member validity: ** -** 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 +** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc +** u1.pFuncArg 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 */ @@ -19283,9 +18534,8 @@ 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 synthesized from NATURAL */ + unsigned isSynthUsing :1; /* u3.pUsing is synthensized 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 { @@ -19296,7 +18546,6 @@ struct SrcItem { union { char *zIndexedBy; /* Identifier from "INDEXED BY " 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 */ @@ -19361,7 +18610,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 */ -#define WHERE_KEEP_ALL_JOINS 0x2000 /* Do not do the omit-noop-join opt */ + /* 0x2000 not currently used */ #define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */ /* 0x8000 not currently used */ @@ -19406,7 +18655,6 @@ 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 */ }; @@ -19427,7 +18675,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_Subquery 0x000040 /* A subquery has been seen */ +#define NC_VarSelect 0x000040 /* A correlated 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 */ @@ -19440,7 +18688,6 @@ 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 */ /* @@ -19464,7 +18711,6 @@ 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 */ @@ -19554,12 +18800,10 @@ 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 /* Modified by WHERE-clause push-down opt */ +#define SF_PushDown 0x1000000 /* SELECT has be modified by 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) @@ -19668,7 +18912,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 for SRT_Set */ + char *zAffSdst; /* Affinity used for SRT_Set, SRT_Table, and similar */ ExprList *pOrderBy; /* Key columns for SRT_Queue and SRT_DistQueue */ }; @@ -19727,10 +18971,10 @@ 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 /* @@ -19749,7 +18993,6 @@ struct IndexedExpr { 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 */ @@ -19799,12 +19042,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 */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) u8 earlyCleanup; /* OOM inside 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 */ @@ -19818,8 +19057,7 @@ 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 */ + IndexedExpr *pIdxExpr;/* List of expressions used by active indexes */ 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 */ @@ -19827,9 +19065,6 @@ 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 sqlite3_prepare() */ -#endif #ifndef SQLITE_OMIT_SHARED_CACHE int nTableLock; /* Number of locks in aTableLock */ TableLock *aTableLock; /* Required table locks for shared-cache mode */ @@ -19843,9 +19078,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 */ @@ -19969,7 +19204,6 @@ 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 */ @@ -20091,7 +19325,6 @@ 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" */ }; /* @@ -20113,28 +19346,6 @@ struct 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 sqlite3RCStrUnref() to free an RCStr string rather than -** sqlite3_free() -** -** 3. Make a (read-only) copy of a read-only RCStr string using -** 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 @@ -20161,7 +19372,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 -** optimal values for parameters in the query planner. The should not +** optimial 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. ** @@ -20187,10 +19398,6 @@ 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 */ @@ -20237,11 +19444,6 @@ struct Sqlite3Config { #endif #ifndef SQLITE_UNTESTABLE int (*xTestCallback)(int); /* Invoked by 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 */ @@ -20282,7 +19484,6 @@ 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 */ @@ -20301,7 +19502,6 @@ struct Walker { struct CoveringIndexCheck *pCovIdxCk; /* Check for covering index */ SrcItem *pSrcItem; /* A single FROM clause item */ DbFixer *pFix; /* See sqlite3FixSelect() */ - Mem *aMem; /* See sqlite3BtreeCursorHint() */ } u; }; @@ -20322,7 +19522,6 @@ struct DbFixer { /* Forward declarations */ SQLITE_PRIVATE int sqlite3WalkExpr(Walker*, Expr*); -SQLITE_PRIVATE int sqlite3WalkExprNN(Walker*, Expr*); SQLITE_PRIVATE int sqlite3WalkExprList(Walker*, ExprList*); SQLITE_PRIVATE int sqlite3WalkSelect(Walker*, Select*); SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker*, Select*); @@ -20403,16 +19602,6 @@ struct CteUse { }; -/* Client data associated with sqlite3_set_clientdata() and -** 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 @@ -20479,9 +19668,6 @@ struct Window { ** due to the SQLITE_SUBTYPE flag */ }; -SQLITE_PRIVATE Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow); -SQLITE_PRIVATE void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal); - #ifndef SQLITE_OMIT_WINDOWFUNC SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3*, Window*); SQLITE_PRIVATE void sqlite3WindowUnlinkFromSelect(Window*); @@ -20585,8 +19771,6 @@ SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno); # define sqlite3Isxdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x08) # define sqlite3Tolower(x) (sqlite3UpperToLower[(unsigned char)(x)]) # define sqlite3Isquote(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x80) -# define sqlite3JsonId1(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x42) -# define sqlite3JsonId2(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x46) #else # define sqlite3Toupper(x) toupper((unsigned char)(x)) # define sqlite3Isspace(x) isspace((unsigned char)(x)) @@ -20596,8 +19780,6 @@ SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno); # define sqlite3Isxdigit(x) isxdigit((unsigned char)(x)) # define sqlite3Tolower(x) tolower((unsigned char)(x)) # define sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`') -# define sqlite3JsonId1(x) (sqlite3IsIdChar(x)&&(x)<'0') -# define sqlite3JsonId2(x) sqlite3IsIdChar(x) #endif SQLITE_PRIVATE int sqlite3IsIdChar(u8); @@ -20647,11 +19829,13 @@ SQLITE_PRIVATE int sqlite3HeapNearlyFull(void); #ifdef SQLITE_USE_ALLOCA # define sqlite3StackAllocRaw(D,N) alloca(N) # define sqlite3StackAllocRawNN(D,N) alloca(N) +# define sqlite3StackAllocZero(D,N) memset(alloca(N), 0, N) # define sqlite3StackFree(D,P) # define sqlite3StackFreeNN(D,P) #else # define sqlite3StackAllocRaw(D,N) sqlite3DbMallocRaw(D,N) # define sqlite3StackAllocRawNN(D,N) sqlite3DbMallocRawNN(D,N) +# define sqlite3StackAllocZero(D,N) sqlite3DbMallocZero(D,N) # define sqlite3StackFree(D,P) sqlite3DbFree(D,P) # define sqlite3StackFreeNN(D,P) sqlite3DbFreeNN(D,P) #endif @@ -20701,13 +19885,10 @@ SQLITE_PRIVATE void sqlite3MutexWarnOnContention(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 sqlite3IsNaN(double); -SQLITE_PRIVATE int sqlite3IsOverflow(double); #else -# define IsNaN(X) 0 -# define sqlite3IsNaN(X) 0 -# define sqlite3IsOVerflow(X) 0 +# define IsNaN(X) 0 +# define sqlite3IsNaN(X) 0 #endif /* @@ -20720,20 +19901,6 @@ struct PrintfArguments { 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 sqlite3FpDecode(FpDecode*,double,int,int); SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3*,const char*, ...); SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3*,const char*, va_list); #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) @@ -20793,13 +19960,11 @@ SQLITE_PRIVATE void sqlite3ShowWinFunc(const Window*); #endif SQLITE_PRIVATE void sqlite3SetString(char **, sqlite3*, const char*); -SQLITE_PRIVATE void sqlite3ProgressCheck(Parse*); SQLITE_PRIVATE void sqlite3ErrorMsg(Parse*, const char*, ...); SQLITE_PRIVATE int sqlite3ErrorToParser(sqlite3*,int); SQLITE_PRIVATE void sqlite3Dequote(char*); SQLITE_PRIVATE void sqlite3DequoteExpr(Expr*); SQLITE_PRIVATE void sqlite3DequoteToken(Token*); -SQLITE_PRIVATE void sqlite3DequoteNumber(Parse*, Expr*); SQLITE_PRIVATE void sqlite3TokenInit(Token*,char*); SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char*, int); SQLITE_PRIVATE int sqlite3RunParser(Parse*, const char*); @@ -20809,10 +19974,6 @@ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse*,int); SQLITE_PRIVATE int sqlite3GetTempRange(Parse*,int); SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse*,int,int); SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse*); -SQLITE_PRIVATE void sqlite3TouchRegister(Parse*,int); -#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_DEBUG) -SQLITE_PRIVATE int sqlite3FirstAvailableRegister(Parse*,int); -#endif #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse*,int,int); #endif @@ -20824,13 +19985,10 @@ SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*); SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse*,Expr*, Expr*); SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr*); SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, const Token*, int); -SQLITE_PRIVATE void sqlite3ExprAddFunctionOrderBy(Parse*,Expr*,ExprList*); -SQLITE_PRIVATE void sqlite3ExprOrderByAggregateError(Parse*,Expr*); SQLITE_PRIVATE void sqlite3ExprFunctionUsable(Parse*,const Expr*,const FuncDef*); SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*); -SQLITE_PRIVATE void sqlite3ExprDeleteGeneric(sqlite3*,void*); -SQLITE_PRIVATE int sqlite3ExprDeferredDelete(Parse*, Expr*); +SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse*, Expr*); SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse*, Expr*); SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*); @@ -20839,7 +19997,6 @@ SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int,int); SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,const Token*,int); SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*); SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*); -SQLITE_PRIVATE void sqlite3ExprListDeleteGeneric(sqlite3*,void*); SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*); SQLITE_PRIVATE int sqlite3IndexHasDuplicateRootPage(Index*); SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**); @@ -20860,7 +20017,7 @@ SQLITE_PRIVATE const char *sqlite3ColumnColl(Column*); SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*); SQLITE_PRIVATE void sqlite3GenerateColumnNames(Parse *pParse, Select *pSelect); SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); -SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(Parse*,Table*,Select*,char); +SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*,char); SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*,char); SQLITE_PRIVATE void sqlite3OpenSchemaTable(Parse *, int); SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*); @@ -20930,7 +20087,6 @@ SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask); SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int); SQLITE_PRIVATE void sqlite3CodeDropTable(Parse*, Table*, int, int); SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3*, Table*); -SQLITE_PRIVATE void sqlite3DeleteTableGeneric(sqlite3*, void*); SQLITE_PRIVATE void sqlite3FreeIndex(sqlite3*, Index*); #ifndef SQLITE_OMIT_AUTOINCREMENT SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse); @@ -20967,9 +20123,8 @@ SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*); SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, Expr*,ExprList*,u32,Expr*); SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*); -SQLITE_PRIVATE void sqlite3SelectDeleteGeneric(sqlite3*,void*); SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*); -SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, Trigger*); +SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int); SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*); @@ -21031,7 +20186,7 @@ SQLITE_PRIVATE int sqlite3ExprCompare(const Parse*,const Expr*,const Expr*, int) SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr*,Expr*,int); SQLITE_PRIVATE int sqlite3ExprListCompare(const ExprList*,const ExprList*, int); SQLITE_PRIVATE int sqlite3ExprImpliesExpr(const Parse*,const Expr*,const Expr*, int); -SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr*,int,int); +SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr*,int); SQLITE_PRIVATE void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*); SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); @@ -21053,10 +20208,12 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3*); SQLITE_PRIVATE u32 sqlite3IsTrueOrFalse(const char*); SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr*); SQLITE_PRIVATE int sqlite3ExprTruthValue(const Expr*); -SQLITE_PRIVATE int sqlite3ExprIsConstant(Parse*,Expr*); +SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*); +SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*); SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8); SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*); -SQLITE_PRIVATE int sqlite3ExprIsSingleTableConstraint(Expr*,const SrcList*,int,int); +SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int); +SQLITE_PRIVATE int sqlite3ExprIsTableConstraint(Expr*,const SrcItem*); #ifdef SQLITE_ENABLE_CURSOR_HINTS SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*); #endif @@ -21064,7 +20221,6 @@ SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr*, int*); SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*); SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); SQLITE_PRIVATE int sqlite3IsRowid(const char*); -SQLITE_PRIVATE const char *sqlite3RowidAlias(Table *pTab); SQLITE_PRIVATE void sqlite3GenerateRowDelete( Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int); SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int); @@ -21179,10 +20335,9 @@ SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*); SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*); SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*); SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); - SQLITE_PRIVATE int sqlite3RealSameAsInt(double,sqlite3_int64); SQLITE_PRIVATE i64 sqlite3RealToI64(double); -SQLITE_PRIVATE int sqlite3Int64ToText(i64,char*); +SQLITE_PRIVATE void sqlite3Int64ToText(i64,char*); SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8); SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*); SQLITE_PRIVATE int sqlite3GetUInt32(const char*, u32*); @@ -21192,7 +20347,6 @@ SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar); #endif SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte); SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**); -SQLITE_PRIVATE int sqlite3Utf8ReadLimited(const u8*, int, u32*); SQLITE_PRIVATE LogEst sqlite3LogEst(u64); SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst,LogEst); SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double); @@ -21234,16 +20388,13 @@ SQLITE_PRIVATE char sqlite3CompareAffinity(const Expr *pExpr, char aff2); SQLITE_PRIVATE int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity); SQLITE_PRIVATE char sqlite3TableColumnAffinity(const Table*,int); SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr); -SQLITE_PRIVATE int sqlite3ExprDataType(const Expr *pExpr); SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*); SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...); SQLITE_PRIVATE void sqlite3Error(sqlite3*,int); SQLITE_PRIVATE void sqlite3ErrorClear(sqlite3*); SQLITE_PRIVATE void sqlite3SystemError(sqlite3*,int); -#if !defined(SQLITE_OMIT_BLOB_LITERAL) SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n); -#endif SQLITE_PRIVATE u8 sqlite3HexToInt(int h); SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); @@ -21253,9 +20404,6 @@ SQLITE_PRIVATE const char *sqlite3ErrName(int); #ifndef SQLITE_OMIT_DESERIALIZE SQLITE_PRIVATE int sqlite3MemdbInit(void); -SQLITE_PRIVATE int sqlite3IsMemdb(const sqlite3_vfs*); -#else -# define sqlite3IsMemdb(X) 0 #endif SQLITE_PRIVATE const char *sqlite3ErrStr(int); @@ -21287,7 +20435,6 @@ SQLITE_PRIVATE void sqlite3FileSuffix3(const char*, char*); SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z,u8); SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8); -SQLITE_PRIVATE int sqlite3ValueIsOfClass(const sqlite3_value*, void(*)(void*)); SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8); SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*)); @@ -21339,8 +20486,7 @@ SQLITE_PRIVATE int sqlite3MatchEName( const struct ExprList_item*, const char*, const char*, - const char*, - int* + const char* ); SQLITE_PRIVATE Bitmask sqlite3ExprColUsed(Expr*); SQLITE_PRIVATE u8 sqlite3StrIHash(const char*); @@ -21396,13 +20542,8 @@ SQLITE_PRIVATE void sqlite3OomClear(sqlite3*); SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int); SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *); -SQLITE_PRIVATE char *sqlite3RCStrRef(char*); -SQLITE_PRIVATE void sqlite3RCStrUnref(void*); -SQLITE_PRIVATE char *sqlite3RCStrNew(u64); -SQLITE_PRIVATE char *sqlite3RCStrResize(char*,u64); - SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int); -SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum*, i64); +SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum*, int); SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*); SQLITE_PRIVATE void sqlite3StrAccumSetError(StrAccum*, u8); SQLITE_PRIVATE void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*); @@ -21516,7 +20657,10 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3*, int, const char *); SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *, VTable *); SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*); -SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(Parse*); +#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \ + && !defined(SQLITE_OMIT_VIRTUALTABLE) +SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(sqlite3_index_info*); +#endif SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*); SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe*, const char*, int); SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); @@ -21541,7 +20685,6 @@ SQLITE_PRIVATE Cte *sqlite3CteNew(Parse*,Token*,ExprList*,Select*,u8); SQLITE_PRIVATE void sqlite3CteDelete(sqlite3*,Cte*); SQLITE_PRIVATE With *sqlite3WithAdd(Parse*,With*,Cte*); SQLITE_PRIVATE void sqlite3WithDelete(sqlite3*,With*); -SQLITE_PRIVATE void sqlite3WithDeleteGeneric(sqlite3*,void*); SQLITE_PRIVATE With *sqlite3WithPush(Parse*, With*, u8); #else # define sqlite3CteNew(P,T,E,S) ((void*)0) @@ -21554,7 +20697,7 @@ SQLITE_PRIVATE With *sqlite3WithPush(Parse*, With*, u8); SQLITE_PRIVATE Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*); SQLITE_PRIVATE void sqlite3UpsertDelete(sqlite3*,Upsert*); SQLITE_PRIVATE Upsert *sqlite3UpsertDup(sqlite3*,Upsert*); -SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*,Upsert*); +SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*); SQLITE_PRIVATE void sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int); SQLITE_PRIVATE Upsert *sqlite3UpsertOfIndex(Upsert*,Index*); SQLITE_PRIVATE int sqlite3UpsertNextIsIPK(Upsert*); @@ -21653,7 +20796,6 @@ SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse*, int); #define sqlite3SelectExprHeight(x) 0 #define sqlite3ExprCheckHeight(x,y) #endif -SQLITE_PRIVATE void sqlite3ExprSetErrorOffset(Expr*,int); SQLITE_PRIVATE u32 sqlite3Get4byte(const u8*); SQLITE_PRIVATE void sqlite3Put4byte(u8*, u32); @@ -21759,18 +20901,6 @@ SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt); SQLITE_PRIVATE int sqlite3KvvfsInit(void); #endif -#if defined(VDBE_PROFILE) \ - || defined(SQLITE_PERFORMANCE_TRACE) \ - || defined(SQLITE_ENABLE_STMT_SCANSTATUS) -SQLITE_PRIVATE sqlite3_uint64 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 *******************************************/ @@ -21812,6 +20942,101 @@ SQLITE_PRIVATE sqlite3_uint64 sqlite3Hwtime(void); */ #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 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 sqlite3Hwtime(void){ + __asm { + rdtsc + ret ; return value at EDX:EAX + } + } + + #endif + +#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__)) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned long val; + __asm__ __volatile__ ("rdtsc" : "=A" (val)); + return val; + } + +#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__)) + + __inline__ sqlite_uint64 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 sqlite3Hwtime() routine. + ** + ** 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 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=sqlite3Hwtime() @@ -21939,14 +21164,14 @@ static const char * const 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 @@ -22237,9 +21462,6 @@ static const char * const 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 @@ -22281,9 +21503,6 @@ static const char * const 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 @@ -22521,9 +21740,6 @@ static const char * const 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 @@ -22775,7 +21991,7 @@ SQLITE_PRIVATE const unsigned char *sqlite3aGTb = &sqlite3UpperToLower[256+12-OP ** isalnum() 0x06 ** isxdigit() 0x08 ** toupper() 0x20 -** SQLite identifier character 0x40 $, _, or non-ascii +** SQLite identifier character 0x40 ** Quote character 0x80 ** ** Bit 0x20 is set if the mapped character requires translation to upper @@ -22921,10 +22137,6 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config 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 */ @@ -22966,9 +22178,6 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { #endif #ifndef SQLITE_UNTESTABLE 0, /* xTestCallback */ -#endif -#ifdef SQLITE_ALLOW_ROWID_IN_VIEW - 0, /* mNoVisibleRowid. 0 == allow rowid-in-view */ #endif 0, /* bLocaltimeFault */ 0, /* xAltLocaltime */ @@ -22976,7 +22185,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { 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 }; @@ -23157,9 +22366,6 @@ 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 @@ -23191,7 +22397,6 @@ 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 */ @@ -23232,7 +22437,6 @@ 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 @@ -23245,25 +22449,12 @@ 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 @@ -23290,6 +22481,7 @@ 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 */ @@ -23505,19 +22697,10 @@ typedef unsigned bft; /* Bit Field Type */ /* The ScanStatus object holds a single value for the ** 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 */ @@ -23573,7 +22756,7 @@ struct Vdbe { int nOp; /* Number of instructions in the program */ int nOpAlloc; /* Slots allocated for aOp[] */ Mem *aColName; /* Column names to return */ - Mem *pResultRow; /* Current output row */ + Mem *pResultSet; /* Pointer to an array of results */ char *zErrMsg; /* Error message written here */ VList *pVList; /* Name of variables */ #ifndef SQLITE_OMIT_TRACE @@ -23584,18 +22767,16 @@ 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; /* 0: normal, 1: EXPLAIN, 2: EXPLAIN QUERY PLAN */ + bft explain:2; /* True if EXPLAIN present on SQL command */ 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 sqlite3_stmt_status() */ @@ -23612,6 +22793,7 @@ 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 sqlite3_stmt_scanstatus() */ #endif @@ -23642,7 +22824,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 updated */ + Table *pTab; /* Schema object being upated */ Index *pPk; /* PK index if pTab is WITHOUT ROWID */ }; @@ -23732,7 +22914,6 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetZeroBlob(Mem*,int); SQLITE_PRIVATE int sqlite3VdbeMemIsRowSet(const Mem*); #endif SQLITE_PRIVATE int sqlite3VdbeMemSetRowSet(Mem*); -SQLITE_PRIVATE void sqlite3VdbeMemZeroTerminateIfAble(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, u8, u8); SQLITE_PRIVATE int sqlite3IntFloatCompare(i64,double); @@ -23779,8 +22960,6 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *); SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *); SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *); -SQLITE_PRIVATE void sqlite3VdbeValueListFree(void*); - #ifdef SQLITE_DEBUG SQLITE_PRIVATE void sqlite3VdbeIncrWriteCounter(Vdbe*, VdbeCursor*); SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe*); @@ -24180,7 +23359,7 @@ SQLITE_API int sqlite3_db_status( case SQLITE_DBSTATUS_CACHE_MISS: case SQLITE_DBSTATUS_CACHE_WRITE:{ int i; - u64 nRet = 0; + int nRet = 0; assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 ); assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 ); @@ -24193,7 +23372,7 @@ SQLITE_API int sqlite3_db_status( *pHighwater = 0; /* IMP: R-42420-56072 */ /* IMP: R-54100-20147 */ /* IMP: R-29431-39229 */ - *pCurrent = (int)nRet & 0x7fffffff; + *pCurrent = nRet; break; } @@ -24290,14 +23469,12 @@ 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 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 */ + char validTZ; /* True (1) if tz is valid */ + char tzSet; /* Timezone was set explicitly */ + char isError; /* An overflow has occurred */ }; @@ -24330,8 +23507,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, 14712 }; + ** spec into a max size: a b c d e f */ + static const u16 aMx[] = { 12, 14, 24, 31, 59, 9999 }; va_list ap; int cnt = 0; char nextC; @@ -24395,8 +23572,6 @@ 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; @@ -24409,6 +23584,7 @@ static int parseTimezone(const char *zDate, DateTime *p){ p->tz = sgn*(nMn + nHr*60); zulu_time: while( sqlite3Isspace(*zDate) ){ zDate++; } + p->tzSet = 1; return *zDate!=0; } @@ -24452,6 +23628,7 @@ 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; } @@ -24498,40 +23675,15 @@ static void computeJD(DateTime *p){ p->validJD = 1; if( p->validHMS ){ p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000 + 0.5); - if( p->tz ){ + if( p->validTZ ){ p->iJD -= p->tz*60000; p->validYMD = 0; p->validHMS = 0; - p->tz = 0; - p->isUtc = 1; - p->isLocal = 0; + p->validTZ = 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<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 ** @@ -24570,16 +23722,12 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){ p->Y = neg ? -Y : Y; p->M = M; p->D = D; - computeFloor(p); - if( p->tz ){ + if( p->validTZ ){ computeJD(p); } return 0; } - -static void clearYMD_HMS_TZ(DateTime *p); /* Forward declaration */ - /* ** Set the time to the current time reported by the VFS. ** @@ -24589,9 +23737,6 @@ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){ p->iJD = sqlite3StmtCurrentTime(context); if( p->iJD>0 ){ p->validJD = 1; - p->isUtc = 1; - p->isLocal = 0; - clearYMD_HMS_TZ(p); return 0; }else{ return 1; @@ -24644,11 +23789,6 @@ static int parseDateOrTime( }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8)>0 ){ setRawDateNumber(p, r); return 0; - }else if( (sqlite3StrICmp(zDate,"subsec")==0 - || sqlite3StrICmp(zDate,"subsecond")==0) - && sqlite3NotPureFunc(context) ){ - p->useSubsec = 1; - return setDateTimeToCurrent(context, p); } return 1; } @@ -24704,14 +23844,17 @@ static void computeYMD(DateTime *p){ ** Compute the Hour, Minute, and Seconds from the julian day number. */ static void computeHMS(DateTime *p){ - int day_ms, day_min; /* milliseconds, minutes into the day */ + int s; if( p->validHMS ) return; computeJD(p); - 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; + 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; p->rawS = 0; p->validHMS = 1; } @@ -24730,7 +23873,7 @@ static void computeYMD_HMS(DateTime *p){ static void clearYMD_HMS_TZ(DateTime *p){ p->validYMD = 0; p->validHMS = 0; - p->tz = 0; + p->validTZ = 0; } #ifndef SQLITE_OMIT_LOCALTIME @@ -24862,7 +24005,7 @@ static int toLocaltime( p->validHMS = 1; p->validJD = 0; p->rawS = 0; - p->tz = 0; + p->validTZ = 0; p->isError = 0; return SQLITE_OK; } @@ -24882,33 +24025,14 @@ static const struct { float rLimit; /* Maximum NNN value for this transform */ float rXform; /* Constant used for this transform */ } aXformType[] = { - /* 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 }, + { 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 }, }; -/* -** 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 = (sqlite3_int64)(r + 0.5); - p->validJD = 1; - p->rawS = 0; - } -} - /* ** Process a modifier to a date-time stamp. The modifiers are ** as follows: @@ -24919,20 +24043,14 @@ static void autoAdjustDate(DateTime *p){ ** 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 @@ -24958,39 +24076,19 @@ static int parseModifier( */ if( sqlite3_stricmp(z, "auto")==0 ){ if( idx>1 ) return 1; /* IMP: R-33611-57934 */ - 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( 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( sqlite3_stricmp(z, "floor")==0 ){ - computeJD(p); - p->iJD -= p->nFloor*86400000; - clearYMD_HMS_TZ(p); - rc = 0; + 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 = (sqlite3_int64)(r + 0.5); + p->validJD = 1; + p->rawS = 0; + rc = 0; + } } break; } @@ -25020,9 +24118,7 @@ static int parseModifier( ** show local time. */ if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){ - rc = p->isLocal ? SQLITE_OK : toLocaltime(p, pCtx); - p->isUtc = 0; - p->isLocal = 1; + rc = toLocaltime(p, pCtx); } break; } @@ -25047,11 +24143,11 @@ static int parseModifier( } #ifndef SQLITE_OMIT_LOCALTIME else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){ - if( p->isUtc==0 ){ + if( p->tzSet==0 ){ i64 iOrigJD; /* Original localtime */ i64 iGuess; /* Guess at the corresponding utc time */ int cnt = 0; /* Safety to prevent infinite loop */ - i64 iErr; /* Guess is off by this much */ + int iErr; /* Guess is off by this much */ computeJD(p); iGuess = iOrigJD = p->iJD; @@ -25070,8 +24166,7 @@ static int parseModifier( memset(p, 0, sizeof(*p)); p->iJD = iGuess; p->validJD = 1; - p->isUtc = 1; - p->isLocal = 0; + p->tzSet = 1; } rc = SQLITE_OK; } @@ -25091,7 +24186,7 @@ static int parseModifier( && r>=0.0 && r<7.0 && (n=(int)r)==r ){ sqlite3_int64 Z; computeYMD_HMS(p); - p->tz = 0; + p->validTZ = 0; p->validJD = 0; computeJD(p); Z = ((p->iJD + 129600000)/86400000) % 7; @@ -25108,22 +24203,8 @@ 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( sqlite3_strnicmp(z, "start of ", 9)!=0 ){ - if( sqlite3_stricmp(z, "subsec")==0 - || sqlite3_stricmp(z, "subsecond")==0 - ){ - p->useSubsec = 1; - rc = 0; - } - break; - } + if( sqlite3_strnicmp(z, "start of ", 9)!=0 ) break; if( !p->validJD && !p->validYMD && !p->validHMS ) break; z += 9; computeYMD(p); @@ -25131,7 +24212,7 @@ static int parseModifier( p->h = p->m = 0; p->s = 0.0; p->rawS = 0; - p->tz = 0; + p->validTZ = 0; p->validJD = 0; if( sqlite3_stricmp(z,"month")==0 ){ p->D = 1; @@ -25159,74 +24240,18 @@ static int parseModifier( case '9': { double rRounder; int i; - 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( 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; - } - } + for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){} if( sqlite3AtoF(z, &r, n, SQLITE_UTF8)<=0 ){ - assert( rc==1 ); + rc = 1; break; } - 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( sqlite3Isspace(z[11]) - && getDigits(&z[12], "20c:20e", &h, &m)==2 - ){ - z2 = &z[12]; - n = 2; - }else{ - break; - } - } - if( z2[n]==':' ){ + if( z[n]==':' ){ /* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the ** specified number of hours, minutes, seconds, and fractional seconds ** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be ** omitted. */ - + const char *z2 = z; DateTime tx; sqlite3_int64 day; if( !sqlite3Isdigit(*z2) ) z2++; @@ -25236,7 +24261,7 @@ static int parseModifier( tx.iJD -= 43200000; day = tx.iJD/86400000; tx.iJD -= day*86400000; - if( z0=='-' ) tx.iJD = -tx.iJD; + if( z[0]=='-' ) tx.iJD = -tx.iJD; computeJD(p); clearYMD_HMS_TZ(p); p->iJD += tx.iJD; @@ -25249,12 +24274,11 @@ static int parseModifier( z += n; while( sqlite3Isspace(*z) ) z++; n = sqlite3Strlen30(z); - if( n<3 || n>10 ) break; + if( n>10 || n<3 ) break; if( sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--; computeJD(p); - assert( rc==1 ); + rc = 1; rRounder = r<0 ? -0.5 : +0.5; - p->nFloor = 0; for(i=0; iM += (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[5].zName,"year")==0 ); + assert( strcmp(aXformType[i].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; @@ -25340,12 +24362,6 @@ 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; } @@ -25386,11 +24402,7 @@ static void unixepochFunc( DateTime x; if( isDate(context, argc, argv, &x)==0 ){ computeJD(&x); - if( x.useSubsec ){ - sqlite3_result_double(context, (x.iJD - 21086676*(i64)10000000)/1000.0); - }else{ - sqlite3_result_int64(context, x.iJD/1000 - 21086676*(i64)10000); - } + sqlite3_result_int64(context, x.iJD/1000 - 21086676*(i64)10000); } } @@ -25406,8 +24418,8 @@ static void datetimeFunc( ){ DateTime x; if( isDate(context, argc, argv, &x)==0 ){ - int Y, s, n; - char zBuf[32]; + int Y, s; + char zBuf[24]; computeYMD_HMS(&x); Y = x.Y; if( Y<0 ) Y = -Y; @@ -25428,28 +24440,15 @@ static void datetimeFunc( zBuf[15] = '0' + (x.m/10)%10; zBuf[16] = '0' + (x.m)%10; zBuf[17] = ':'; - 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; - } + s = (int)x.s; + zBuf[18] = '0' + (s/10)%10; + zBuf[19] = '0' + (s)%10; + zBuf[20] = 0; if( x.Y<0 ){ zBuf[0] = '-'; - sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT); + sqlite3_result_text(context, zBuf, 20, SQLITE_TRANSIENT); }else{ - sqlite3_result_text(context, &zBuf[1], n-1, SQLITE_TRANSIENT); + sqlite3_result_text(context, &zBuf[1], 19, SQLITE_TRANSIENT); } } } @@ -25466,7 +24465,7 @@ static void timeFunc( ){ DateTime x; if( isDate(context, argc, argv, &x)==0 ){ - int s, n; + int s; char zBuf[16]; computeHMS(&x); zBuf[0] = '0' + (x.h/10)%10; @@ -25475,24 +24474,11 @@ static void timeFunc( zBuf[3] = '0' + (x.m/10)%10; zBuf[4] = '0' + (x.m)%10; zBuf[5] = ':'; - 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; - } - sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT); + s = (int)x.s; + zBuf[6] = '0' + (s/10)%10; + zBuf[7] = '0' + (s)%10; + zBuf[8] = 0; + sqlite3_result_text(context, zBuf, 8, SQLITE_TRANSIENT); } } @@ -25533,83 +24519,22 @@ 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 01-31 -** %e day of month 1-31 +** %d day of month ** %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 -** %k hour 0-24 (leading zero converted to space) -** %I hour 01-12 -** %j day of year 001-366 +** %j day of year 000-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 -** %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) +** %w day of week 0-6 sunday==0 +** %W week of year 00-53 ** %Y year 0000-9999 ** %% % */ @@ -25634,61 +24559,44 @@ static void strftimeFunc( computeJD(&x); computeYMD_HMS(&x); for(i=j=0; zFmt[i]; i++){ - char cf; if( zFmt[i]!='%' ) continue; if( j59.999 ) s = 59.999; sqlite3_str_appendf(&sRes, "%06.3f", s); break; } - case 'F': { - sqlite3_str_appendf(&sRes, "%04d-%02d-%02d", x.Y, x.M, x.D); + case 'H': { + sqlite3_str_appendf(&sRes, "%02d", x.h); break; } - case 'G': /* Fall thru */ - case 'g': { + case 'W': /* Fall thru */ + case 'j': { + int nDay; /* Number of days since 1st day of year */ DateTime y = x; - 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' ){ - sqlite3_str_appendf(&sRes, "%02d", y.Y%100); + 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); + sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7); }else{ - sqlite3_str_appendf(&sRes, "%04d", y.Y); + sqlite3_str_appendf(&sRes,"%03d",nDay+1); } break; } - case 'H': - case 'k': { - 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; - sqlite3_str_appendf(&sRes, cf=='I' ? "%02d" : "%2d", h); - break; - } - case 'j': { /* Day of year. Jan01==1, Jan02==2, and so forth */ - sqlite3_str_appendf(&sRes,"%03d",daysAfterJan01(&x)+1); - break; - } - case 'J': { /* Julian day number. (Non-standard) */ + case 'J': { sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0); break; } @@ -25700,62 +24608,18 @@ static void strftimeFunc( sqlite3_str_appendf(&sRes,"%02d",x.m); break; } - case 'p': /* Fall thru */ - case 'P': { - if( x.h>=12 ){ - sqlite3_str_append(&sRes, cf=='p' ? "PM" : "pm", 2); - }else{ - sqlite3_str_append(&sRes, cf=='p' ? "AM" : "am", 2); - } - break; - } - case 'R': { - sqlite3_str_appendf(&sRes, "%02d:%02d", x.h, x.m); - break; - } case 's': { - if( x.useSubsec ){ - sqlite3_str_appendf(&sRes,"%.3f", - (x.iJD - 21086676*(i64)10000000)/1000.0); - }else{ - i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000); - sqlite3_str_appendf(&sRes,"%lld",iS); - } + i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000); + sqlite3_str_appendf(&sRes,"%lld",iS); break; } case 'S': { sqlite3_str_appendf(&sRes,"%02d",(int)x.s); break; } - case 'T': { - 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'; - sqlite3_str_appendchar(&sRes, 1, c); - break; - } - case 'U': { /* Week num. 00-53. First Sun of the year is week 01 */ - 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); - sqlite3_str_appendf(&sRes,"%02d", daysAfterJan01(&y)/7+1); - break; - } - case 'W': { /* Week num. 00-53. First Mon of the year is week 01 */ - sqlite3_str_appendf(&sRes,"%02d", - (daysAfterJan01(&x)-daysAfterMonday(&x)+7)/7); + case 'w': { + sqlite3_str_appendchar(&sRes, 1, + (char)(((x.iJD+129600000)/86400000) % 7) + '0'); break; } case 'Y': { @@ -25804,115 +24668,6 @@ static void cdateFunc( dateFunc(context, 0, 0); } -/* -** 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( - sqlite3_context *context, - int NotUsed1, - sqlite3_value **argv -){ - char sign; - int Y, M; - DateTime d1, d2; - 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.iJDd2.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); - sqlite3StrAccumInit(&sRes, 0, 0, 0, 100); - sqlite3_str_appendf(&sRes, "%c%04d-%02d-%02d %02d:%02d:%06.3f", - sign, Y, M, d1.D-1, d1.h, d1.m, d1.s); - sqlite3ResultStrAccum(context, &sRes); -} - - /* ** current_timestamp() ** @@ -25973,36 +24728,6 @@ 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( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - DateTime x; - if( isDate(context, argc, argv, &x)==0 ){ - char *zJson; - zJson = 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); - sqlite3_result_text(context, zJson, -1, 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 @@ -26017,10 +24742,6 @@ SQLITE_PRIVATE void 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 ), @@ -26174,7 +24895,7 @@ SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){ /* 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 command returns SQLITE_NOMEM + ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM ** but the transaction is committed anyway. ** ** The core must call OsFileControl() though, not OsFileControlHint(), @@ -26795,7 +25516,7 @@ static void *sqlite3MemMalloc(int nByte){ ** or sqlite3MemRealloc(). ** ** For this low-level routine, we already know that pPrior!=0 since -** cases where pPrior==0 will have been intercepted and dealt with +** cases where pPrior==0 will have been intecepted and dealt with ** by higher-level routines. */ static void sqlite3MemFree(void *pPrior){ @@ -26883,7 +25604,7 @@ static int sqlite3MemInit(void *NotUsed){ return SQLITE_OK; } len = sizeof(cpuCount); - /* One usually wants to use hw.activecpu for MT decisions, but not here */ + /* One usually wants to use hw.acctivecpu for MT decisions, but not here */ sysctlbyname("hw.ncpu", &cpuCount, &len, NULL, 0); if( cpuCount>1 ){ /* defer MT decisions to system malloc */ @@ -28875,7 +27596,7 @@ static void checkMutexFree(sqlite3_mutex *p){ assert( SQLITE_MUTEX_FAST<2 ); assert( SQLITE_MUTEX_WARNONCONTENTION<2 ); -#ifdef SQLITE_ENABLE_API_ARMOR +#if SQLITE_ENABLE_API_ARMOR if( ((CheckMutex*)p)->iType<2 ) #endif { @@ -29350,7 +28071,7 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ /* ** The sqlite3_mutex.id, sqlite3_mutex.nRef, and sqlite3_mutex.owner fields -** are necessary under two conditions: (1) Debug builds and (2) using +** are necessary under two condidtions: (1) Debug builds and (2) using ** home-grown mutexes. Encapsulate these conditions into a single #define. */ #if defined(SQLITE_DEBUG) || defined(SQLITE_HOMEGROWN_RECURSIVE_MUTEX) @@ -29547,7 +28268,7 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){ */ static void pthreadMutexFree(sqlite3_mutex *p){ assert( p->nRef==0 ); -#ifdef SQLITE_ENABLE_API_ARMOR +#if SQLITE_ENABLE_API_ARMOR if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ) #endif { @@ -29851,7 +28572,7 @@ struct sqlite3_mutex { CRITICAL_SECTION mutex; /* Mutex controlling the lock */ int id; /* Mutex type */ #ifdef SQLITE_DEBUG - volatile int nRef; /* Number of entrances */ + volatile int nRef; /* Number of enterances */ volatile DWORD owner; /* Thread holding this mutex */ volatile LONG trace; /* True to trace changes */ #endif @@ -29900,7 +28621,7 @@ SQLITE_PRIVATE void sqlite3MemoryBarrier(void){ SQLITE_MEMORY_BARRIER; #elif defined(__GNUC__) __sync_synchronize(); -#elif MSVC_VERSION>=1400 +#elif MSVC_VERSION>=1300 _ReadWriteBarrier(); #elif defined(MemoryBarrier) MemoryBarrier(); @@ -30436,24 +29157,6 @@ static void sqlite3MallocAlarm(int nByte){ 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. @@ -30480,7 +29183,6 @@ static void mallocWithAlarm(int n, void **pp){ if( mem0.hardLimit ){ nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); if( nUsed >= mem0.hardLimit - nFull ){ - test_oom_breakpoint(1); *pp = 0; return; } @@ -30513,7 +29215,7 @@ static void mallocWithAlarm(int n, void **pp){ ** 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 +** Parnoid 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. @@ -30769,7 +29471,6 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){ sqlite3MallocAlarm(nDiff); if( mem0.hardLimit>0 && nUsed >= mem0.hardLimit - nDiff ){ sqlite3_mutex_leave(mem0.mutex); - test_oom_breakpoint(1); return 0; } } @@ -31028,14 +29729,9 @@ SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){ */ SQLITE_PRIVATE char *sqlite3DbSpanDup(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; sqlite3Isspace(zStart[n]); n++){ assert( &zStart[n]0) && sqlite3Isspace(zStart[n-1]) ) n--; return sqlite3DbStrNDup(db, zStart, n); } @@ -31131,7 +29827,7 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){ if( db->mallocFailed || rc ){ return apiHandleError(db, rc); } - return 0; + return rc & db->errMask; } /************** End of malloc.c **********************************************/ @@ -31243,6 +29939,43 @@ 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. */ @@ -31334,15 +30067,18 @@ SQLITE_API void 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 */ - double realvalue; /* Value for real types */ + LONGDOUBLE_TYPE 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 */ - int exp, e2; /* exponent of real numbers */ +#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 */ 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 */ @@ -31617,69 +30353,74 @@ SQLITE_API void sqlite3_str_vappendf( break; case etFLOAT: case etEXP: - case etGENERIC: { - FpDecode s; - int iRound; - int j; - + case etGENERIC: 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( xtype==etFLOAT ){ - iRound = -precision; - }else if( xtype==etGENERIC ){ - if( precision==0 ) precision = 1; - iRound = precision; + if( realvalue<0.0 ){ + realvalue = -realvalue; + prefix = '-'; }else{ - iRound = precision+1; + prefix = flag_prefix; } - sqlite3FpDecode(&s, realvalue, iRound, flag_altform2 ? 26 : 16); - if( s.isSpecial ){ - if( s.isSpecial==2 ){ - bufpt = flag_zeropad ? "null" : "NaN"; - length = sqlite3Strlen30(bufpt); - break; - }else if( flag_zeropad ){ - s.z[0] = '9'; - s.iDP = 1000; - s.n = 1; - }else{ - memcpy(buf, "-Inf", 5); + 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; + 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( sqlite3IsNaN((double)realvalue) ){ + bufpt = "NaN"; + length = 3; + break; + } + 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 ){ bufpt = buf; - if( s.sign=='-' ){ - /* no-op */ - }else if( flag_prefix ){ - buf[0] = flag_prefix; - }else{ - bufpt++; - } - length = sqlite3Strlen30(bufpt); + buf[0] = prefix; + memcpy(buf+(prefix!=0),"Inf",4); + length = 3+(prefix!=0); break; } } - if( s.sign=='-' ){ - prefix = '-'; - }else{ - prefix = flag_prefix; - } - - exp = s.iDP-1; - + bufpt = buf; /* ** 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; @@ -31693,32 +30434,29 @@ SQLITE_API void sqlite3_str_vappendf( if( xtype==etEXP ){ e2 = 0; }else{ - e2 = s.iDP - 1; + e2 = exp; } - 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++) = j1 ) *(bufpt++) = ','; + *(bufpt++) = et_getdigit(&realvalue,&nsd); } } /* The decimal point */ @@ -31727,12 +30465,13 @@ SQLITE_API void sqlite3_str_vappendf( } /* "0" digits after the decimal point but before the first ** significant digit of the number */ - for(e2++; e2<0 && precision>0; precision--, e2++){ + for(e2++; e2<0; precision--, e2++){ + assert( precision>0 ); *(bufpt++) = '0'; } /* Significant digits after the decimal point */ while( (precision--)>0 ){ - *(bufpt++) = jcharset]; if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; @@ -31782,8 +30520,8 @@ SQLITE_API void 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; @@ -31832,26 +30570,13 @@ SQLITE_API void sqlite3_str_vappendf( } } if( precision>1 ){ - i64 nPrior = 1; width -= precision-1; if( width>1 && !flag_leftjustify ){ sqlite3_str_appendchar(pAccum, width-1, ' '); width = 0; } - 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 ){ - sqlite3StrAccumEnlarge(pAccum, nCopyBytes); - } - if( pAccum->accError ) break; - sqlite3_str_append(pAccum, - &pAccum->zText[pAccum->nChar-nCopyBytes], nCopyBytes); - precision -= nPrior; - nPrior *= 2; + while( precision-- > 1 ){ + sqlite3_str_append(pAccum, buf, length); } } bufpt = buf; @@ -31995,13 +30720,9 @@ SQLITE_API void sqlite3_str_vappendf( sqlite3_str_appendall(pAccum, pItem->zAlias); }else{ Select *pSel = pItem->pSelect; - assert( pSel!=0 ); /* Because of tag-20240424-1 */ + assert( pSel!=0 ); if( pSel->selFlags & SF_NestedFrom ){ sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId); - }else if( pSel->selFlags & SF_MultiValue ){ - assert( !pItem->fg.isTabFunc && !pItem->fg.isIndexedBy ); - sqlite3_str_appendf(pAccum, "%u-ROW VALUES CLAUSE", - pItem->u1.nRow); }else{ sqlite3_str_appendf(pAccum, "(subquery-%u)", pSel->selId); } @@ -32083,9 +30804,9 @@ SQLITE_PRIVATE void sqlite3RecordErrorOffsetOfExpr(sqlite3 *db, const Expr *pExp ** 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 sqlite3StrAccumEnlarge(StrAccum *p, i64 N){ +SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum *p, int N){ char *zNew; - assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */ + assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */ if( p->accError ){ testcase(p->accError==SQLITE_TOOBIG); testcase(p->accError==SQLITE_NOMEM); @@ -32096,7 +30817,8 @@ SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum *p, i64 N){ return p->nAlloc - p->nChar - 1; }else{ char *zOld = isMalloced(p) ? p->zText : 0; - i64 szNew = p->nChar + N + 1; + i64 szNew = p->nChar; + szNew += (sqlite3_int64)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 */ @@ -32126,8 +30848,7 @@ SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum *p, i64 N){ return 0; } } - assert( N>=0 && N<=0x7fffffff ); - return (int)N; + return N; } /* @@ -32418,22 +31139,12 @@ SQLITE_API char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_li return zBuf; } SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ - StrAccum acc; + char *z; 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 - sqlite3StrAccumInit(&acc, 0, zBuf, n, 0); va_start(ap,zFormat); - sqlite3_str_vappendf(&acc, zFormat, ap); + z = sqlite3_vsnprintf(n, zBuf, zFormat, ap); va_end(ap); - zBuf[acc.nChar] = 0; - return zBuf; + return z; } /* @@ -32511,75 +31222,6 @@ SQLITE_API void 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 *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 sqlite3RCStrUnref(void *z){ - RCStr *p = (RCStr*)z; - assert( p!=0 ); - p--; - assert( p->nRCRef>0 ); - if( p->nRCRef>=2 ){ - p->nRCRef--; - }else{ - 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 sqlite3RCStrUnref() to free the -** newly allocated string. -** -** This routine returns 0 on an OOM. -*/ -SQLITE_PRIVATE char *sqlite3RCStrNew(u64 N){ - RCStr *p = 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 *sqlite3RCStrResize(char *z, u64 N){ - RCStr *p = (RCStr*)z; - RCStr *pNew; - assert( p!=0 ); - p--; - assert( p->nRCRef==1 ); - pNew = sqlite3_realloc64(p, N+sizeof(RCStr)+1); - if( pNew==0 ){ - sqlite3_free(p); - return 0; - }else{ - return (char*)&pNew[1]; - } -} - /************** End of printf.c **********************************************/ /************** Begin file treeview.c ****************************************/ /* @@ -32778,10 +31420,8 @@ SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc) x.printfFlags |= SQLITE_PRINTF_INTERNAL; sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem); if( pItem->pTab ){ - 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" : ""); + sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx", + pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->colUsed); } if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==(JT_LEFT|JT_RIGHT) ){ sqlite3_str_appendf(&x, " FULL-OUTER-JOIN"); @@ -32804,13 +31444,6 @@ SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc) if( pItem->fg.isOn || (pItem->fg.isUsing==0 && pItem->u3.pOn!=0) ){ sqlite3_str_appendf(&x, " ON"); } - if( pItem->fg.isTabFunc ) sqlite3_str_appendf(&x, " isTabFunc"); - if( pItem->fg.isCorrelated ) sqlite3_str_appendf(&x, " isCorrelated"); - if( pItem->fg.isMaterialized ) sqlite3_str_appendf(&x, " isMaterialized"); - if( pItem->fg.viaCoroutine ) sqlite3_str_appendf(&x, " viaCoroutine"); - if( pItem->fg.notCte ) sqlite3_str_appendf(&x, " notCte"); - if( pItem->fg.isNestedFrom ) sqlite3_str_appendf(&x, " isNestedFrom"); - sqlite3StrAccumFinish(&x); sqlite3TreeViewItem(pView, zLine, inSrc-1); n = 0; @@ -32821,14 +31454,12 @@ SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc) sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING"); } if( pItem->pSelect ){ - sqlite3TreeViewPush(&pView, i+1nSrc); if( pItem->pTab ){ Table *pTab = pItem->pTab; sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1); } assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) ); sqlite3TreeViewSelect(pView, pItem->pSelect, (--n)>0); - sqlite3TreeViewPop(&pView); } if( pItem->fg.isTabFunc ){ sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:"); @@ -32932,7 +31563,7 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m sqlite3TreeViewItem(pView, "LIMIT", (n--)>0); sqlite3TreeViewExpr(pView, p->pLimit->pLeft, p->pLimit->pRight!=0); if( p->pLimit->pRight ){ - sqlite3TreeViewItem(pView, "OFFSET", 0); + sqlite3TreeViewItem(pView, "OFFSET", (n--)>0); sqlite3TreeViewExpr(pView, p->pLimit->pRight, 0); sqlite3TreeViewPop(&pView); } @@ -33000,7 +31631,6 @@ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u sqlite3TreeViewItem(pView, "FILTER", 1); sqlite3TreeViewExpr(pView, pWin->pFilter, 0); sqlite3TreeViewPop(&pView); - if( pWin->eFrmType==TK_FILTER ) return; } sqlite3TreeViewPush(&pView, more); if( pWin->zName ){ @@ -33010,7 +31640,7 @@ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u } if( pWin->zBase ) nElement++; if( pWin->pOrderBy ) nElement++; - if( pWin->eFrmType!=0 && pWin->eFrmType!=TK_FILTER ) nElement++; + if( pWin->eFrmType ) nElement++; if( pWin->eExclude ) nElement++; if( pWin->zBase ){ sqlite3TreeViewPush(&pView, (--nElement)>0); @@ -33023,7 +31653,7 @@ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u if( pWin->pOrderBy ){ sqlite3TreeViewExprList(pView, pWin->pOrderBy, (--nElement)>0, "ORDER-BY"); } - if( pWin->eFrmType!=0 && pWin->eFrmType!=TK_FILTER ){ + if( pWin->eFrmType ){ char zBuf[30]; const char *zFrmType = "ROWS"; if( pWin->eFrmType==TK_RANGE ) zFrmType = "RANGE"; @@ -33083,7 +31713,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m sqlite3TreeViewPop(&pView); return; } - if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags || pExpr->pAggInfo ){ + if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags ){ StrAccum x; sqlite3StrAccumInit(&x, 0, zFlgs, sizeof(zFlgs), 0); sqlite3_str_appendf(&x, " fg.af=%x.%c", @@ -33100,9 +31730,6 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m if( ExprHasVVAProperty(pExpr, EP_Immutable) ){ sqlite3_str_appendf(&x, " IMMUTABLE"); } - if( pExpr->pAggInfo!=0 ){ - sqlite3_str_appendf(&x, " agg-column[%d]", pExpr->iAgg); - } sqlite3StrAccumFinish(&x); }else{ zFlgs[0] = 0; @@ -33232,8 +31859,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m }; assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT ); assert( pExpr->pRight ); - assert( sqlite3ExprSkipCollateAndLikely(pExpr->pRight)->op - == TK_TRUEFALSE ); + assert( sqlite3ExprSkipCollate(pExpr->pRight)->op==TK_TRUEFALSE ); x = (pExpr->op2==TK_ISNOT)*2 + sqlite3ExprTruthValue(pExpr->pRight); zUniOp = azOp[x]; break; @@ -33271,7 +31897,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m assert( ExprUseXList(pExpr) ); pFarg = pExpr->x.pList; #ifndef SQLITE_OMIT_WINDOWFUNC - pWin = IsWindowFunc(pExpr) ? pExpr->y.pWin : 0; + pWin = ExprHasProperty(pExpr, EP_WinFunc) ? pExpr->y.pWin : 0; #else pWin = 0; #endif @@ -33297,13 +31923,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m sqlite3TreeViewLine(pView, "FUNCTION %Q%s", pExpr->u.zToken, zFlgs); } if( pFarg ){ - sqlite3TreeViewExprList(pView, pFarg, pWin!=0 || pExpr->pLeft, 0); - if( pExpr->pLeft ){ - Expr *pOB = pExpr->pLeft; - assert( pOB->op==TK_ORDER ); - assert( ExprUseXList(pOB) ); - sqlite3TreeViewExprList(pView, pOB->x.pList, pWin!=0, "ORDERBY"); - } + sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0); } #ifndef SQLITE_OMIT_WINDOWFUNC if( pWin ){ @@ -33312,10 +31932,6 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m #endif break; } - case TK_ORDER: { - sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, "ORDERBY"); - break; - } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: { assert( ExprUseXSelect(pExpr) ); @@ -33369,7 +31985,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m assert( pExpr->x.pList->nExpr==2 ); pY = pExpr->x.pList->a[0].pExpr; pZ = pExpr->x.pList->a[1].pExpr; - sqlite3TreeViewLine(pView, "BETWEEN%s", zFlgs); + sqlite3TreeViewLine(pView, "BETWEEN"); sqlite3TreeViewExpr(pView, pX, 1); sqlite3TreeViewExpr(pView, pY, 1); sqlite3TreeViewExpr(pView, pZ, 0); @@ -34504,38 +33120,7 @@ SQLITE_PRIVATE u32 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 sqlite3Utf8ReadLimited( - const u8 *z, - int n, - u32 *piOut -){ - u32 c; - int i = 1; - assert( n>0 ); - c = z[0]; - if( c>=0xc0 ){ - c = sqlite3Utf8Trans1[c-0xc0]; - if( n>4 ) n = 4; - while( inDb; ii++){ - if( db->aDb[ii].pBt ){ - iErr = sqlite3PagerWalSystemErrno(sqlite3BtreePager(db->aDb[ii].pBt)); - if( iErr ){ - db->iSysErrno = iErr; - } - } - } - sqlite3BtreeLeaveAll(db); - return; - } -#endif rc &= 0xff; if( rc==SQLITE_CANTOPEN || rc==SQLITE_IOERR ){ db->iSysErrno = sqlite3OsGetLastError(db->pVfs); @@ -35114,30 +33669,6 @@ SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *z } } -/* -** Check for interrupts and invoke progress callback. -*/ -SQLITE_PRIVATE void sqlite3ProgressCheck(Parse *p){ - 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. ** @@ -35233,44 +33764,6 @@ SQLITE_PRIVATE void sqlite3DequoteExpr(Expr *p){ sqlite3Dequote(p->u.zToken); } -/* -** 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 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 && (!sqlite3Isdigit(pIn[-1]) || !sqlite3Isdigit(pIn[1]))) - || (bHex==1 && (!sqlite3Isxdigit(pIn[-1]) || !sqlite3Isxdigit(pIn[1]))) - ){ - 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 && 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: @@ -35367,40 +33860,43 @@ SQLITE_PRIVATE u8 sqlite3StrIHash(const char *z){ return h; } -/* Double-Double multiplication. (x[0],x[1]) *= (y,yy) +/* +** Compute 10 to the E-th power. Examples: E==1 results in 10. +** E==2 results in 100. E==50 results in 1.0e50. ** -** Reference: -** T. J. Dekker, "A Floating-Point Technique for Extending the -** Available Precision". 1971-07-26. +** This routine only works for values of E between 1 and 341. */ -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; +static LONGDOUBLE_TYPE 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 } /* @@ -35441,11 +33937,12 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en const char *zEnd; /* sign * significand * (10 ^ (esign * exponent)) */ int sign = 1; /* sign of significand */ - u64 s = 0; /* significand */ + i64 s = 0; /* significand */ int d = 0; /* adjust exponent for shifting decimal point */ int esign = 1; /* sign of exponent */ int e = 0; /* exponent */ int eValid = 1; /* True exponent is either not used or is well-formed */ + double result; int nDigit = 0; /* Number of digits processed */ int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */ @@ -35485,7 +33982,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en while( z=((LARGEST_UINT64-9)/10) ){ + if( s>=((LARGEST_INT64-9)/10) ){ /* skip non-significant significand digits ** (increase exponent by d to shift decimal left) */ while( z0 && s<(LARGEST_UINT64/10) ){ - s *= 10; - e--; - } - while( e<0 && (s%10)==0 ){ - s /= 10; - e++; + if( e<0 ) { + esign = -1; + e *= -1; + } else { + esign = 1; } - if( e==0 ){ - *pResult = s; - }else if( 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{ - 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; } + 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--; } - assert( r>=0.0 ); - if( r>+1.7976931348623157081452742373e+308L ){ + + /* adjust the sign of significand */ + s = sign<0 ? -s : s; + + 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 = 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 - *pResult = +INFINITY; + result = INFINITY*s; #else - *pResult = 1.0e308*10.0; + result = 1e308*1e308*s; /* Infinity */ #endif - }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); + } + } + }else{ + LONGDOUBLE_TYPE scale = sqlite3Pow10(e); + if( esign<0 ){ + result = s / scale; + }else{ + result = s * scale; + } } } - *pResult = rr[0]+rr[1]; - if( sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300; } - if( sign<0 ) *pResult = -*pResult; - assert( !sqlite3IsNaN(*pResult) ); -atof_return: - /* return true if number and no extra non-whitespace characters after */ + /* store the result */ + *pResult = result; + + /* return true if number and no extra non-whitespace chracters after */ if( z==zEnd && nDigit>0 && eValid && eType>0 ){ return eType; }else if( eType>=2 && (eType==3 || eValid) && nDigit>0 ){ @@ -35642,14 +34126,11 @@ atof_return: #endif /* -** 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. +** Render an signed 64-bit integer as text. Store the result in zOut[]. ** ** The caller must ensure that zOut[] is at least 21 bytes in size. */ -SQLITE_PRIVATE int sqlite3Int64ToText(i64 v, char *zOut){ +SQLITE_PRIVATE void sqlite3Int64ToText(i64 v, char *zOut){ int i; u64 x; char zTemp[22]; @@ -35660,15 +34141,12 @@ SQLITE_PRIVATE int sqlite3Int64ToText(i64 v, char *zOut){ } i = sizeof(zTemp)-2; zTemp[sizeof(zTemp)-1] = 0; - while( 1 /*exit-by-break*/ ){ - zTemp[i] = (x%10) + '0'; + do{ + zTemp[i--] = (x%10) + '0'; x = x/10; - if( x==0 ) break; - i--; - }; - if( v<0 ) zTemp[--i] = '-'; - memcpy(zOut, &zTemp[i], sizeof(zTemp)-i); - return sizeof(zTemp)-1-i; + }while( x ); + if( v<0 ) zTemp[i--] = '-'; + memcpy(zOut, &zTemp[i+1], sizeof(zTemp)-1-i); } /* @@ -35761,7 +34239,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc /* 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 appease the undefined-behavior pharisees. */ + ** them, but we must appaise the undefined-behavior pharisees. */ *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64; }else if( neg ){ *pNum = -(i64)u; @@ -35833,15 +34311,11 @@ SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){ u = u*16 + sqlite3HexToInt(z[k]); } memcpy(pOut, &u, 8); - if( k-i>16 ) return 2; - if( z[k]!=0 ) return 1; - return 0; + return (z[k]==0 && k-i<=16) ? 0 : 2; }else #endif /* SQLITE_OMIT_HEX_INTEGER */ { - int n = (int)(0x3fffffff&strspn(z,"+- \n\t0123456789")); - if( z[n] ) n++; - return sqlite3Atoi64(z, pOut, n, SQLITE_UTF8); + return sqlite3Atoi64(z, pOut, sqlite3Strlen30(z), SQLITE_UTF8); } } @@ -35873,7 +34347,7 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){ u32 u = 0; zNum += 2; while( zNum[0]=='0' ) zNum++; - for(i=0; i<8 && sqlite3Isxdigit(zNum[i]); i++){ + for(i=0; sqlite3Isxdigit(zNum[i]) && i<8; i++){ u = u*16 + sqlite3HexToInt(zNum[i]); } if( (u&0x80000000)==0 && sqlite3Isxdigit(zNum[i])==0 ){ @@ -35920,153 +34394,6 @@ SQLITE_PRIVATE int sqlite3Atoi(const char *z){ return x; } -/* -** 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 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( 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 && izBuf)-1 ); - p->n = sizeof(p->zBuf) - 1 - i; - assert( p->n>0 ); - assert( p->nzBuf) ); - 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 && (iRoundn || 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. @@ -36330,32 +34657,121 @@ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){ ** this function assumes the single-byte case has already been handled. */ SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){ - u64 v64; - u8 n; + u32 a,b; - /* Assume that the single-byte case has already been handled by - ** the getVarint32() macro */ - assert( (p[0] & 0x80)!=0 ); + /* 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 - if( (p[1] & 0x80)==0 ){ - /* This is the two-byte case */ - *v = ((p[0]&0x7f)<<7) | p[1]; + /* The 2-byte case */ + p++; + b = *p; + /* b: p1 (unmasked) */ + if (!(b&0x80)) + { + /* Values between 128 and 16383 */ + a &= 0x7f; + a = a<<7; + *v = a | b; return 2; } - if( (p[2] & 0x80)==0 ){ - /* This is the three-byte case */ - *v = ((p[0]&0x7f)<<14) | ((p[1]&0x7f)<<7) | p[2]; + + /* The 3-byte case */ + p++; + a = a<<14; + a |= *p; + /* a: p0<<14 | p2 (unmasked) */ + if (!(a&0x80)) + { + /* Values between 16384 and 2097151 */ + a &= (0x7f<<14)|(0x7f); + b &= 0x7f; + b = b<<7; + *v = a | b; return 3; } - /* four or more bytes */ - n = sqlite3GetVarint(p, &v64); - assert( n>3 && n<=9 ); - if( (v64 & SQLITE_MAX_U32)!=v64 ){ - *v = 0xffffffff; - }else{ + + /* 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 = 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 sqlite3GetVarint() routine to extract the + ** value. */ + { + u64 v64; + u8 n; + + p -= 4; + n = sqlite3GetVarint(p, &v64); + assert( n>5 && n<=9 ); *v = (u32)v64; + return n; } - return n; +#endif } /* @@ -36506,7 +34922,7 @@ SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){ } /* -** Attempt to add, subtract, or multiply the 64-bit signed value iB against +** Attempt to add, substract, 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. @@ -36792,104 +35208,6 @@ SQLITE_PRIVATE int sqlite3VListNameToNum(VList *pIn, const char *zName, int nNam 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 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 sqlite3Hwtime(void){ - __asm { - rdtsc - ret ; return value at EDX:EAX - } - } - - #endif - -#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__)) - - __inline__ sqlite_uint64 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 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 sqlite3Hwtime() routine. - ** - ** 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 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 ********************************************/ /* @@ -36991,7 +35309,7 @@ static void insertElement( } -/* Resize the hash table so that it contains "new_size" buckets. +/* Resize the hash table so that it cantains "new_size" buckets. ** ** The hash table might fail to resize if sqlite3_malloc() fails or ** if the new size is the same as the prior size. @@ -37060,13 +35378,12 @@ static HashElem *findElementWithHash( count = pH->count; } if( pHash ) *pHash = h; - while( count ){ + while( count-- ){ assert( elem!=0 ); if( sqlite3StrICmp(elem->pKey,pKey)==0 ){ return elem; } elem = elem->next; - count--; } return &nullElement; } @@ -37210,7 +35527,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 30 */ "SeekRowid" OpHelp("intkey=r[P3]"), /* 31 */ "NotExists" OpHelp("intkey=r[P3]"), /* 32 */ "Last" OpHelp(""), - /* 33 */ "IfSizeBetween" OpHelp(""), + /* 33 */ "IfSmaller" OpHelp(""), /* 34 */ "SorterSort" OpHelp(""), /* 35 */ "Sort" OpHelp(""), /* 36 */ "Rewind" OpHelp(""), @@ -37255,7 +35572,7 @@ SQLITE_PRIVATE const char *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)"), + /* 78 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), /* 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]"), @@ -37351,22 +35668,19 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 171 */ "VCreate" OpHelp(""), /* 172 */ "VDestroy" OpHelp(""), /* 173 */ "VOpen" 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(""), + /* 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(""), }; return azName[i]; } @@ -37428,9 +35742,7 @@ struct KVVfsFile { char *aJrnl; /* Journal content */ int szPage; /* Last known page size */ sqlite3_int64 szDb; /* Database file size. -1 means unknown */ - char *aData; /* Buffer to hold page data */ }; -#define SQLITE_KVOS_SZ 133073 /* ** Methods for KVVfsFile @@ -37793,7 +36105,8 @@ static int kvvfsDecode(const char *a, char *aOut, int nOut){ if( j+n>nOut ) return -1; memset(&aOut[j], 0, n); j += n; - if( c==0 || mult==1 ) break; /* progress stalled if mult==1 */ + c = aIn[i]; + if( c==0 ) break; }else{ aOut[j] = c<<4; c = kvvfsHexValue[aIn[++i]]; @@ -37870,7 +36183,6 @@ static int kvvfsClose(sqlite3_file *pProtoFile){ SQLITE_KV_LOG(("xClose %s %s\n", pFile->zClass, pFile->isJournal ? "journal" : "db")); sqlite3_free(pFile->aJrnl); - sqlite3_free(pFile->aData); return SQLITE_OK; } @@ -37919,7 +36231,7 @@ static int kvvfsReadDb( unsigned int pgno; int got, n; char zKey[30]; - char *aData = pFile->aData; + char aData[133073]; assert( iOfst>=0 ); assert( iAmt>=0 ); SQLITE_KV_LOG(("xRead('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst)); @@ -37936,8 +36248,7 @@ static int kvvfsReadDb( pgno = 1; } sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno); - got = sqlite3KvvfsMethods.xRead(pFile->zClass, zKey, - aData, SQLITE_KVOS_SZ-1); + got = sqlite3KvvfsMethods.xRead(pFile->zClass, zKey, aData, sizeof(aData)-1); if( got<0 ){ n = 0; }else{ @@ -37945,7 +36256,7 @@ static int kvvfsReadDb( if( iOfst+iAmt<512 ){ int k = iOfst+iAmt; aData[k*2] = 0; - n = kvvfsDecode(aData, &aData[2000], SQLITE_KVOS_SZ-2000); + n = kvvfsDecode(aData, &aData[2000], sizeof(aData)-2000); if( n>=iOfst+iAmt ){ memcpy(zBuf, &aData[2000+iOfst], iAmt); n = iAmt; @@ -38004,7 +36315,7 @@ static int kvvfsWriteDb( KVVfsFile *pFile = (KVVfsFile*)pProtoFile; unsigned int pgno; char zKey[30]; - char *aData = pFile->aData; + char aData[131073]; SQLITE_KV_LOG(("xWrite('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst)); assert( iAmt>=512 && iAmt<=65536 ); assert( (iAmt & (iAmt-1))==0 ); @@ -38213,10 +36524,6 @@ static int kvvfsOpen( }else{ pFile->zClass = "local"; } - pFile->aData = sqlite3_malloc64(SQLITE_KVOS_SZ); - if( pFile->aData==0 ){ - return SQLITE_NOMEM; - } pFile->aJrnl = 0; pFile->nJrnl = 0; pFile->szPage = -1; @@ -38380,7 +36687,7 @@ SQLITE_PRIVATE int 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 labelled. +** in the correct division and should be clearly labeled. ** ** The layout of divisions is as follows: ** @@ -38430,7 +36737,7 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){ #endif /* Use pread() and pwrite() if they are available */ -#if defined(__APPLE__) || defined(__linux__) +#if defined(__APPLE__) # define HAVE_PREAD 1 # define HAVE_PWRITE 1 #endif @@ -38453,8 +36760,7 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){ /* #include */ #include /* amalgamator: keep */ #include -#if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \ - && !defined(SQLITE_WASI) +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 # include #endif @@ -38542,46 +36848,9 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){ */ #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() -#endif +#define osGetpid(X) (pid_t)getpid() /* ** Only set the lastErrno if the error code is a real error and not @@ -38853,11 +37122,7 @@ static struct unix_syscall { #define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\ aSyscall[13].pCurrent) -#if defined(HAVE_FCHMOD) { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 }, -#else - { "fchmod", (sqlite3_syscall_ptr)0, 0 }, -#endif #define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent) #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE @@ -38893,16 +37158,14 @@ static struct unix_syscall { #endif #define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent) -#if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \ - && !defined(SQLITE_WASI) +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 { "mmap", (sqlite3_syscall_ptr)mmap, 0 }, #else { "mmap", (sqlite3_syscall_ptr)0, 0 }, #endif #define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent) -#if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \ - && !defined(SQLITE_WASI) +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 { "munmap", (sqlite3_syscall_ptr)munmap, 0 }, #else { "munmap", (sqlite3_syscall_ptr)0, 0 }, @@ -38967,7 +37230,7 @@ static int robustFchown(int fd, uid_t uid, gid_t gid){ /* ** This is the xSetSystemCall() method of sqlite3_vfs for all of the -** "unix" VFSes. Return SQLITE_OK upon successfully updating the +** "unix" VFSes. Return SQLITE_OK opon successfully updating the ** system call pointer, or SQLITE_NOTFOUND if there is no configurable ** system call named zName. */ @@ -39489,7 +37752,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 the inode. +** maintains a count of the number of pending locks on tha inode. ** When an attempt is made to close an unixFile, if there are ** other unixFile open on the same inode that are holding locks, the call ** to close() the file descriptor is deferred until all of the locks clear. @@ -39503,7 +37766,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 application uses the newer Native Posix Thread Library (NPTL) +** if the appliation 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 @@ -39653,12 +37916,8 @@ 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)) \ - && !defined(ANDROID) && !defined(__ANDROID__) +#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU) zErr = # endif strerror_r(iErrno, aErr, sizeof(aErr)-1); @@ -39709,7 +37968,7 @@ static void storeLastErrno(unixFile *pFile, int error){ } /* -** Close all file descriptors accumulated in the unixInodeInfo->pUnused list. +** Close all file descriptors accumuated in the unixInodeInfo->pUnused list. */ static void closePendingFds(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; @@ -40057,7 +38316,7 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){ ** ** UNLOCKED -> SHARED ** SHARED -> RESERVED -** SHARED -> EXCLUSIVE +** SHARED -> (PENDING) -> EXCLUSIVE ** RESERVED -> (PENDING) -> EXCLUSIVE ** PENDING -> EXCLUSIVE ** @@ -40072,7 +38331,7 @@ static int unixLock(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 identify the 'pending byte' and the 'reserved + ** Symbols defined in os.h indentify 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. ** @@ -40080,7 +38339,7 @@ static int unixLock(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 Windows95 lacks a shared-lock capability. So on Windows95, a + ** and Widnows95 lacks a shared-lock capability. So on Windows95, a ** single randomly selected by from the 'shared byte range' is locked. ** Windows95 is now pretty much extinct, but this work-around for the ** lack of shared-locks on Windows95 lives on, for backwards @@ -40090,20 +38349,19 @@ static int unixLock(sqlite3_file *id, int eFileLock){ ** A RESERVED lock is implemented by grabbing a write-lock on the ** 'reserved byte'. ** - ** 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. + ** 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. ** - ** 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. + ** 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. */ int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; @@ -40129,7 +38387,7 @@ static int unixLock(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 pending lock. + ** (2) SQLite never explicitly requests a pendig lock. ** (3) A shared lock is always held when a reserve lock is requested. */ assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK ); @@ -40174,7 +38432,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ lock.l_len = 1L; lock.l_whence = SEEK_SET; if( eFileLock==SHARED_LOCK - || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock==RESERVED_LOCK) + || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLockeFileLock = PENDING_LOCK; - pInode->eFileLock = PENDING_LOCK; } } @@ -40275,9 +38530,13 @@ static int unixLock(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: @@ -41347,7 +39606,7 @@ static int afpLock(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 pending lock. + ** (2) SQLite never explicitly requests a pendig lock. ** (3) A shared lock is always held when a reserve lock is requested. */ assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK ); @@ -41463,7 +39722,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){ if( !(failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST + pInode->sharedByte, 1, 0)) ){ int failed2 = SQLITE_OK; - /* now attempt to get the exclusive lock range */ + /* now attemmpt to get the exclusive lock range */ failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 1); if( failed && (failed2 = afpSetLock(context->dbPath, pFile, @@ -41512,6 +39771,9 @@ static int afpUnlock(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, @@ -41527,6 +39789,9 @@ static int afpUnlock(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 @@ -41575,6 +39840,9 @@ static int afpUnlock(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); } @@ -41675,6 +39943,12 @@ static int nfsUnlock(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. */ @@ -41749,7 +40023,7 @@ static int unixRead( #endif #if SQLITE_MAX_MMAP_SIZE>0 - /* Deal with as much of this read request as possible by transferring + /* Deal with as much of this read request as possible by transfering ** data from the memory mapping using memcpy(). */ if( offsetmmapSize ){ if( offset+amt <= pFile->mmapSize ){ @@ -41901,7 +40175,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 transferring + /* Deal with as much of this write request as possible by transfering ** data from the memory mapping using memcpy(). */ if( offsetmmapSize ){ if( offset+amt <= pFile->mmapSize ){ @@ -42023,7 +40297,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 - ** coverage testing. + ** coverate testing. */ #ifdef SQLITE_NO_SYNC { @@ -42416,13 +40690,7 @@ static int unixFileControl(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; } @@ -42675,25 +40943,6 @@ 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 */ @@ -42707,11 +40956,10 @@ 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 - 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 }; @@ -42794,35 +41042,16 @@ 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 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 || sqlite3_mutex_held(pShmNode->pShmMutex) ); - }else{ -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT - int ii; - for(ii=ofst-UNIX_SHM_BASE; iiaMutex[ii]) ); - } -#else - assert( sqlite3_mutex_held(pShmNode->pShmMutex) ); - assert( pShmNode->nRef>0 ); -#endif - } + assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) ); + assert( pShmNode->nRef>0 || unixMutexHeld() ); /* 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; @@ -42833,7 +41062,7 @@ static int unixShmSystemLock( f.l_len = n; res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile); if( res==-1 ){ -#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && SQLITE_ENABLE_SETLK_TIMEOUT==1 +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY); #else rc = SQLITE_BUSY; @@ -42841,28 +41070,39 @@ static int unixShmSystemLock( } } - /* Do debug tracing */ + /* Update the global lock state and do debug tracing */ #ifdef SQLITE_DEBUG + { u16 mask; OSTRACE(("SHM-LOCK ")); + mask = ofst>31 ? 0xffff : (1<<(ofst+n)) - (1<exclMask &= ~mask; + pShmNode->sharedMask &= ~mask; }else if( lockType==F_RDLCK ){ - OSTRACE(("read-lock %d..%d ok\n", ofst, ofst+n-1)); + OSTRACE(("read-lock %d ok", ofst)); + pShmNode->exclMask &= ~mask; + pShmNode->sharedMask |= mask; }else{ assert( lockType==F_WRLCK ); - OSTRACE(("write-lock %d..%d ok\n", ofst, ofst+n-1)); + OSTRACE(("write-lock %d ok", ofst)); + pShmNode->exclMask |= mask; + pShmNode->sharedMask &= ~mask; } }else{ if( lockType==F_UNLCK ){ - OSTRACE(("unlock %d..%d failed\n", ofst, ofst+n-1)); + OSTRACE(("unlock %d failed", ofst)); }else if( lockType==F_RDLCK ){ - OSTRACE(("read-lock %d..%d failed\n", ofst, ofst+n-1)); + OSTRACE(("read-lock failed")); }else{ assert( lockType==F_WRLCK ); - OSTRACE(("write-lock %d..%d failed\n", ofst, ofst+n-1)); + OSTRACE(("write-lock %d failed", ofst)); } } + OSTRACE((" - afterwards %03x,%03x\n", + pShmNode->sharedMask, pShmNode->exclMask)); + } #endif return rc; @@ -42899,11 +41139,6 @@ static void unixShmPurge(unixFile *pFd){ int i; assert( p->pInode==pFd->pInode ); sqlite3_mutex_free(p->pShmMutex); -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT - for(i=0; iaMutex[i]); - } -#endif for(i=0; inRegion; i+=nShmPerMap){ if( p->hShm>=0 ){ osMunmap(p->apRegion[i], p->szRegion); @@ -42963,20 +41198,7 @@ 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 @@ -43097,18 +41319,6 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ rc = SQLITE_NOMEM_BKPT; goto shm_open_err; } -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT - { - int ii; - for(ii=0; iiaMutex[ii] = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); - if( pShmNode->aMutex[ii]==0 ){ - rc = SQLITE_NOMEM_BKPT; - goto shm_open_err; - } - } - } -#endif } if( pInode->bProcessLock==0 ){ @@ -43330,11 +41540,9 @@ 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( sqlite3_mutex_held(pShmNode->pShmMutex) ); memset(aLock, 0, sizeof(aLock)); for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ @@ -43352,14 +41560,13 @@ 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. @@ -43374,7 +41581,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 = (1<<(ofst+n)) - (1<pShm; @@ -43409,151 +41616,88 @@ static int unixShmLock( ** It is not permitted to block on the RECOVER lock. */ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT - { - 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<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<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)) - ){ - - /* Take the required mutexes. In SETLK_TIMEOUT mode (blocking locks), if - ** this is an attempt on an exclusive lock use 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 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; iMutexaMutex[iMutex]); - if( rc!=SQLITE_OK ) goto leave_shmnode_mutexes; - }else{ - sqlite3_mutex_enter(pShmNode->aMutex[iMutex]); - } - } -#else - sqlite3_mutex_enter(pShmNode->pShmMutex); -#endif + mask = (1<<(ofst+n)) - (1<1 || mask==(1<pShmMutex); + assert( assertLockingArrayOk(pShmNode) ); + if( flags & SQLITE_SHM_UNLOCK ){ + if( (p->exclMask|p->sharedMask) & mask ){ + int ii; + int bUnlock = 1; - 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; - } + for(ii=ofst; ii((p->sharedMask & (1<sharedMask &= ~mask; - p->exclMask &= ~mask; - } + if( bUnlock ){ + rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n); + if( rc==SQLITE_OK ){ + memset(&aLock[ofst], 0, sizeof(int)*n); } - }else if( flags & SQLITE_SHM_SHARED ){ - /* Case (b) - a shared lock. */ + }else if( ALWAYS(p->sharedMask & (1<1 ); + aLock[ofst]--; + } - 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); - } + /* 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<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); + } - /* Get the local shared locks */ - if( rc==SQLITE_OK ){ - p->sharedMask |= mask; - aLock[ofst]++; - } - }else{ - /* Case (c) - an exclusive lock. */ - int ii; + /* 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; iisharedMask & mask)==0 ); + if( ALWAYS((p->exclMask & (1<sharedMask & mask)==0 ); - 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. */ + p->exclMask |= mask; for(ii=ofst; iiexclMask |= mask; - for(ii=ofst; ii=ofst; iMutex--){ - sqlite3_mutex_leave(pShmNode->aMutex[iMutex]); } -#else - sqlite3_mutex_leave(pShmNode->pShmMutex); -#endif } - + assert( assertLockingArrayOk(pShmNode) ); + 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; @@ -43803,16 +41947,11 @@ static int unixFetch(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+nEofBuffer) ){ + if( pFd->mmapSize >= iOff+nAmt ){ *pp = &((u8 *)pFd->pMapRegion)[iOff]; pFd->nFetchOut++; } @@ -44756,19 +42895,12 @@ 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; - pReadonly = findReusableFd(zName, flags); - if( pReadonly ){ - fd = pReadonly->fd; - sqlite3_free(pReadonly); - }else{ - fd = robust_open(zName, openFlags, openMode); - } + fd = robust_open(zName, openFlags, openMode); } } if( fd<0 ){ @@ -44995,10 +43127,12 @@ static void appendOnePathElement( if( zName[0]=='.' ){ if( nName==1 ) return; if( zName[1]=='.' && nName==2 ){ - if( pPath->nUsed>1 ){ - assert( pPath->zOut[0]=='/' ); - while( pPath->zOut[--pPath->nUsed]!='/' ){} + if( pPath->nUsed<=1 ){ + pPath->rc = SQLITE_ERROR; + return; } + assert( pPath->zOut[0]=='/' ); + while( pPath->zOut[--pPath->nUsed]!='/' ){} return; } } @@ -45210,17 +43344,12 @@ static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){ ** than the argument. */ static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){ -#if !defined(HAVE_NANOSLEEP) || HAVE_NANOSLEEP+0 +#if OS_VXWORKS 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 @@ -47810,7 +45939,7 @@ static struct win_syscall { /* ** This is the xSetSystemCall() method of sqlite3_vfs for all of the -** "win32" VFSes. Return SQLITE_OK upon successfully updating the +** "win32" VFSes. Return SQLITE_OK opon successfully updating the ** system call pointer, or SQLITE_NOTFOUND if there is no configurable ** system call named zName. */ @@ -49390,7 +47519,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 transferring + /* Deal with as much of this read request as possible by transfering ** data from the memory mapping using memcpy(). */ if( offsetmmapSize ){ if( offset+amt <= pFile->mmapSize ){ @@ -49468,7 +47597,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 transferring + /* Deal with as much of this write request as possible by transfering ** data from the memory mapping using memcpy(). */ if( offsetmmapSize ){ if( offset+amt <= pFile->mmapSize ){ @@ -49578,7 +47707,7 @@ static int winTruncate(sqlite3_file *id, 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 transactions a no-op if there are pending reads. We + ** now to simply make trancations a no-op if there are pending reads. We ** can maybe revisit this decision in the future. */ return SQLITE_OK; @@ -49637,7 +47766,7 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ #ifdef SQLITE_TEST /* ** Count the number of fullsyncs and normal syncs. This is used to test -** that syncs and fullsyncs are occurring at the right times. +** that syncs and fullsyncs are occuring at the right times. */ SQLITE_API int sqlite3_sync_count = 0; SQLITE_API int sqlite3_fullsync_count = 0; @@ -49994,7 +48123,7 @@ static int winLock(sqlite3_file *id, int locktype){ */ if( locktype==EXCLUSIVE_LOCK && res ){ assert( pFile->locktype>=SHARED_LOCK ); - (void)winUnlockReadLock(pFile); + res = winUnlockReadLock(pFile); res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0, SHARED_SIZE, 0); if( res ){ @@ -51172,11 +49301,6 @@ static int winFetch(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 ){ @@ -51185,7 +49309,7 @@ static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){ return rc; } } - if( pFd->mmapSize >= (iOff+nAmt+nEofBuffer) ){ + if( pFd->mmapSize >= iOff+nAmt ){ assert( pFd->pMapRegion!=0 ); *pp = &((u8 *)pFd->pMapRegion)[iOff]; pFd->nFetchOut++; @@ -51403,7 +49527,6 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; size_t i, j; - DWORD pid; int nPre = sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX); int nMax, nBuf, nDir, nLen; char *zBuf; @@ -51616,10 +49739,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ j = sqlite3Strlen30(zBuf); 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; @@ -51857,7 +49977,7 @@ static int winOpen( if( isReadWrite ){ int rc2, isRO = 0; sqlite3BeginBenignMalloc(); - rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO); + rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO); sqlite3EndBenignMalloc(); if( rc2==SQLITE_OK && isRO ) break; } @@ -51874,7 +49994,7 @@ static int winOpen( if( isReadWrite ){ int rc2, isRO = 0; sqlite3BeginBenignMalloc(); - rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO); + rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO); sqlite3EndBenignMalloc(); if( rc2==SQLITE_OK && isRO ) break; } @@ -51894,7 +50014,7 @@ static int winOpen( if( isReadWrite ){ int rc2, isRO = 0; sqlite3BeginBenignMalloc(); - rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO); + rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO); sqlite3EndBenignMalloc(); if( rc2==SQLITE_OK && isRO ) break; } @@ -52117,13 +50237,6 @@ 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)); @@ -53664,14 +51777,6 @@ SQLITE_API unsigned char *sqlite3_serialize( pOut = 0; }else{ sz = sqlite3_column_int64(pStmt, 0)*szPage; - if( sz==0 ){ - sqlite3_reset(pStmt); - sqlite3_exec(db, "BEGIN IMMEDIATE; COMMIT;", 0, 0, 0); - rc = sqlite3_step(pStmt); - if( rc==SQLITE_ROW ){ - sz = sqlite3_column_int64(pStmt, 0)*szPage; - } - } if( piSize ) *piSize = sz; if( mFlags & SQLITE_SERIALIZE_NOCOPY ){ pOut = 0; @@ -53992,7 +52097,7 @@ SQLITE_PRIVATE int 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 */ - /* worrying about sub-dividing and re-hashing. */ + /* worring about sub-dividing and re-hashing. */ if( !p->u.aHash[h] ){ if (p->nSet<(BITVEC_NINT-1)) { goto bitvec_set_end; @@ -54259,7 +52364,7 @@ bitvec_end: struct PCache { PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */ PgHdr *pSynced; /* Last synced page in dirty page list */ - i64 nRefSum; /* Sum of ref counts over all pages */ + int 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 */ @@ -54288,15 +52393,11 @@ struct PCache { 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); - } + 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(" ptr %p\n", pPg); } static void pcacheDump(PCache *pCache){ int N; @@ -54309,8 +52410,9 @@ struct PCache { if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump; for(i=1; i<=N; i++){ pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0); + if( pLower==0 ) continue; pcachePageTrace(i, pLower); - if( pLower && ((PgHdr*)pLower)->pPage==0 ){ + if( ((PgHdr*)pLower)->pPage==0 ){ sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0); } } @@ -54325,7 +52427,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. */ -#if defined(SQLITE_ENABLE_EXPENSIVE_ASSERT) +#ifdef SQLITE_DEBUG static int pageOnDirtyList(PCache *pCache, PgHdr *pPg){ PgHdr *p; for(p=pCache->pDirty; p; p=p->pDirtyNext){ @@ -54333,16 +52435,6 @@ 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 /* @@ -54363,7 +52455,7 @@ SQLITE_PRIVATE int 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( pageNotOnDirtyList(pCache, pPg) );/* CLEAN pages not on dirtylist */ + assert( !pageOnDirtyList(pCache, pPg) );/* CLEAN pages not on dirty list */ }else{ assert( (pPg->flags & PGHDR_DIRTY)!=0 );/* If not CLEAN must be DIRTY */ assert( pPg->pDirtyNext==0 || pPg->pDirtyNext->pDirtyPrev==pPg ); @@ -54499,7 +52591,7 @@ static int numberOfCachePages(PCache *p){ return p->szCache; }else{ i64 n; - /* IMPLEMENTATION-OF: R-59858-46238 If the argument N is negative, then the + /* IMPLEMANTATION-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. */ @@ -54987,7 +53079,7 @@ static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){ } /* -** Sort the list of pages in ascending order by pgno. Pages are +** Sort the list of pages in accending order by pgno. Pages are ** connected by pDirty pointers. The pDirtyPrev pointers are ** corrupted by this sort. ** @@ -55046,14 +53138,14 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache *pCache){ ** This is not the total number of pages referenced, but the sum of the ** reference count for all pages. */ -SQLITE_PRIVATE i64 sqlite3PcacheRefCount(PCache *pCache){ +SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache *pCache){ return pCache->nRefSum; } /* ** Return the number of references to the page supplied as an argument. */ -SQLITE_PRIVATE i64 sqlite3PcachePageRefcount(PgHdr *p){ +SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){ return p->nRef; } @@ -55227,7 +53319,7 @@ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHd ** If N is positive, then N pages worth of memory are allocated using a single ** sqlite3Malloc() call and that memory is used for the first N pages allocated. ** Or if N is negative, then -1024*N bytes of memory are allocated and used -** for as many pages as can be accommodated. +** for as many pages as can be accomodated. ** ** Only one of (2) or (3) can be used. Once the memory available to (2) or ** (3) is exhausted, subsequent allocations fail over to the general-purpose @@ -55261,7 +53353,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 uninitialized gap is accessed. Using u16 +** can cause a valgrind error if the unitialized gap is accessed. Using u16 ** ensures there is no such gap, and therefore no bytes of uninitialized ** memory in the structure. ** @@ -56481,7 +54573,7 @@ SQLITE_PRIVATE void 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 number, then the +** two TESTs where the TESTs have the same batch nubmer, 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. @@ -57013,7 +55105,6 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 # define sqlite3WalFramesize(z) 0 # define sqlite3WalFindFrame(x,y,z) 0 # define sqlite3WalFile(x) 0 -# undef SQLITE_USE_SEH #else #define WAL_SAVEPOINT_NDATA 4 @@ -57120,10 +55211,6 @@ SQLITE_PRIVATE int sqlite3WalWriteLock(Wal *pWal, int bLock); SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db); #endif -#ifdef SQLITE_USE_SEH -SQLITE_PRIVATE int sqlite3WalSystemErrno(Wal*); -#endif - #endif /* ifndef SQLITE_OMIT_WAL */ #endif /* SQLITE_WAL_H */ @@ -57409,7 +55496,7 @@ int 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 performed) +** is reloaded from disk (and, if necessary, hot-journal rollback peformed) ** when a read-transaction is next opened on the pager (transitioning ** the pager into READER state). At that point the system has recovered ** from the error. @@ -57796,7 +55883,7 @@ struct Pager { char *zJournal; /* Name of the journal file */ int (*xBusyHandler)(void*); /* Function to call when busy */ void *pBusyHandlerArg; /* Context argument for xBusyHandler */ - u32 aStat[4]; /* Total cache hits, misses, writes, spills */ + int aStat[4]; /* Total cache hits, misses, writes, spills */ #ifdef SQLITE_TEST int nRead; /* Database pages read */ #endif @@ -57926,8 +56013,9 @@ SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){ #ifndef SQLITE_OMIT_WAL if( pPager->pWal ){ u32 iRead = 0; - (void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); - return iRead==0; + int rc; + rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); + return (rc==SQLITE_OK && iRead==0); } #endif return 1; @@ -58599,32 +56687,9 @@ static int writeJournalHdr(Pager *pPager){ memset(zHeader, 0, sizeof(aJournalMagic)+4); } - - /* The random check-hash initializer */ - if( pPager->journalMode!=PAGER_JOURNALMODE_MEMORY ){ - 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 sqlite3_randomness() call if possible - ** as it takes the global PRNG mutex. */ - i64 sz = 0; - sqlite3OsFileSize(pPager->jfd, &sz); - assert( sz==0 ); - assert( pPager->journalOff==journalHdrOffset(pPager) ); - assert( sqlite3JournalIsInMemory(pPager->jfd) ); - } -#endif + sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit); 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 */ @@ -58804,7 +56869,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 the super-journal +** The super-journal page checksum is the sum of the bytes in thesuper-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), @@ -58857,7 +56922,7 @@ static int writeSuperJournal(Pager *pPager, const char *zSuper){ } pPager->journalOff += (nSuper+20); - /* If the pager is in persistent-journal mode, then the physical + /* If the pager is in peristent-journal mode, then the physical ** journal-file may extend past the end of the 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 @@ -59027,7 +57092,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 have occurred. +** the pager to transition into the ERROR state may ahve occurred. ** The first argument is a pointer to the pager structure, the second ** the error-code about to be returned by a pager API function. The ** value returned is a copy of the second argument to this function. @@ -59268,9 +57333,6 @@ 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. @@ -59299,28 +57361,13 @@ 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 on the contents of the +** of data. Compute and return a checksum based ont the contents of the ** page of data and the current value of pPager->cksumInit. ** ** This is not a real checksum. It is really just the sum of the @@ -59753,8 +57800,6 @@ 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) @@ -60085,7 +58130,7 @@ end_playback: ** see if it is possible to delete the super-journal. */ assert( zSuper==&pPager->pTmpSpace[4] ); - memset(pPager->pTmpSpace, 0, 4); + memset(&zSuper[-4], 0, 4); rc = pager_delsuper(pPager, zSuper); testcase( rc!=SQLITE_OK ); } @@ -60286,7 +58331,7 @@ static int pagerWalFrames( assert( pPager->pWal ); assert( pList ); #ifdef SQLITE_DEBUG - /* Verify that the page list is in ascending order */ + /* Verify that the page list is in accending order */ for(p=pList; p && p->pDirty; p=p->pDirty){ assert( p->pgno < p->pDirty->pgno ); } @@ -60417,7 +58462,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 empty, or verify that the *-wal file does +** exists if the database is not empy, or verify that the *-wal file does ** not exist (by deleting it) if the database file is empty. ** ** If the database is not empty and the *-wal file exists, open the pager @@ -60706,6 +58751,7 @@ SQLITE_PRIVATE void 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 sqlite3PagerSetFlags( Pager *pPager, /* The pager to set safety level for */ unsigned pgFlags /* Various flags */ @@ -60740,6 +58786,7 @@ SQLITE_PRIVATE void sqlite3PagerSetFlags( pPager->doNotSpill |= SPILLFLAG_OFF; } } +#endif /* ** The following global variable is incremented whenever the library @@ -61827,7 +59874,11 @@ SQLITE_PRIVATE int 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 */ @@ -61837,6 +59888,7 @@ SQLITE_PRIVATE int 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). */ @@ -61884,6 +59936,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen( while( *z ){ z += strlen(z)+1; z += strlen(z)+1; + nUri++; } nUriByte = (int)(&z[1] - zUri); assert( nUriByte>=1 ); @@ -61946,13 +59999,12 @@ SQLITE_PRIVATE int 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 *)sqlite3MallocZero( ROUND8(sizeof(*pPager)) + /* Pager structure */ ROUND8(pcacheSize) + /* PCache object */ ROUND8(pVfs->szOsFile) + /* The main db file */ journalFileSize * 2 + /* The two journal files */ - SQLITE_PTRSIZE + /* Space to hold a pointer */ + sizeof(pPager) + /* Space to hold a pointer */ 4 + /* Database prefix */ nPathname + 1 + /* database filename */ nUriByte + /* query parameters */ @@ -61973,7 +60025,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen( pPager->sjfd = (sqlite3_file*)pPtr; pPtr += journalFileSize; pPager->jfd = (sqlite3_file*)pPtr; pPtr += journalFileSize; assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) ); - memcpy(pPtr, &pPager, SQLITE_PTRSIZE); pPtr += SQLITE_PTRSIZE; + memcpy(pPtr, &pPager, sizeof(pPager)); pPtr += sizeof(pPager); /* Fill in the Pager.zFilename and pPager.zQueryParam fields */ pPtr += 4; /* Skip zero prefix */ @@ -62027,7 +60079,9 @@ SQLITE_PRIVATE int sqlite3PagerOpen( int fout = 0; /* VFS flags returned by xOpen() */ rc = 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, @@ -62138,7 +60192,18 @@ act_like_temp_file: pPager->memDb = (u8)memDb; pPager->readOnly = (u8)readOnly; assert( useJournal || pPager->tempFile ); - sqlite3PagerSetFlags(pPager, (SQLITE_DEFAULT_SYNCHRONOUS+1)|PAGER_CACHESPILL); + 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); + } /* pPager->pFirst = 0; */ /* pPager->pFirstSynced = 0; */ /* pPager->pLast = 0; */ @@ -62164,18 +60229,15 @@ act_like_temp_file: /* ** Return the sqlite3_file for the main database given the name -** of the corresponding WAL or Journal name as passed into +** of the corresonding WAL or Journal name as passed into ** xOpen. */ SQLITE_API sqlite3_file *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--; } - p = zName - 4 - sizeof(Pager*); - assert( EIGHT_BYTE_ALIGNMENT(p) ); - pPager = *(Pager**)p; + pPager = *(Pager**)(zName - 4 - sizeof(Pager*)); return pPager->fd; } @@ -62670,10 +60732,6 @@ static int getPageNormal( if( !isOpen(pPager->fd) || pPager->dbSizepPager->mxPgno ){ rc = SQLITE_FULL; - if( pgno<=pPager->dbSize ){ - sqlite3PcacheRelease(pPg); - pPg = 0; - } goto pager_acquire_err; } if( noContent ){ @@ -62809,20 +60867,8 @@ SQLITE_PRIVATE int sqlite3PagerGet( DbPage **ppPage, /* Write a pointer to the page here */ int flags /* PAGER_GET_XXX flags */ ){ -#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 sqlite3PagerGet() */ + /* printf("PAGE %u\n", pgno); fflush(stdout); */ return pPager->xGet(pPager, pgno, ppPage, flags); -#endif } /* @@ -62850,12 +60896,10 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ /* ** Release a page reference. ** -** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be used -** if we know that the page being released is not the last reference to page1. +** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be +** used if we know that the page being released is not the last page. ** The btree layer always holds page1 open until the end, so these first -** 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. +** to routines can be used to release any page other than BtShared.pPage1. ** ** Use sqlite3PagerUnrefPageOne() to release page1. This latter routine ** checks the total number of outstanding pages and if the number of @@ -62871,7 +60915,7 @@ SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage *pPg){ sqlite3PcacheRelease(pPg); } /* Do not use this routine to release the last reference to page1 */ - assert( sqlite3PcacheRefCount(pPager->pPCache)>0 ); /* tag-20230419-2 */ + assert( sqlite3PcacheRefCount(pPager->pPCache)>0 ); } SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){ if( pPg ) sqlite3PagerUnrefNotNull(pPg); @@ -63420,7 +61464,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){ # define DIRECT_MODE isDirectMode #endif - if( !pPager->changeCountDone && pPager->dbSize>0 ){ + if( !pPager->changeCountDone && ALWAYS(pPager->dbSize>0) ){ PgHdr *pPgHdr; /* Reference to page 1 */ assert( !pPager->tempFile && isOpen(pPager->fd) ); @@ -63698,13 +61742,6 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( rc = 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 = sqlite3OsWrite(pPager->fd, pTmp, szPage, - ((i64)pPager->dbSize*pPager->pageSize)-szPage); - } if( rc==SQLITE_OK ){ rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0); } @@ -63939,11 +61976,11 @@ SQLITE_PRIVATE int *sqlite3PagerStats(Pager *pPager){ a[3] = pPager->eState==PAGER_OPEN ? -1 : (int) pPager->dbSize; a[4] = pPager->eState; a[5] = pPager->errCode; - a[6] = (int)pPager->aStat[PAGER_STAT_HIT] & 0x7fffffff; - a[7] = (int)pPager->aStat[PAGER_STAT_MISS] & 0x7fffffff; + a[6] = pPager->aStat[PAGER_STAT_HIT]; + a[7] = pPager->aStat[PAGER_STAT_MISS]; a[8] = 0; /* Used to be pPager->nOvfl */ a[9] = pPager->nRead; - a[10] = (int)pPager->aStat[PAGER_STAT_WRITE] & 0x7fffffff; + a[10] = pPager->aStat[PAGER_STAT_WRITE]; return a; } #endif @@ -63959,7 +61996,7 @@ SQLITE_PRIVATE int *sqlite3PagerStats(Pager *pPager){ ** reset parameter is non-zero, the cache hit or miss count is zeroed before ** returning. */ -SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, u64 *pnVal){ +SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){ assert( eStat==SQLITE_DBSTATUS_CACHE_HIT || eStat==SQLITE_DBSTATUS_CACHE_MISS @@ -64167,11 +62204,7 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){ */ SQLITE_PRIVATE const char *sqlite3PagerFilename(const Pager *pPager, int nullIfMemDb){ static const char zFake[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - if( nullIfMemDb && (pPager->memDb || sqlite3IsMemdb(pPager->pVfs)) ){ - return &zFake[4]; - }else{ - return pPager->zFilename; - } + return (nullIfMemDb && pPager->memDb) ? &zFake[4] : pPager->zFilename; } /* @@ -64195,7 +62228,7 @@ SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){ ** This will be either the rollback journal or the WAL file. */ SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){ -#ifdef SQLITE_OMIT_WAL +#if SQLITE_OMIT_WAL return pPager->jfd; #else return pPager->pWal ? sqlite3WalFile(pPager->pWal) : pPager->jfd; @@ -64471,7 +62504,7 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ assert( pPager->eState!=PAGER_ERROR ); pPager->journalMode = (u8)eMode; - /* When transitioning from TRUNCATE or PERSIST to any other journal + /* When transistioning from TRUNCATE or PERSIST to any other journal ** mode except WAL, unless the pager is in locking_mode=exclusive mode, ** delete the journal file. */ @@ -64516,7 +62549,7 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ } assert( state==pPager->eState ); } - }else if( eMode==PAGER_JOURNALMODE_OFF || eMode==PAGER_JOURNALMODE_MEMORY ){ + }else if( eMode==PAGER_JOURNALMODE_OFF ){ sqlite3OsClose(pPager->jfd); } } @@ -64638,15 +62671,13 @@ SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){ */ static int pagerExclusiveLock(Pager *pPager){ int rc; /* Return code */ - u8 eOrigLock; /* Original lock */ - assert( pPager->eLock>=SHARED_LOCK ); - eOrigLock = pPager->eLock; + assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK ); rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); if( rc!=SQLITE_OK ){ /* If the attempt to grab the exclusive lock failed, release the ** pending lock that may have been obtained instead. */ - pagerUnlockDb(pPager, eOrigLock); + pagerUnlockDb(pPager, SHARED_LOCK); } return rc; @@ -64899,12 +62930,6 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){ } #endif -#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL) -SQLITE_PRIVATE int sqlite3PagerWalSystemErrno(Pager *pPager){ - return sqlite3WalSystemErrno(pPager->pWal); -} -#endif - #endif /* SQLITE_OMIT_DISKIO */ /************** End of pager.c ***********************************************/ @@ -65195,7 +63220,7 @@ SQLITE_PRIVATE int 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 implementation used on both unix and windows +** interoperate. The standard implemention 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 @@ -65271,7 +63296,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[] indexes by one. Readers holding +** to avoid having to offset aReadMark[] indexs by one. Readers holding ** WAL_READ_LOCK(0) always ignore the entire WAL and read all content ** directly from the database. ** @@ -65439,15 +63464,7 @@ 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 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 @@ -65529,113 +63546,6 @@ struct WalIterator { sizeof(ht_slot)*HASHTABLE_NSLOT + HASHTABLE_NPAGE*sizeof(u32) \ ) -/* -** 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 - -/* 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 = 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 @@ -65708,7 +63618,6 @@ 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); } @@ -65720,7 +63629,6 @@ 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]); } @@ -65729,7 +63637,6 @@ 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]; } @@ -65775,40 +63682,19 @@ 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( aDatalockError = (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)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){ @@ -66009,20 +63889,12 @@ 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<exclusiveMode ) return; (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n, SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE); -#ifdef SQLITE_USE_SEH - pWal->lockMask &= ~(((1<apWiData[0][WALINDEX_HDR_SIZE/sizeof(u32) + iFrame - 1]; } @@ -66374,7 +64245,6 @@ static int walIndexRecover(Wal *pWal){ /* Malloc a buffer to read frames into. */ szFrame = szPage + WAL_FRAME_HDRSIZE; aFrame = (u8 *)sqlite3_malloc64(szFrame + WALINDEX_PGSZ); - SEH_FREE_ON_ERROR(0, aFrame); if( !aFrame ){ rc = SQLITE_NOMEM_BKPT; goto recovery_error; @@ -66393,7 +64263,6 @@ 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++){ @@ -66421,7 +64290,6 @@ 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 @@ -66452,11 +64320,9 @@ static int walIndexRecover(Wal *pWal){ } } #endif - SEH_INJECT_FAULT; if( iFrame<=iLast ) break; } - SEH_FREE_ON_ERROR(aFrame, 0); sqlite3_free(aFrame); } @@ -66484,7 +64350,6 @@ 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; @@ -66642,7 +64507,7 @@ SQLITE_PRIVATE int sqlite3WalOpen( } /* -** Change the size to which the WAL file is truncated on each reset. +** Change the size to which the WAL file is trucated on each reset. */ SQLITE_PRIVATE void sqlite3WalLimit(Wal *pWal, i64 iLimit){ if( pWal ) pWal->mxWalSize = iLimit; @@ -66868,16 +64733,23 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){ nByte = sizeof(WalIterator) + (nSegment-1)*sizeof(struct WalSegment) + iLast*sizeof(ht_slot); - p = (WalIterator *)sqlite3_malloc64(nByte - + sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast) - ); + p = (WalIterator *)sqlite3_malloc64(nByte); if( !p ){ return SQLITE_NOMEM_BKPT; } memset(p, 0, nByte); p->nSegment = nSegment; - aTmp = (ht_slot*)&(((u8*)p)[nByte]); - SEH_FREE_ON_ERROR(0, p); + + /* Allocate temporary space used by the merge-sort routine. This block + ** of memory will be freed before this function returns. + */ + aTmp = (ht_slot *)sqlite3_malloc64( + sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast) + ); + if( !aTmp ){ + rc = SQLITE_NOMEM_BKPT; + } + for(i=walFramePage(nBackfill+1); rc==SQLITE_OK && iaSegment[i].aPgno = (u32 *)sLoc.aPgno; } } + sqlite3_free(aTmp); + if( rc!=SQLITE_OK ){ - SEH_FREE_ON_ERROR(p, 0); walIteratorFree(p); p = 0; } @@ -66915,19 +64788,6 @@ 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 = 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 @@ -66939,7 +64799,11 @@ static int walEnableBlocking(Wal *pWal){ if( pWal->db ){ int tmout = pWal->db->busyTimeout; if( tmout ){ - res = walEnableBlockingMs(pWal, tmout); + int rc; + rc = sqlite3OsFileControl( + pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout + ); + res = (rc==SQLITE_OK); } } return res; @@ -66988,10 +64852,20 @@ SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, 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 walEnableBlockingMs(pWal, ms) 0 +# define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1) # define sqlite3WalDb(pWal, db) #endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */ @@ -67131,13 +65005,13 @@ static int walCheckpoint( mxSafeFrame = pWal->hdr.mxFrame; mxPage = pWal->hdr.nPage; for(i=1; iaReadMark+i); SEH_INJECT_FAULT; + u32 y = AtomicLoad(pInfo->aReadMark+i); if( mxSafeFrame>y ){ assert( y<=pWal->hdr.mxFrame ); rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1); if( rc==SQLITE_OK ){ u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED); - AtomicStore(pInfo->aReadMark+i, iMark); SEH_INJECT_FAULT; + AtomicStore(pInfo->aReadMark+i, iMark); walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); }else if( rc==SQLITE_BUSY ){ mxSafeFrame = y; @@ -67158,7 +65032,8 @@ static int walCheckpoint( && (rc = walBusyLock(pWal,xBusy,pBusyArg,WAL_READ_LOCK(0),1))==SQLITE_OK ){ u32 nBackfill = pInfo->nBackfill; - pInfo->nBackfillAttempted = mxSafeFrame; SEH_INJECT_FAULT; + + pInfo->nBackfillAttempted = mxSafeFrame; /* Sync the WAL to disk */ rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags)); @@ -67189,7 +65064,6 @@ 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; @@ -67219,7 +65093,7 @@ static int walCheckpoint( } } if( rc==SQLITE_OK ){ - AtomicStore(&pInfo->nBackfill, mxSafeFrame); SEH_INJECT_FAULT; + AtomicStore(&pInfo->nBackfill, mxSafeFrame); } } @@ -67241,7 +65115,6 @@ static int walCheckpoint( */ if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){ assert( pWal->writeLock ); - SEH_INJECT_FAULT; if( pInfo->nBackfillhdr.mxFrame ){ rc = SQLITE_BUSY; }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){ @@ -67273,7 +65146,6 @@ static int walCheckpoint( } walcheckpoint_out: - SEH_FREE_ON_ERROR(pIter, 0); walIteratorFree(pIter); return rc; } @@ -67296,93 +65168,6 @@ 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 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<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; iipFree); - 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<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 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. */ @@ -67397,8 +65182,6 @@ SQLITE_PRIVATE int 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 @@ -67423,7 +65206,7 @@ SQLITE_PRIVATE int sqlite3WalClose( ); if( bPersist!=1 ){ /* Try to delete the WAL file if the checkpoint completed and - ** fsynced (rc==SQLITE_OK) and if we are not in persistent-wal + ** fsyned (rc==SQLITE_OK) and if we are not in persistent-wal ** mode (!bPersist) */ isDelete = 1; }else if( pWal->mxWalSize>=0 ){ @@ -67490,7 +65273,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 implementations work + ** shared among multiple processes and not all mutex implementions work ** reliably in that environment. */ aHdr = walIndexHdr(pWal); @@ -67592,9 +65375,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ } }else{ int bWriteLock = pWal->writeLock; - if( bWriteLock - || SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) - ){ + if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){ pWal->writeLock = 1; if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){ badHdr = walIndexTryHdr(pWal, pChanged); @@ -67602,8 +65383,7 @@ 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; } @@ -67813,37 +65593,6 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){ return rc; } -/* -** 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 -** 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 @@ -67894,16 +65643,13 @@ 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 *pCnt){ +static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */ u32 mxReadMark; /* Largest aReadMark[] value */ int mxI; /* Index of largest aReadMark[] value */ int i; /* Loop counter */ int rc = SQLITE_OK; /* Return code */ u32 mxFrame; /* Wal frame to lock to */ -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT - int nBlockTmout = 0; -#endif assert( pWal->readLock<0 ); /* Not currently locked */ @@ -67927,34 +65673,14 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ ** 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. */ - (*pCnt)++; - if( *pCnt>5 ){ + if( cnt>5 ){ int nDelay = 1; /* Pause time in microseconds */ - int cnt = (*pCnt & ~WAL_RETRY_BLOCKED_MASK); - if( cnt>WAL_RETRY_PROTOCOL_LIMIT ){ + if( cnt>100 ){ VVA_ONLY( pWal->lockError = 1; ) return SQLITE_PROTOCOL; } - 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 + if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39; sqlite3OsSleep(pWal->pVfs, nDelay); - *pCnt &= ~WAL_RETRY_BLOCKED_MASK; } if( !useWal ){ @@ -67962,13 +65688,6 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ 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 @@ -68005,7 +65724,6 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ 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) @@ -68055,7 +65773,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ } #endif for(i=1; iaReadMark+i); SEH_INJECT_FAULT; + u32 thisMark = AtomicLoad(pInfo->aReadMark+i); if( mxReadMark<=thisMark && thisMark<=mxFrame ){ assert( thisMark!=READMARK_NOT_USED ); mxReadMark = thisMark; @@ -68083,19 +65801,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT; } - (void)walEnableBlockingMs(pWal, nBlockTmout); rc = walLockShared(pWal, WAL_READ_LOCK(mxI)); - walDisableBlocking(pWal); if( 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; + return rc==SQLITE_BUSY ? WAL_RETRY : rc; } /* Now that the read-lock has been obtained, check that neither the ** value in the aReadMark[] array or the contents of the wal-index @@ -68131,7 +65839,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ ** 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; SEH_INJECT_FAULT; + pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1; walShmBarrier(pWal); if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) @@ -68146,54 +65854,6 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ } #ifdef SQLITE_ENABLE_SNAPSHOT -/* -** This function does the work of 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 = 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 = sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff); - - if( rc==SQLITE_OK ){ - rc = 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 @@ -68219,21 +65879,50 @@ SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){ assert( pWal->readLock>=0 ); rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); if( rc==SQLITE_OK ){ - void *pBuf1 = sqlite3_malloc(pWal->szPage); - void *pBuf2 = sqlite3_malloc(pWal->szPage); - if( pBuf1==0 || pBuf2==0 ){ - rc = SQLITE_NOMEM; - }else{ - pWal->ckptLock = 1; - SEH_TRY { - rc = walSnapshotRecover(pWal, pBuf1, pBuf2); + volatile WalCkptInfo *pInfo = walCkptInfo(pWal); + int szPage = (int)pWal->szPage; + i64 szDb; /* Size of db file in bytes */ + + rc = sqlite3OsFileSize(pWal->pDbFd, &szDb); + if( rc==SQLITE_OK ){ + void *pBuf1 = sqlite3_malloc(szPage); + void *pBuf2 = 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 = sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff); + + if( rc==SQLITE_OK ){ + rc = sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff); + } + + if( rc!=SQLITE_OK || 0==memcmp(pBuf1, pBuf2, szPage) ){ + break; + } + } + + pInfo->nBackfillAttempted = i-1; + } } - SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; ) - pWal->ckptLock = 0; - } - sqlite3_free(pBuf1); - sqlite3_free(pBuf2); + sqlite3_free(pBuf1); + sqlite3_free(pBuf2); + } walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1); } @@ -68242,20 +65931,28 @@ SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){ #endif /* SQLITE_ENABLE_SNAPSHOT */ /* -** This function does the work of sqlite3WalBeginReadTransaction() (see -** below). That function simply calls this one inside an SEH_TRY{...} block. +** Begin a read transaction on the database. +** +** This routine used to be called sqlite3OpenSnapshot() and with good reason: +** it takes a snapshot of the state of the WAL and wal-index for the current +** instant in time. The current thread will continue to use this snapshot. +** Other threads might append new content to the WAL and wal-index but +** that extra content is ignored by the current thread. +** +** If the database contents have changes since the previous read +** transaction, then *pChanged is set to 1 before returning. The +** Pager layer will use this to know that its cache is stale and +** needs to be flushed. */ -static int walBeginReadTransaction(Wal *pWal, int *pChanged){ +SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(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 ){ @@ -68278,12 +65975,12 @@ static int walBeginReadTransaction(Wal *pWal, int *pChanged){ if( rc!=SQLITE_OK ){ return rc; } - ckptLock = 1; + pWal->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 ); @@ -68342,37 +66039,15 @@ static int walBeginReadTransaction(Wal *pWal, int *pChanged){ } /* Release the shared CKPT lock obtained above. */ - if( ckptLock ){ + if( pWal->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 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 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. @@ -68393,7 +66068,7 @@ SQLITE_PRIVATE void 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. */ -static int walFindFrame( +SQLITE_PRIVATE int sqlite3WalFindFrame( Wal *pWal, /* WAL handle */ Pgno pgno, /* Database page number to read data for */ u32 *piRead /* OUT: Frame number (or zero) */ @@ -68456,7 +66131,6 @@ static int walFindFrame( } 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 ){ @@ -68464,7 +66138,6 @@ static int walFindFrame( iRead = iFrame; } if( (nCollide--)==0 ){ - *piRead = 0; return SQLITE_CORRUPT_BKPT; } iKey = walNextHash(iKey); @@ -68494,30 +66167,6 @@ static int walFindFrame( return SQLITE_OK; } -/* -** 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 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 @@ -68599,17 +66248,12 @@ SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){ ** time the read transaction on this connection was started, then ** the write is disallowed. */ - 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 ){ + if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); pWal->writeLock = 0; + rc = SQLITE_BUSY_SNAPSHOT; } + return rc; } @@ -68645,33 +66289,30 @@ SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *p Pgno iMax = pWal->hdr.mxFrame; Pgno iFrame; - 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. - */ - memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr)); + /* Restore the clients cache of the wal-index header to the state it + ** was in before the client began writing to the database. + */ + memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr)); - for(iFrame=pWal->hdr.mxFrame+1; - ALWAYS(rc==SQLITE_OK) && iFrame<=iMax; - iFrame++ - ){ - /* This call cannot fail. Unless the page for which the page number - ** is passed as the second argument is (a) in the cache and - ** (b) has an outstanding reference, then xUndo is either a no-op - ** (if (a) is false) or simply expels the page from the cache (if (b) - ** is false). - ** - ** If the upper layer is doing a rollback, it is guaranteed that there - ** are no outstanding references to any page other than page 1. And - ** page 1 is never written to the log until the transaction is - ** committed. As a result, the call to xUndo may not fail. - */ - assert( walFramePgno(pWal, iFrame)!=1 ); - rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame)); - } - if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal); + 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)); } - SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; ) + if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal); } return rc; } @@ -68715,10 +66356,7 @@ SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){ pWal->hdr.mxFrame = aWalData[0]; pWal->hdr.aFrameCksum[0] = aWalData[1]; pWal->hdr.aFrameCksum[1] = aWalData[2]; - SEH_TRY { - walCleanupHash(pWal); - } - SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; ) + walCleanupHash(pWal); } return rc; @@ -68768,7 +66406,7 @@ static int walRestartLog(Wal *pWal){ cnt = 0; do{ int notUsed; - rc = walTryBeginRead(pWal, ¬Used, 1, &cnt); + rc = walTryBeginRead(pWal, ¬Used, 1, ++cnt); }while( rc==WAL_RETRY ); assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */ testcase( (rc&0xff)==SQLITE_IOERR ); @@ -68899,7 +66537,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 sqlite3WalBeginWriteTransaction()). */ -static int walFrames( +SQLITE_PRIVATE int sqlite3WalFrames( Wal *pWal, /* Wal handle to write to */ int szPage, /* Database page-size in bytes */ PgHdr *pList, /* List of dirty pages to write */ @@ -68987,9 +66625,7 @@ static int walFrames( if( rc ) return rc; } } - if( (int)pWal->szPage!=szPage ){ - return SQLITE_CORRUPT_BKPT; /* TH3 test case: cov1/corrupt155.test */ - } + assert( (int)pWal->szPage==szPage ); /* Setup information needed to write frames into the WAL */ w.pWal = pWal; @@ -69010,7 +66646,7 @@ static int walFrames( ** checksums must be recomputed when the transaction is committed. */ if( iFirst && (p->pDirty || isCommit==0) ){ u32 iWrite = 0; - VVA_ONLY(rc =) walFindFrame(pWal, p->pgno, &iWrite); + VVA_ONLY(rc =) sqlite3WalFindFrame(pWal, p->pgno, &iWrite); assert( rc==SQLITE_OK || iWrite==0 ); if( iWrite>=iFirst ){ i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE; @@ -69129,29 +66765,6 @@ static int walFrames( return rc; } -/* -** Write a set of frames to the log. The caller must hold the write-lock -** on the log file (obtained using sqlite3WalBeginWriteTransaction()). -** -** The difference between this function and walFrames() is that this -** function wraps walFrames() in an SEH_TRY{...} block. -*/ -SQLITE_PRIVATE int sqlite3WalFrames( - Wal *pWal, /* Wal handle to write to */ - int szPage, /* Database page-size in bytes */ - PgHdr *pList, /* List of dirty pages to write */ - Pgno nTruncate, /* Database size after this commit */ - int isCommit, /* True if this is a commit */ - int sync_flags /* Flags to pass to OsSync() (or 0) */ -){ - int rc; - SEH_TRY { - rc = walFrames(pWal, szPage, pList, nTruncate, isCommit, sync_flags); - } - SEH_EXCEPT( rc = walHandleException(pWal); ) - return rc; -} - /* ** This routine is called to implement sqlite3_wal_checkpoint() and ** related interfaces. @@ -69189,9 +66802,10 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( if( pWal->readOnly ) return SQLITE_READONLY; WALTRACE(("WAL%p: checkpoint begins\n", pWal)); - /* Enable blocking locks, if possible. */ + /* Enable blocking locks, if possible. If blocking locks are successfully + ** enabled, set xBusy2=0 so that the busy-handler is never invoked. */ sqlite3WalDb(pWal, db); - if( xBusy2 ) (void)walEnableBlocking(pWal); + (void)walEnableBlocking(pWal); /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive ** "checkpoint" lock on the database file. @@ -69230,38 +66844,30 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( /* Read the wal-index header. */ - 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 ){ - sqlite3OsUnfetch(pWal->pDbFd, 0, 0); - } + if( rc==SQLITE_OK ){ + walDisableBlocking(pWal); + rc = walIndexReadHdr(pWal, &isChanged); + (void)walEnableBlocking(pWal); + if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){ + 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 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); - } + 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); } } - SEH_EXCEPT( rc = walHandleException(pWal); ) if( isChanged ){ /* If a new wal-index header was loaded before the checkpoint was @@ -69338,9 +66944,7 @@ SQLITE_PRIVATE int 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 ){ @@ -69441,19 +67045,16 @@ SQLITE_API int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){ */ SQLITE_PRIVATE int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot){ int rc; - 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->mxFramenBackfillAttempted - ){ - rc = SQLITE_ERROR_SNAPSHOT; - walUnlockShared(pWal, WAL_CKPT_LOCK); - } + 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->mxFramenBackfillAttempted + ){ + rc = SQLITE_ERROR_SNAPSHOT; + walUnlockShared(pWal, WAL_CKPT_LOCK); } } - SEH_EXCEPT( rc = walHandleException(pWal); ) return rc; } @@ -69576,7 +67177,7 @@ SQLITE_PRIVATE sqlite3_file *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 The size of the database in pages +** 28 4 Reserved for future use ** 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 @@ -69684,7 +67285,7 @@ SQLITE_PRIVATE sqlite3_file *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 bits of the 9th byte are used as data. This +** As a special case, all 8 bytes of the 9th byte are used as data. This ** allows a 64-bit integer to be encoded in 9 bytes. ** ** 0x00 becomes 0x00000000 @@ -69692,7 +67293,7 @@ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){ ** 0x81 0x00 becomes 0x00000080 ** 0x82 0x00 becomes 0x00000100 ** 0x80 0x7f becomes 0x0000007f -** 0x81 0x91 0xd1 0xac 0x78 becomes 0x12345678 +** 0x8a 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 @@ -69775,7 +67376,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 allocates an +** As each database page is loaded into memory, the pager allocats an ** instance of this object and zeros the first 8 bytes. (This is the ** "extra" information associated with each page of the pager.) ** @@ -70068,7 +67669,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 to the last entry */ +#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */ #define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */ #define BTCF_Multiple 0x20 /* Maybe another cursor on the same btree */ #define BTCF_Pinned 0x40 /* Cursor is busy and cannot be moved */ @@ -70186,15 +67787,15 @@ struct BtCursor { ** So, this macro is defined instead. */ #ifndef SQLITE_OMIT_AUTOVACUUM -#define ISAUTOVACUUM(pBt) (pBt->autoVacuum) +#define ISAUTOVACUUM (pBt->autoVacuum) #else -#define ISAUTOVACUUM(pBt) 0 +#define ISAUTOVACUUM 0 #endif /* -** This structure is passed around through all the PRAGMA integrity_check -** checking routines in order to keep track of some global state information. +** This structure is passed around through all the sanity checking routines +** in order to keep track of some global state information. ** ** The aRef[] array is allocated so that there is 1 bit for each page in ** the database. As the integrity-check proceeds, for each page used in @@ -70207,19 +67808,16 @@ 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 nCkPage; /* Pages in the database. 0 for partial check */ + Pgno nPage; /* Number of pages in the database */ 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 */ + int bOomFault; /* A memory allocation error has occurred */ const char *zPfx; /* Error message prefix */ - 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 */ + Pgno v1; /* Value for first %u substitution in zPfx */ + int v2; /* Value for second %d substitution in zPfx */ StrAccum errMsg; /* Accumulate the error message text here */ u32 *heap; /* Min-heap used for analyzing cell coverage */ sqlite3 *db; /* Database connection running the check */ - i64 nRow; /* Number of rows visited in current tree */ }; /* @@ -70232,7 +67830,7 @@ struct IntegrityCk { /* ** get2byteAligned(), unlike get2byte(), requires that its argument point to a -** two-byte aligned address. get2byteAligned() is only used for accessing the +** two-byte aligned address. get2bytea() is only used for accessing the ** cell addresses in a btree header. */ #if SQLITE_BYTEORDER==4321 @@ -70409,7 +68007,7 @@ SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree *p){ ** ** There is a corresponding leave-all procedures. ** -** Enter the mutexes in ascending order by BtShared pointer address +** Enter the mutexes in accending 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. @@ -70679,8 +68277,8 @@ SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){ int corruptPageError(int lineno, MemPage *p){ char *zMsg; sqlite3BeginBenignMalloc(); - zMsg = sqlite3_mprintf("database corruption page %u of %s", - p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0) + zMsg = sqlite3_mprintf("database corruption page %d of %s", + (int)p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0) ); sqlite3EndBenignMalloc(); if( zMsg ){ @@ -70694,47 +68292,8 @@ 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. *** @@ -70811,8 +68370,6 @@ 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. */ @@ -70946,8 +68503,6 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){ BtLock *pLock = 0; BtLock *pIter; - SHARED_LOCK_TRACE(pBt,"setLock", iTable, eLock); - assert( sqlite3BtreeHoldsMutex(p) ); assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); assert( p->db!=0 ); @@ -71015,8 +68570,6 @@ 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 ); @@ -71055,9 +68608,6 @@ 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; @@ -71537,25 +69087,8 @@ SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow) */ SQLITE_PRIVATE void 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 = 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 ); - sqlite3WalkExpr(&w, pExpr); - } -#endif /* SQLITE_DEBUG */ } -#endif /* SQLITE_ENABLE_CURSOR_HINTS */ - +#endif /* ** Provide flag hints to the cursor. @@ -71640,7 +69173,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){ - TRACE(("PTRMAP_UPDATE: %u->(%u,%u)\n", key, eType, parent)); + TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent)); *pRC= rc = sqlite3PagerWrite(pDbPage); if( rc==SQLITE_OK ){ pPtrmap[offset] = eType; @@ -71839,31 +69372,27 @@ static void btreeParseCellPtr( iKey = *pIter; if( iKey>=0x80 ){ u8 x; - iKey = (iKey<<7) ^ (x = *++pIter); + iKey = ((iKey&0x7f)<<7) | ((x = *++pIter) & 0x7f); if( x>=0x80 ){ - iKey = (iKey<<7) ^ (x = *++pIter); + iKey = (iKey<<7) | ((x =*++pIter) & 0x7f); if( x>=0x80 ){ - iKey = (iKey<<7) ^ 0x10204000 ^ (x = *++pIter); + iKey = (iKey<<7) | ((x = *++pIter) & 0x7f); if( x>=0x80 ){ - iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter); + iKey = (iKey<<7) | ((x = *++pIter) & 0x7f); if( x>=0x80 ){ - iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter); + iKey = (iKey<<7) | ((x = *++pIter) & 0x7f); if( x>=0x80 ){ - iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter); + iKey = (iKey<<7) | ((x = *++pIter) & 0x7f); if( x>=0x80 ){ - iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter); + iKey = (iKey<<7) | ((x = *++pIter) & 0x7f); if( x>=0x80 ){ - iKey = (iKey<<8) ^ 0x8000 ^ (*++pIter); + iKey = (iKey<<8) | (*++pIter); } } } } } - }else{ - iKey ^= 0x204000; } - }else{ - iKey ^= 0x4000; } } pIter++; @@ -71940,53 +69469,10 @@ static void btreeParseCell( ** ** cellSizePtrNoPayload() => table internal nodes ** cellSizePtrTableLeaf() => table leaf nodes -** cellSizePtr() => index internal nodes -** cellSizeIdxLeaf() => index leaf nodes +** cellSizePtr() => all index nodes & table leaf nodes */ static u16 cellSizePtr(MemPage *pPage, u8 *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 && pItermaxLocal ); - 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 *pIter = pCell + pPage->childPtrSize; /* For looping over bytes of pCell */ u8 *pEnd; /* End mark for a varint */ u32 nSize; /* Size value to return */ @@ -71999,7 +69485,6 @@ static u16 cellSizePtrIdxLeaf(MemPage *pPage, u8 *pCell){ pPage->xParseCell(pPage, pCell, &debuginfo); #endif - assert( pPage->childPtrSize==0 ); nSize = *pIter; if( nSize>=0x80 ){ pEnd = &pIter[8]; @@ -72124,7 +69609,7 @@ static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){ pPage->xParseCell(pPage, pCell, &info); if( info.nLocalaDataEnd, pCell, pCell+info.nLocal) ){ + if( SQLITE_WITHIN(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){ testcase( pSrc!=pPage ); *pRC = SQLITE_CORRUPT_BKPT; return; @@ -72225,7 +69710,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ iCellStart = get2byte(&data[hdr+5]); if( nCell>0 ){ temp = sqlite3PagerTempSpace(pPage->pBt->pPager); - memcpy(temp, data, usableSize); + memcpy(&temp[iCellStart], &data[iCellStart], usableSize - iCellStart); src = temp; for(i=0; iiCellLast ){ + if( pciCellLast ){ return SQLITE_CORRUPT_PAGE(pPage); } - assert( pc>=0 && pc<=iCellLast ); + assert( pc>=iCellStart && pc<=iCellLast ); size = pPage->xCellSize(pPage, &src[pc]); cbrk -= size; if( cbrkusableSize ){ @@ -72354,7 +69839,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 SQLITE_INLINE int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ +static 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 */ @@ -72380,14 +69865,13 @@ static SQLITE_INLINE 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, @@ -72449,7 +69933,7 @@ static SQLITE_INLINE 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 encroach into the reserved bytes +** does it detect cells or freeblocks that encrouch 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. */ @@ -72470,7 +69954,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( iSize>=4 ); /* Minimum cell size is 4 */ - assert( CORRUPT_DB || iStart<=pPage->pBt->usableSize-4 ); + assert( 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. @@ -72527,11 +70011,6 @@ 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 @@ -72543,9 +70022,14 @@ 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; } @@ -72557,67 +70041,62 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ ** Only the following combinations are supported. Anything different ** indicates a corrupt database files: ** -** PTF_ZERODATA (0x02, 2) -** PTF_LEAFDATA | PTF_INTKEY (0x05, 5) -** PTF_ZERODATA | PTF_LEAF (0x0a, 10) -** PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF (0x0d, 13) +** PTF_ZERODATA +** PTF_ZERODATA | PTF_LEAF +** PTF_LEAFDATA | PTF_INTKEY +** PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF */ static int decodeFlags(MemPage *pPage, int flagByte){ BtShared *pBt; /* A copy of pPage->pBt */ assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) ); assert( 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; - pPage->max1bytePayload = pBt->max1bytePayload; - if( flagByte>=(PTF_ZERODATA | PTF_LEAF) ){ - pPage->childPtrSize = 0; - pPage->leaf = 1; - if( flagByte==(PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF) ){ + 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->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; } @@ -72908,41 +70387,68 @@ SQLITE_PRIVATE Pgno 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( 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) ){ - *ppPage = 0; - return SQLITE_CORRUPT_BKPT; + rc = SQLITE_CORRUPT_BKPT; + goto getAndInitPage_error1; } rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly); if( rc ){ - *ppPage = 0; - return rc; + goto getAndInitPage_error1; } - pPage = (MemPage*)sqlite3PagerGetExtra(pDbPage); - if( pPage->isInit==0 ){ + *ppPage = (MemPage*)sqlite3PagerGetExtra(pDbPage); + if( (*ppPage)->isInit==0 ){ btreePageFromDbPage(pDbPage, pgno, pBt); - rc = btreeInitPage(pPage); + rc = btreeInitPage(*ppPage); if( rc!=SQLITE_OK ){ - releasePage(pPage); - *ppPage = 0; - return rc; + goto getAndInitPage_error2; } } - assert( pPage->pgno==pgno || CORRUPT_DB ); - assert( pPage->aData==sqlite3PagerGetData(pDbPage) ); - *ppPage = pPage; + assert( (*ppPage)->pgno==pgno || CORRUPT_DB ); + assert( (*ppPage)->aData==sqlite3PagerGetData(pDbPage) ); + + /* If obtaining a child page for a cursor, we must verify that the page is + ** compatible with the root page. */ + if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){ + rc = SQLITE_CORRUPT_PGNO(pgno); + goto getAndInitPage_error2; + } 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; } /* @@ -73025,7 +70531,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-initializing. */ + ** the call for every page that comes in for re-initing. */ btreeInitPage(pPage); } } @@ -73204,9 +70710,6 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( assert( sizeof(u16)==2 ); assert( sizeof(Pgno)==4 ); - /* Suppress false-positive compiler warning from PVS-Studio */ - memset(&zDbHeader[16], 0, 8); - pBt = sqlite3MallocZero( sizeof(*pBt) ); if( pBt==0 ){ rc = SQLITE_NOMEM_BKPT; @@ -73423,7 +70926,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 uninitialized + ** does cause a valgrind error when the 1 or 2 bytes of unitialized ** data is passed to system call write(). So to avoid this error, ** zero the first 4 bytes of temp space here. ** @@ -73658,7 +71161,7 @@ SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p){ /* ** Return the number of bytes of space at the end of every page that -** are intentionally left unused. This is the "reserved" space that is +** are intentually 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 @@ -73905,6 +71408,7 @@ 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 @@ -73924,7 +71428,6 @@ static int lockBtree(BtShared *pBt){ releasePageOne(pPage1); pBt->usableSize = usableSize; pBt->pageSize = pageSize; - pBt->btsFlags |= BTS_PAGESIZE_FIXED; freeTempSpace(pBt); rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, pageSize-usableSize); @@ -73944,7 +71447,6 @@ 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 @@ -74123,11 +71625,7 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){ ** when A already has a read lock, we encourage A to give up and let B ** proceed. */ -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 */ -){ +SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){ BtShared *pBt = p->pBt; Pager *pPager = pBt->pPager; int rc = SQLITE_OK; @@ -74299,28 +71797,6 @@ trans_begun: sqlite3BtreeLeave(p); return rc; } -SQLITE_PRIVATE int 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 sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint); - }else{ - return SQLITE_OK; - } -} #ifndef SQLITE_OMIT_AUTOVACUUM @@ -74458,7 +71934,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 %u to free page %u (ptr page %u type %u)\n", + TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n", iDbPage, iFreePage, iPtrPage, eType)); rc = sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage, isCommit); if( rc!=SQLITE_OK ){ @@ -75416,6 +72892,7 @@ SQLITE_PRIVATE void 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. @@ -75427,6 +72904,7 @@ SQLITE_PRIVATE i64 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 @@ -75452,7 +72930,7 @@ SQLITE_PRIVATE u32 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 database. +** corrupt datrabase. ** ** The current implementation merely returns the size of the underlying ** database file. @@ -75671,12 +73149,9 @@ static int accessPayload( if( pCur->aOverflow==0 || nOvfl*(int)sizeof(Pgno) > sqlite3MallocSize(pCur->aOverflow) ){ - Pgno *aNew; - if( sqlite3FaultSim(413) ){ - aNew = 0; - }else{ - aNew = (Pgno*)sqlite3Realloc(pCur->aOverflow, nOvfl*2*sizeof(Pgno)); - } + Pgno *aNew = (Pgno*)sqlite3Realloc( + pCur->aOverflow, nOvfl*2*sizeof(Pgno) + ); if( aNew==0 ){ return SQLITE_NOMEM_BKPT; }else{ @@ -75686,12 +73161,6 @@ 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. @@ -75761,6 +73230,7 @@ static int accessPayload( assert( aWrite>=pBufStart ); /* due to (6) */ memcpy(aSave, aWrite, 4); rc = 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 @@ -75922,7 +73392,6 @@ SQLITE_PRIVATE const void *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->iPageapPage[pCur->iPage] = pCur->pPage; pCur->ix = 0; pCur->iPage++; - 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; + return getAndInitPage(pCur->pBt, newPgno, &pCur->pPage, pCur, + pCur->curPagerFlags); } #ifdef SQLITE_DEBUG @@ -76054,7 +73513,7 @@ static int moveToRoot(BtCursor *pCur){ sqlite3BtreeClearCursor(pCur); } rc = getAndInitPage(pCur->pBt, pCur->pgnoRoot, &pCur->pPage, - pCur->curPagerFlags); + 0, pCur->curPagerFlags); if( rc!=SQLITE_OK ){ pCur->eState = CURSOR_INVALID; return rc; @@ -76166,36 +73625,42 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ *pRes = 0; rc = moveToLeftmost(pCur); }else if( rc==SQLITE_EMPTY ){ - assert( pCur->pgnoRoot==0 || (pCur->pPage!=0 && pCur->pPage->nCell==0) ); + assert( pCur->pgnoRoot==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; iiiPage; 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. */ -static SQLITE_NOINLINE int btreeLast(BtCursor *pCur, int *pRes){ - int rc = moveToRoot(pCur); +SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ + int rc; + + assert( cursorOwnsBtShared(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); + + /* If the cursor already points to the last entry, this is a no-op. */ + if( CURSOR_VALID==pCur->eState && (pCur->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; iiiPage; 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); if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_VALID ); *pRes = 0; @@ -76212,18 +73677,6 @@ static SQLITE_NOINLINE int btreeLast(BtCursor *pCur, int *pRes){ } return rc; } -SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ - assert( cursorOwnsBtShared(pCur) ); - assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); - - /* If the cursor already points to the last entry, this is a no-op. */ - if( CURSOR_VALID==pCur->eState && (pCur->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. @@ -76271,14 +73724,13 @@ SQLITE_PRIVATE int sqlite3BtreeTableMoveto( } if( pCur->info.nKeycurFlags & 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 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 slowly. */ + ** is still obtained without this case, only a little more slowely */ if( pCur->info.nKey+1==intKey ){ *pRes = 0; rc = sqlite3BtreeNext(pCur, 0); @@ -76674,36 +74126,10 @@ bypass_moveto_root: }else{ chldPg = get4byte(findCell(pPage, lwr)); } - - /* 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 */ - } + pCur->ix = (u16)lwr; + rc = moveToChild(pCur, chldPg); + if( rc ) break; + } moveto_index_finish: pCur->info.nSize = 0; assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); @@ -76738,10 +74164,10 @@ SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor *pCur){ assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); - /* 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; + /* 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; if( NEVER(pCur->pPage->leaf==0) ) return -1; n = pCur->pPage->nCell; @@ -76794,8 +74220,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){ pPage = pCur->pPage; idx = ++pCur->ix; - if( sqlite3FaultSim(412) ) pPage->isInit = 0; - if( !pPage->isInit ){ + if( NEVER(!pPage->isInit) || sqlite3FaultSim(412) ){ return SQLITE_CORRUPT_BKPT; } @@ -76887,10 +74312,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){ } pPage = pCur->pPage; - if( sqlite3FaultSim(412) ) pPage->isInit = 0; - if( !pPage->isInit ){ - return SQLITE_CORRUPT_BKPT; - } + assert( pPage->isInit ); if( !pPage->leaf ){ int idx = pCur->ix; rc = moveToChild(pCur, get4byte(findCell(pPage, idx))); @@ -77061,7 +74483,7 @@ static int allocateBtreePage( memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4); *ppPage = pTrunk; pTrunk = 0; - TRACE(("ALLOCATE: %u trunk - %u free pages left\n", *pPgno, n-1)); + TRACE(("ALLOCATE: %d trunk - %d 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); @@ -77127,7 +74549,7 @@ static int allocateBtreePage( } } pTrunk = 0; - TRACE(("ALLOCATE: %u trunk - %u free pages left\n", *pPgno, n-1)); + TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1)); #endif }else if( k>0 ){ /* Extract a leaf from the trunk */ @@ -77172,8 +74594,8 @@ static int allocateBtreePage( ){ int noContent; *pPgno = iPage; - TRACE(("ALLOCATE: %u was leaf %u of %u on trunk %u" - ": %u more free pages\n", + TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d" + ": %d more free pages\n", *pPgno, closest+1, k, pTrunk->pgno, n-1)); rc = sqlite3PagerWrite(pTrunk->pDbPage); if( rc ) goto end_allocate_page; @@ -77229,7 +74651,7 @@ static int allocateBtreePage( ** becomes a new pointer-map page, the second is used by the caller. */ MemPage *pPg = 0; - TRACE(("ALLOCATE: %u from end of file (pointer-map page)\n", pBt->nPage)); + TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage)); assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) ); rc = btreeGetUnusedPage(pBt, pBt->nPage, &pPg, bNoContent); if( rc==SQLITE_OK ){ @@ -77252,7 +74674,7 @@ static int allocateBtreePage( releasePage(*ppPage); *ppPage = 0; } - TRACE(("ALLOCATE: %u from end of file\n", *pPgno)); + TRACE(("ALLOCATE: %d from end of file\n", *pPgno)); } assert( CORRUPT_DB || *pPgno!=PENDING_BYTE_PAGE(pBt) ); @@ -77320,7 +74742,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(pBt) ){ + if( ISAUTOVACUUM ){ ptrmapPut(pBt, iPage, PTRMAP_FREEPAGE, 0, &rc); if( rc ) goto freepage_out; } @@ -77380,7 +74802,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ } rc = btreeSetHasContent(pBt, iPage); } - TRACE(("FREE-PAGE: %u leaf on trunk page %u\n",pPage->pgno,pTrunk->pgno)); + TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno)); goto freepage_out; } } @@ -77401,7 +74823,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: %u new trunk page replacing %u\n", pPage->pgno, iTrunk)); + TRACE(("FREE-PAGE: %d new trunk page replacing %d\n", pPage->pgno, iTrunk)); freepage_out: if( pPage ){ @@ -77490,7 +74912,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. */ @@ -77563,10 +74985,7 @@ static int fillInCell( n = nHeader + nPayload; testcase( n==3 ); testcase( n==4 ); - if( n<4 ){ - n = 4; - pPayload[nPayload] = 0; - } + if( n<4 ) n = 4; *pnSize = n; assert( nSrc<=nPayload ); testcase( nSrcaCell[] 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()! +** *pRC must be SQLITE_OK when this routine is called. */ -static int insertCell( +static void 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 */ + Pgno iChild, /* If non-zero, replace first 4 bytes with this value */ + int *pRC /* Read and write return code from here */ ){ 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 ); @@ -77793,103 +75208,14 @@ static int insertCell( assert( 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; } - 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 = sqlite3PagerWrite(pPage->pDbPage); - if( NEVER(rc!=SQLITE_OK) ){ - return rc; - } - assert( 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; + if( iChild ){ + put4byte(pCell, iChild); } -#endif - } - return SQLITE_OK; -} - -/* -** This variant of insertCell() assumes that the pTemp and iChild -** parameters are both zero. Use this variant in 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( 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 @@ -77908,20 +75234,31 @@ static int insertCellFast( }else{ int rc = sqlite3PagerWrite(pPage->pDbPage); if( rc!=SQLITE_OK ){ - return rc; + *pRC = rc; + return; } assert( sqlite3PagerIswriteable(pPage->pDbPage) ); data = pPage->aData; assert( &data[pPage->cellOffset]==pPage->aCellIdx ); rc = allocateSpace(pPage, sz, &idx); - if( rc ){ return rc; } + if( rc ){ *pRC = rc; return; } /* The allocateSpace() routine guarantees the following properties ** if it returns successfully */ assert( idx >= 0 ); assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB ); assert( idx+sz <= (int)pPage->pBt->usableSize ); pPage->nFree -= (u16)(2 + sz); - memcpy(&data[idx], pCell, 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); + } pIns = pPage->aCellIdx + i*2; memmove(pIns+2, pIns, 2*(pPage->nCell - i)); put2byte(pIns, idx); @@ -77931,16 +75268,13 @@ static int insertCellFast( 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; + ptrmapPutOvflPtr(pPage, pPage, pCell, pRC); } #endif } - return SQLITE_OK; } /* @@ -78041,16 +75375,14 @@ 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( szCell[idx]==0 ){ - szCell[idx] = pRef->xCellSize(pRef, p->apCell[idx]); + if( p->szCell[idx]==0 ){ + p->szCell[idx] = p->pRef->xCellSize(p->pRef, p->apCell[idx]); }else{ assert( CORRUPT_DB || - szCell[idx]==pRef->xCellSize(pRef, p->apCell[idx]) ); + p->szCell[idx]==p->pRef->xCellSize(p->pRef, p->apCell[idx]) ); } idx++; N--; @@ -78104,13 +75436,12 @@ static int rebuildPage( int k; /* Current slot in pCArray->apEnd[] */ u8 *pSrcEnd; /* Current pCArray->apEnd[k] value */ - assert( nCell>0 ); assert( i(u32)usableSize ){ j = 0; } memcpy(&pTmp[j], &aData[j], usableSize - j); - for(k=0; ALWAYS(kixNx[k]<=i; k++){} + for(k=0; pCArray->ixNx[k]<=i && ALWAYS(kapEnd[k]; pData = pEnd; @@ -78173,7 +75504,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 accommodate all +** area must be extended to before this point in order to accomodate all ** cells in apCell[], then the cells do not fit and non-zero is returned. */ static int pageInsertArray( @@ -78193,7 +75524,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; ALWAYS(kixNx[k]<=i ; k++){} + for(k=0; pCArray->ixNx[k]<=i && ALWAYS(kapEnd[k]; while( 1 /*Exit by break*/ ){ int sz, rc; @@ -78251,50 +75582,39 @@ static int pageFreeArray( u8 * const pEnd = &aData[pPg->pBt->usableSize]; u8 * const pStart = &aData[pPg->hdrOffset + 8 + pPg->childPtrSize]; int nRet = 0; - int i, j; + int i; int iEnd = iFirst + nCell; - int nFree = 0; - int aOfst[10]; - int aAfter[10]; + u8 *pFree = 0; + int szFree = 0; for(i=iFirst; iapCell[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 ); - iOfst = (u16)(pCell - aData); - iAfter = iOfst+sz; - for(j=0; j=nFree ){ - if( nFree>=(int)(sizeof(aOfst)/sizeof(aOfst[0])) ){ - for(j=0; jaData && (pFree - aData)<65536 ); + freeSpace(pPg, (u16)(pFree - aData), szFree); + } + pFree = pCell; + szFree = sz; + if( pFree+sz>pEnd ){ + return 0; } - aOfst[nFree] = iOfst; - aAfter[nFree] = iAfter; - if( &aData[iAfter]>pEnd ) return 0; - nFree++; + }else{ + pFree = pCell; + szFree += sz; } nRet++; } } - for(j=0; jaData && (pFree - aData)<65536 ); + freeSpace(pPg, (u16)(pFree - aData), szFree); } return nRet; } @@ -78347,9 +75667,9 @@ static int editPage( nCell -= nTail; } - pData = &aData[get2byte(&aData[hdr+5])]; + pData = &aData[get2byteNotZero(&aData[hdr+5])]; if( pDatapPg->aDataEnd) ) goto editpage_fail; + if( pData>pPg->aDataEnd ) goto editpage_fail; /* Add cells to the start of the page */ if( iNewpgno, &rc); if( szCell>pNew->minLocal ){ ptrmapPutOvflPtr(pNew, pNew, pCell, &rc); @@ -78522,8 +75841,8 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ /* Insert the new divider cell into pParent. */ if( rc==SQLITE_OK ){ - rc = insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace), - 0, pPage->pgno); + insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace), + 0, pPage->pgno, &rc); } /* Set the right-child pointer of pParent to point to the new page. */ @@ -78632,7 +75951,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(pBt) ){ + if( ISAUTOVACUUM ){ *pRC = setChildPtrmaps(pTo); } } @@ -78765,7 +76084,7 @@ static int balance_nonroot( pgno = get4byte(pRight); while( 1 ){ if( rc==SQLITE_OK ){ - rc = getAndInitPage(pBt, pgno, &apOld[i], 0); + rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0); } if( rc ){ memset(apOld, 0, (i+1)*sizeof(MemPage*)); @@ -78872,7 +76191,7 @@ static int balance_nonroot( ** table-interior, index-leaf, or index-interior). */ if( pOld->aData[0]!=apOld[0]->aData[0] ){ - rc = SQLITE_CORRUPT_PAGE(pOld); + rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; } @@ -78896,7 +76215,7 @@ static int balance_nonroot( memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow)); if( pOld->nOverflow>0 ){ if( NEVER(limitaiOvfl[0]) ){ - rc = SQLITE_CORRUPT_PAGE(pOld); + rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; } limit = pOld->aiOvfl[0]; @@ -79056,17 +76375,15 @@ static int balance_nonroot( d = r + 1 - leafData; (void)cachedCellSize(&b, d); do{ - int szR, szD; assert( d szLeft-(szR+(i==k-1?0:2)))){ + && (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+(i==k-1?0:2)))){ break; } - szRight += szD + 2; - szLeft -= szR + 2; + szRight += b.szCell[d] + 2; + szLeft -= b.szCell[r] + 2; cntNew[i-1] = r; r--; d--; @@ -79079,7 +76396,7 @@ static int balance_nonroot( } } - /* Sanity check: For a non-corrupt database file one of the following + /* Sanity check: For a non-corrupt database file one of the follwing ** 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 @@ -79087,7 +76404,7 @@ static int balance_nonroot( ** that page. */ assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) || CORRUPT_DB); - TRACE(("BALANCE: old: %u(nc=%u) %u(nc=%u) %u(nc=%u)\n", + TRACE(("BALANCE: old: %d(nc=%d) %d(nc=%d) %d(nc=%d)\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 @@ -79120,7 +76437,7 @@ static int balance_nonroot( cntOld[i] = b.nCell; /* Set the pointer-map entry for the new sibling page. */ - if( ISAUTOVACUUM(pBt) ){ + if( ISAUTOVACUUM ){ ptrmapPut(pBt, pNew->pgno, PTRMAP_BTREE, pParent->pgno, &rc); if( rc!=SQLITE_OK ){ goto balance_cleanup; @@ -79171,8 +76488,8 @@ static int balance_nonroot( } } - TRACE(("BALANCE: new: %u(%u nc=%u) %u(%u nc=%u) %u(%u nc=%u) " - "%u(%u nc=%u) %u(%u nc=%u)\n", + TRACE(("BALANCE: new: %d(%d nc=%d) %d(%d nc=%d) %d(%d nc=%d) " + "%d(%d nc=%d) %d(%d nc=%d)\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, @@ -79213,7 +76530,7 @@ static int balance_nonroot( ** updated. This happens below, after the sibling pages have been ** populated, not here. */ - if( ISAUTOVACUUM(pBt) ){ + if( ISAUTOVACUUM ){ MemPage *pOld; MemPage *pNew = pOld = apNew[0]; int cntOldNext = pNew->nCell + pNew->nOverflow; @@ -79304,13 +76621,13 @@ static int balance_nonroot( iOvflSpace += sz; assert( sz<=pBt->maxLocal+23 ); assert( iOvflSpace <= (int)pBt->pageSize ); - for(k=0; ALWAYS(kpgno); + insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno, &rc); if( rc!=SQLITE_OK ) goto balance_cleanup; assert( sqlite3PagerIswriteable(pParent->pDbPage) ); } @@ -79340,8 +76657,6 @@ static int balance_nonroot( for(i=1-nNew; i=0 && iPg=1 || i>=0 ); - assert( iPg=0 /* On the upwards pass, or... */ || cntOld[iPg-1]>=cntNew[iPg-1] /* Condition (1) is true */ @@ -79408,7 +76723,7 @@ static int balance_nonroot( ); copyNodeContent(apNew[0], pParent, &rc); freePage(apNew[0], &rc); - }else if( ISAUTOVACUUM(pBt) && !leafCorrection ){ + }else if( ISAUTOVACUUM && !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. */ @@ -79419,7 +76734,7 @@ static int balance_nonroot( } assert( pParent->isInit ); - TRACE(("BALANCE: finished: old=%u new=%u cells=%u\n", + TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n", nOld, nNew, b.nCell)); /* Free any old pages that were not reused as new pages. @@ -79429,7 +76744,7 @@ static int balance_nonroot( } #if 0 - if( ISAUTOVACUUM(pBt) && rc==SQLITE_OK && apNew[0]->isInit ){ + if( ISAUTOVACUUM && 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 @@ -79491,7 +76806,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(pBt) ){ + if( ISAUTOVACUUM ){ ptrmapPut(pBt, pgnoChild, PTRMAP_BTREE, pRoot->pgno, &rc); } } @@ -79504,7 +76819,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){ assert( sqlite3PagerIswriteable(pRoot->pDbPage) ); assert( pChild->nCell==pRoot->nCell || CORRUPT_DB ); - TRACE(("BALANCE: copy root %u into %u\n", pRoot->pgno, pChild->pgno)); + TRACE(("BALANCE: copy root %d into %d\n", pRoot->pgno, pChild->pgno)); /* Copy the overflow cells from pRoot to pChild */ memcpy(pChild->aiOvfl, pRoot->aiOvfl, @@ -79539,7 +76854,7 @@ static int anotherValidCursor(BtCursor *pCur){ && pOther->eState==CURSOR_VALID && pOther->pPage==pCur->pPage ){ - return SQLITE_CORRUPT_PAGE(pCur->pPage); + return SQLITE_CORRUPT_BKPT; } } return SQLITE_OK; @@ -79599,7 +76914,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_PAGE(pPage); + rc = SQLITE_CORRUPT_BKPT; }else{ MemPage * const pParent = pCur->apPage[iPage-1]; int const iIdx = pCur->aiIdx[iPage-1]; @@ -79698,7 +77013,7 @@ static int btreeOverwriteContent( ){ int nData = pX->nData - iOffset; if( nData<=0 ){ - /* Overwriting with zeros */ + /* Overwritting with zeros */ int i; for(i=0; ipData to write */ int nTotal = pX->nData + pX->nZero; /* Total bytes of to write */ int rc; /* Return code */ @@ -79745,12 +77056,16 @@ static SQLITE_NOINLINE int btreeOverwriteOverflowCell( Pgno ovflPgno; /* Next overflow page to write */ u32 ovflPageSize; /* Size to write on overflow page */ - assert( pCur->info.nLocalinfo.pPayload + pCur->info.nLocal > pPage->aDataEnd + || pCur->info.pPayload < pPage->aData + pPage->cellOffset + ){ + return SQLITE_CORRUPT_BKPT; + } /* 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; @@ -79763,7 +77078,7 @@ static SQLITE_NOINLINE int btreeOverwriteOverflowCell( rc = btreeGetPage(pBt, ovflPgno, &pPage, 0); if( rc ) return rc; if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 || pPage->isInit ){ - rc = SQLITE_CORRUPT_PAGE(pPage); + rc = SQLITE_CORRUPT_BKPT; }else{ if( iOffset+ovflPageSize<(u32)nTotal ){ ovflPgno = get4byte(pPage->aData); @@ -79780,29 +77095,6 @@ static SQLITE_NOINLINE int btreeOverwriteOverflowCell( 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 @@ -79846,6 +77138,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( int idx; MemPage *pPage; Btree *p = pCur->pBtree; + BtShared *pBt = p->pBt; unsigned char *oldCell; unsigned char *newCell = 0; @@ -79864,7 +77157,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( ** not to clear the cursor here. */ if( pCur->curFlags & BTCF_Multiple ){ - rc = saveAllCursors(p->pBt, pCur->pgnoRoot, pCur); + rc = saveAllCursors(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 @@ -79872,7 +77165,7 @@ SQLITE_PRIVATE int 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_PGNO(pCur->pgnoRoot); + return SQLITE_CORRUPT_BKPT; } } @@ -79888,8 +77181,8 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( assert( cursorOwnsBtShared(pCur) ); assert( (pCur->curFlags & BTCF_WriteFlag)!=0 - && p->pBt->inTransaction==TRANS_WRITE - && (p->pBt->btsFlags & BTS_READ_ONLY)==0 ); + && pBt->inTransaction==TRANS_WRITE + && (pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); /* Assert that the caller has been consistent. If this cursor was opened @@ -79987,7 +77280,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( } } assert( pCur->eState==CURSOR_VALID - || (pCur->eState==CURSOR_INVALID && loc) || CORRUPT_DB ); + || (pCur->eState==CURSOR_INVALID && loc) ); pPage = pCur->pPage; assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) ); @@ -79995,49 +77288,43 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( if( pPage->nFree<0 ){ if( NEVER(pCur->eState>CURSOR_INVALID) ){ /* ^^^^^--- due to the moveToRoot() call above */ - rc = SQLITE_CORRUPT_PAGE(pPage); + rc = SQLITE_CORRUPT_BKPT; }else{ rc = btreeComputeFreeSpace(pPage); } if( rc ) return rc; } - TRACE(("INSERT: table=%u nkey=%lld ndata=%u page=%u %s\n", + TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno, loc==0 ? "overwrite" : "new entry")); assert( pPage->isInit || CORRUPT_DB ); - newCell = p->pBt->pTmpSpace; + newCell = pBt->pTmpSpace; assert( newCell!=0 ); - assert( BTREE_PREFORMAT==OPFLAG_PREFORMAT ); if( flags & BTREE_PREFORMAT ){ rc = SQLITE_OK; - szNew = p->pBt->nPreformatSize; - if( szNew<4 ){ - szNew = 4; - newCell[3] = 0; - } - if( ISAUTOVACUUM(p->pBt) && szNew>pPage->maxLocal ){ + szNew = pBt->nPreformatSize; + if( szNew<4 ) szNew = 4; + if( ISAUTOVACUUM && szNew>pPage->maxLocal ){ CellInfo info; pPage->xParseCell(pPage, newCell, &info); if( info.nPayload!=info.nLocal ){ Pgno ovfl = get4byte(&newCell[szNew-4]); - ptrmapPut(p->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc); - if( NEVER(rc) ) goto end_insert; + ptrmapPut(pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc); } } }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(p->pBt) ); + assert( szNew <= MX_CELL_SIZE(pBt) ); idx = pCur->ix; - pCur->info.nSize = 0; if( loc==0 ){ CellInfo info; assert( idx>=0 ); if( idx>=pPage->nCell ){ - return SQLITE_CORRUPT_PAGE(pPage); + return SQLITE_CORRUPT_BKPT; } rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ){ @@ -80051,7 +77338,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( testcase( pCur->curFlags & BTCF_ValidOvfl ); invalidateOverflowCache(pCur); if( info.nSize==szNew && info.nLocal==info.nPayload - && (!ISAUTOVACUUM(p->pBt) || szNewminLocal) + && (!ISAUTOVACUUM || szNewminLocal) ){ /* 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 @@ -80064,10 +77351,10 @@ SQLITE_PRIVATE int 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_PAGE(pPage); + return SQLITE_CORRUPT_BKPT; } if( oldCell+szNew > pPage->aDataEnd ){ - return SQLITE_CORRUPT_PAGE(pPage); + return SQLITE_CORRUPT_BKPT; } memcpy(oldCell, newCell, szNew); return SQLITE_OK; @@ -80077,11 +77364,11 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( }else if( loc<0 && pPage->nCell>0 ){ assert( pPage->leaf ); idx = ++pCur->ix; - pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); + pCur->curFlags &= ~BTCF_ValidNKey; }else{ assert( pPage->leaf ); } - rc = insertCellFast(pPage, idx, newCell, szNew); + insertCell(pPage, idx, newCell, szNew, 0, 0, &rc); assert( pPage->nOverflow==0 || rc==SQLITE_OK ); assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 ); @@ -80105,9 +77392,10 @@ SQLITE_PRIVATE int 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|BTCF_ValidOvfl); + pCur->curFlags &= ~(BTCF_ValidNKey); rc = balance(pCur); /* Must make sure nOverflow is reset to zero even if the balance() @@ -80153,6 +77441,7 @@ end_insert: ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ SQLITE_PRIVATE int 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 */ @@ -80169,15 +77458,13 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 nIn = pSrc->info.nLocal; aIn = pSrc->info.pPayload; if( aIn+nIn>pSrc->pPage->aDataEnd ){ - return SQLITE_CORRUPT_PAGE(pSrc->pPage); + return SQLITE_CORRUPT_BKPT; } nRem = pSrc->info.nPayload; if( nIn==nRem && nInpPage->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; @@ -80194,7 +77481,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 if( nRem>nIn ){ if( aIn+nIn+4>pSrc->pPage->aDataEnd ){ - return SQLITE_CORRUPT_PAGE(pSrc->pPage); + return SQLITE_CORRUPT_BKPT; } ovflIn = get4byte(&pSrc->info.pPayload[nIn]); } @@ -80229,7 +77516,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 MemPage *pNew = 0; rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0); put4byte(pPgnoOut, pgnoNew); - if( ISAUTOVACUUM(pBt) && pPageOut ){ + if( ISAUTOVACUUM && pPageOut ){ ptrmapPut(pBt, pgnoNew, PTRMAP_OVERFLOW2, pPageOut->pgno, &rc); } releasePage(pPageOut); @@ -80245,8 +77532,9 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 releasePage(pPageOut); sqlite3PagerUnref(pPageIn); - return rc; } + + return rc; } /* @@ -80290,7 +77578,7 @@ SQLITE_PRIVATE int 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_PGNO(pCur->pgnoRoot); + return SQLITE_CORRUPT_BKPT; } } assert( pCur->eState==CURSOR_VALID ); @@ -80299,14 +77587,11 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ iCellIdx = pCur->ix; pPage = pCur->pPage; if( pPage->nCell<=iCellIdx ){ - return SQLITE_CORRUPT_PAGE(pPage); + return SQLITE_CORRUPT_BKPT; } pCell = findCell(pPage, iCellIdx); if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ){ - return SQLITE_CORRUPT_PAGE(pPage); - } - if( pCell<&pPage->aCellIdx[pPage->nCell] ){ - return SQLITE_CORRUPT_PAGE(pPage); + return SQLITE_CORRUPT_BKPT; } /* If the BTREE_SAVEPOSITION bit is on, then the cursor position must @@ -80397,14 +77682,14 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ n = pCur->pPage->pgno; } pCell = findCell(pLeaf, pLeaf->nCell-1); - if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_PAGE(pLeaf); + if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT; nCell = pLeaf->xCellSize(pLeaf, pCell); assert( MX_CELL_SIZE(pBt) >= nCell ); pTmp = pBt->pTmpSpace; assert( pTmp!=0 ); rc = sqlite3PagerWrite(pLeaf->pDbPage); if( rc==SQLITE_OK ){ - rc = insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n); + insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc); } dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc); if( rc ) return rc; @@ -80484,7 +77769,7 @@ static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){ MemPage *pRoot; Pgno pgnoRoot; int rc; - int ptfFlags; /* Page-type flags for the root page of new table */ + int ptfFlags; /* Page-type flage for the root page of new table */ assert( sqlite3BtreeHoldsMutex(p) ); assert( pBt->inTransaction==TRANS_WRITE ); @@ -80513,7 +77798,7 @@ static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){ */ sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot); if( pgnoRoot>btreePagecount(pBt) ){ - return SQLITE_CORRUPT_PGNO(pgnoRoot); + return SQLITE_CORRUPT_BKPT; } pgnoRoot++; @@ -80561,7 +77846,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_PGNO(pgnoRoot); + rc = SQLITE_CORRUPT_BKPT; } if( rc!=SQLITE_OK ){ releasePage(pRoot); @@ -80651,14 +77936,14 @@ static int clearDatabasePage( assert( sqlite3_mutex_held(pBt->mutex) ); if( pgno>btreePagecount(pBt) ){ - return SQLITE_CORRUPT_PGNO(pgno); + return SQLITE_CORRUPT_BKPT; } - rc = getAndInitPage(pBt, pgno, &pPage, 0); + rc = getAndInitPage(pBt, pgno, &pPage, 0, 0); if( rc ) return rc; if( (pBt->openFlags & BTREE_SINGLE)==0 && sqlite3PagerPageRefcount(pPage->pDbPage) != (1 + (pgno==1)) ){ - rc = SQLITE_CORRUPT_PAGE(pPage); + rc = SQLITE_CORRUPT_BKPT; goto cleardatabasepage_out; } hdr = pPage->hdrOffset; @@ -80762,7 +78047,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_PGNO(iTable); + return SQLITE_CORRUPT_BKPT; } rc = sqlite3BtreeClearTable(p, iTable, 0); @@ -81003,41 +78288,6 @@ SQLITE_PRIVATE Pager *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){ - 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. */ @@ -81047,7 +78297,6 @@ static void checkAppendMsg( ... ){ va_list ap; - checkProgress(pCheck); if( !pCheck->mxErr ) return; pCheck->mxErr--; pCheck->nErr++; @@ -81056,13 +78305,12 @@ static void checkAppendMsg( sqlite3_str_append(&pCheck->errMsg, "\n", 1); } if( pCheck->zPfx ){ - sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx, - pCheck->v0, pCheck->v1, pCheck->v2); + sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2); } sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap); va_end(ap); if( pCheck->errMsg.accError==SQLITE_NOMEM ){ - checkOom(pCheck); + pCheck->bOomFault = 1; } } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ @@ -81074,8 +78322,7 @@ static void checkAppendMsg( ** corresponds to page iPg is already set. */ static int getPageReferenced(IntegrityCk *pCheck, Pgno iPg){ - assert( pCheck->aPgRef!=0 ); - assert( iPg<=pCheck->nCkPage && sizeof(pCheck->aPgRef[0])==1 ); + assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 ); return (pCheck->aPgRef[iPg/8] & (1 << (iPg & 0x07))); } @@ -81083,8 +78330,7 @@ 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( pCheck->aPgRef!=0 ); - assert( iPg<=pCheck->nCkPage && sizeof(pCheck->aPgRef[0])==1 ); + assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 ); pCheck->aPgRef[iPg/8] |= (1 << (iPg & 0x07)); } @@ -81098,14 +78344,15 @@ 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->nCkPage || iPage==0 ){ - checkAppendMsg(pCheck, "invalid page number %u", iPage); + if( iPage>pCheck->nPage || iPage==0 ){ + checkAppendMsg(pCheck, "invalid page number %d", iPage); return 1; } if( getPageReferenced(pCheck, iPage) ){ - checkAppendMsg(pCheck, "2nd reference to page %u", iPage); + checkAppendMsg(pCheck, "2nd reference to page %d", iPage); return 1; } + if( AtomicLoad(&pCheck->db->u1.isInterrupted) ) return 1; setPageReferenced(pCheck, iPage); return 0; } @@ -81128,14 +78375,14 @@ 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=%u", iChild); + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->bOomFault = 1; + checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild); return; } if( ePtrmapType!=eType || iPtrmapParent!=iParent ){ checkAppendMsg(pCheck, - "Bad ptr map entry key=%u expected=(%u,%u) got=(%u,%u)", + "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)", iChild, eType, iParent, ePtrmapType, iPtrmapParent); } } @@ -81160,7 +78407,7 @@ static void checkList( if( checkRef(pCheck, iPage) ) break; N--; if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){ - checkAppendMsg(pCheck, "failed to get page %u", iPage); + checkAppendMsg(pCheck, "failed to get page %d", iPage); break; } pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage); @@ -81173,7 +78420,7 @@ static void checkList( #endif if( n>pCheck->pBt->usableSize/4-2 ){ checkAppendMsg(pCheck, - "freelist leaf count too big on page %u", iPage); + "freelist leaf count too big on page %d", iPage); N--; }else{ for(i=0; i<(int)n; i++){ @@ -81205,7 +78452,7 @@ static void checkList( } if( N && nErrAtStart==pCheck->nErr ){ checkAppendMsg(pCheck, - "%s is %u but should be %u", + "%s is %d but should be %d", isFreeList ? "size" : "overflow list length", expected-N, expected); } @@ -81235,9 +78482,7 @@ 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; - assert( aHeap!=0 ); - i = ++aHeap[0]; + u32 j, i = ++aHeap[0]; aHeap[i] = x; while( (j = i/2)>0 && aHeap[j]>aHeap[i] ){ x = aHeap[j]; @@ -81314,18 +78559,15 @@ 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 = "Tree %u page %u: "; + pCheck->zPfx = "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; } @@ -81348,7 +78590,7 @@ static int checkTreePage( hdr = pPage->hdrOffset; /* Set up for cell analysis */ - pCheck->zPfx = "Tree %u page %u cell %u: "; + pCheck->zPfx = "On tree page %u cell %d: "; contentOffset = get2byteNotZero(&data[hdr+5]); assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */ @@ -81356,9 +78598,6 @@ 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. */ @@ -81371,7 +78610,7 @@ static int checkTreePage( pgno = get4byte(&data[hdr+8]); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ - pCheck->zPfx = "Tree %u page %u right child: "; + pCheck->zPfx = "On page %u at right child: "; checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage); } #endif @@ -81395,7 +78634,7 @@ static int checkTreePage( pc = get2byteAligned(pCellIdx); pCellIdx -= 2; if( pcusableSize-4 ){ - checkAppendMsg(pCheck, "Offset %u out of range %u..%u", + checkAppendMsg(pCheck, "Offset %d out of range %d..%d", pc, contentOffset, usableSize-4); doCoverageCheck = 0; continue; @@ -81470,7 +78709,6 @@ 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 @@ -81528,7 +78766,7 @@ static int checkTreePage( */ if( heap[0]==0 && nFrag!=data[hdr+7] ){ checkAppendMsg(pCheck, - "Fragmentation of %u bytes reported as %u on page %u", + "Fragmentation of %d bytes reported as %d on page %u", nFrag, data[hdr+7], iPage); } } @@ -81566,15 +78804,13 @@ end_of_check: ** the unverified btrees. Except, if aRoot[1] is 1, then the freelist ** checks are still performed. */ -SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( +SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( 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 */ - char **pzOut /* OUT: Write the error message string here */ + int *pnErr /* Write number of errors seen to this variable */ ){ Pgno i; IntegrityCk sCheck; @@ -81584,9 +78820,7 @@ SQLITE_PRIVATE int 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 ){ @@ -81599,36 +78833,42 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE ); VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) ); assert( nRef>=0 ); - memset(&sCheck, 0, sizeof(sCheck)); sCheck.db = db; sCheck.pBt = pBt; sCheck.pPager = pBt->pPager; - sCheck.nCkPage = btreePagecount(sCheck.pBt); + sCheck.nPage = 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; sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH); sCheck.errMsg.printfFlags = SQLITE_PRINTF_INTERNAL; - if( sCheck.nCkPage==0 ){ + if( sCheck.nPage==0 ){ goto integrity_ck_cleanup; } - sCheck.aPgRef = sqlite3MallocZero((sCheck.nCkPage / 8)+ 1); + sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1); if( !sCheck.aPgRef ){ - checkOom(&sCheck); + sCheck.bOomFault = 1; goto integrity_ck_cleanup; } sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize ); if( sCheck.heap==0 ){ - checkOom(&sCheck); + sCheck.bOomFault = 1; goto integrity_ck_cleanup; } i = PENDING_BYTE_PAGE(pBt); - if( i<=sCheck.nCkPage ) setPageReferenced(&sCheck, i); + if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i); /* Check the integrity of the freelist */ if( bCkFreelist ){ - sCheck.zPfx = "Freelist: "; + sCheck.zPfx = "Main freelist: "; checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]), get4byte(&pBt->pPage1->aData[36])); sCheck.zPfx = 0; @@ -81645,7 +78885,7 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( mxInHdr = get4byte(&pBt->pPage1->aData[52]); if( mx!=mxInHdr ){ checkAppendMsg(&sCheck, - "max rootpage (%u) disagrees with header (%u)", + "max rootpage (%d) disagrees with header (%d)", mx, mxInHdr ); } @@ -81659,28 +78899,24 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( testcase( pBt->db->flags & SQLITE_CellSizeCk ); pBt->db->flags &= ~(u64)SQLITE_CellSizeCk; for(i=0; (int)iautoVacuum && aRoot[i]>1 && !bPartial ){ - checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0); - } -#endif - sCheck.v0 = aRoot[i]; - checkTreePage(&sCheck, aRoot[i], ¬Used, LARGEST_INT64); + if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){ + checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0); } - sqlite3MemSetArrayInt64(aCnt, i, sCheck.nRow); +#endif + checkTreePage(&sCheck, aRoot[i], ¬Used, LARGEST_INT64); } pBt->db->flags = savedDbFlags; /* Make sure every page in the file is referenced */ if( !bPartial ){ - for(i=1; i<=sCheck.nCkPage && sCheck.mxErr; i++){ + for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){ #ifdef SQLITE_OMIT_AUTOVACUUM if( getPageReferenced(&sCheck, i)==0 ){ - checkAppendMsg(&sCheck, "Page %u: never used", i); + checkAppendMsg(&sCheck, "Page %d is never used", i); } #else /* If the database supports auto-vacuum, make sure no tables contain @@ -81688,11 +78924,11 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( */ if( getPageReferenced(&sCheck, i)==0 && (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){ - checkAppendMsg(&sCheck, "Page %u: never used", i); + checkAppendMsg(&sCheck, "Page %d is never used", i); } if( getPageReferenced(&sCheck, i)!=0 && (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){ - checkAppendMsg(&sCheck, "Page %u: pointer map referenced", i); + checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i); } #endif } @@ -81703,17 +78939,16 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( integrity_ck_cleanup: sqlite3PageFree(sCheck.heap); sqlite3_free(sCheck.aPgRef); - *pnErr = sCheck.nErr; - if( sCheck.nErr==0 ){ + if( sCheck.bOomFault ){ sqlite3_str_reset(&sCheck.errMsg); - *pzOut = 0; - }else{ - *pzOut = sqlite3StrAccumFinish(&sCheck.errMsg); + sCheck.nErr++; } + *pnErr = sCheck.nErr; + if( sCheck.nErr==0 ) sqlite3_str_reset(&sCheck.errMsg); /* Make sure this analysis did not leave any unref() pages. */ assert( nRef==sqlite3PagerRefcount(pBt->pPager) ); sqlite3BtreeLeave(p); - return sCheck.rc; + return sqlite3StrAccumFinish(&sCheck.errMsg); } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ @@ -82254,7 +79489,13 @@ static int backupOnePage( assert( !isFatalError(p->rc) ); assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ); assert( zSrcData ); - assert( nSrcPgsz==nDestPgsz || sqlite3PagerIsMemdb(pDestPager)==0 ); + + /* Catch the case where the destination is an in-memory database and the + ** page sizes of the source and destination differ. + */ + if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){ + rc = SQLITE_READONLY; + } /* This loop runs once for each destination page spanned by the source ** page. For each iteration, variable iOff is set to the byte offset @@ -82387,10 +79628,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ pgszSrc = sqlite3BtreeGetPageSize(p->pSrc); pgszDest = sqlite3BtreeGetPageSize(p->pDest); destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest)); - if( SQLITE_OK==rc - && (destMode==PAGER_JOURNALMODE_WAL || sqlite3PagerIsMemdb(pDestPager)) - && pgszSrc!=pgszDest - ){ + if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){ rc = SQLITE_READONLY; } @@ -82896,9 +80134,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); - p->n = sqlite3Int64ToText(x, zBuf); + sqlite3Int64ToText(x, zBuf); #else - p->n = sqlite3Int64ToText(p->u.i, zBuf); + sqlite3Int64ToText(p->u.i, zBuf); #endif }else{ sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0); @@ -82906,7 +80144,6 @@ 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 sqlite3StrAccumFinish(&acc) */ - p->n = acc.nChar; } } @@ -82934,12 +80171,10 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ ** This routine is for use inside of assert() statements only. */ SQLITE_PRIVATE int 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 */ @@ -82952,8 +80187,7 @@ SQLITE_PRIVATE int 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; - memcpy(&tmp, p, sizeof(tmp)); - vdbeMemRenderNum(sizeof(zBuf), zBuf, &tmp); + vdbeMemRenderNum(sizeof(zBuf), zBuf, p); z = p->z; i = j = 0; incr = 1; @@ -83096,40 +80330,6 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ return SQLITE_OK; } -/* -** 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 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==sqlite3_free - && sqlite3_msize(pMem->z) >= (u64)(pMem->n+1) - ){ - pMem->z[pMem->n] = 0; - pMem->flags |= MEM_Term; - return; - } - if( pMem->xDel==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. @@ -83256,7 +80456,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ vdbeMemRenderNum(nByte, pMem->z, pMem); assert( pMem->z!=0 ); - assert( pMem->n==(int)sqlite3Strlen30NN(pMem->z) ); + pMem->n = sqlite3Strlen30NN(pMem->z); pMem->enc = SQLITE_UTF8; pMem->flags |= MEM_Str|MEM_Term; if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal); @@ -83391,6 +80591,36 @@ SQLITE_PRIVATE void sqlite3VdbeMemReleaseMalloc(Mem *p){ if( p->szMalloc ) vdbeMemClear(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. @@ -83417,7 +80647,7 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(const Mem *pMem){ testcase( flags & MEM_IntReal ); return pMem->u.i; }else if( flags & MEM_Real ){ - return sqlite3RealToI64(pMem->u.r); + return doubleToInt64(pMem->u.r); }else if( (flags & (MEM_Str|MEM_Blob))!=0 && pMem->z!=0 ){ return memIntValue(pMem); }else{ @@ -83466,35 +80696,32 @@ SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){ } /* -** The MEM structure is already a MEM_Real or MEM_IntReal. Try to -** make it a MEM_Int if we can. +** The MEM structure is already a MEM_Real. Try to also make it a +** MEM_Int if we can. */ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){ + i64 ix; assert( pMem!=0 ); - assert( pMem->flags & (MEM_Real|MEM_IntReal) ); + assert( pMem->flags & MEM_Real ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); - if( pMem->flags & MEM_IntReal ){ - MemSetTypeFlag(pMem, MEM_Int); - }else{ - i64 ix = sqlite3RealToI64(pMem->u.r); + 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 && ixu.i = ix; - MemSetTypeFlag(pMem, MEM_Int); - } + /* 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 && ixu.i = ix; + MemSetTypeFlag(pMem, MEM_Int); } } @@ -83547,8 +80774,8 @@ SQLITE_PRIVATE int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){ ** from UBSAN. */ SQLITE_PRIVATE i64 sqlite3RealToI64(double r){ - if( r<-9223372036854774784.0 ) return SMALLEST_INT64; - if( r>+9223372036854774784.0 ) return LARGEST_INT64; + if( r<=(double)SMALLEST_INT64 ) return SMALLEST_INT64; + if( r>=(double)LARGEST_INT64) return LARGEST_INT64; return (i64)r; } @@ -83619,7 +80846,6 @@ SQLITE_PRIVATE int 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; @@ -83627,9 +80853,7 @@ SQLITE_PRIVATE int 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; - rc = sqlite3VdbeChangeEncoding(pMem, encoding); - if( rc ) return rc; - sqlite3VdbeMemZeroTerminateIfAble(pMem); + return sqlite3VdbeChangeEncoding(pMem, encoding); } } return SQLITE_OK; @@ -83725,13 +80949,6 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ } } -/* -** Set the iIdx'th entry of array aMem[] to contain integer value val. -*/ -SQLITE_PRIVATE void sqlite3MemSetArrayInt64(sqlite3_value *aMem, int iIdx, i64 val){ - sqlite3VdbeMemSetInt64(&aMem[iIdx], val); -} - /* A no-op destructor */ SQLITE_PRIVATE void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); } @@ -84160,24 +81377,6 @@ SQLITE_PRIVATE const void *sqlite3ValueText(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 sqlite3ValueIsOfClass(const 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 sqlite3_value object. */ @@ -84245,7 +81444,6 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ } pRec->nField = p->iVal+1; - sqlite3VdbeMemSetNull(&pRec->aMem[p->iVal]); return &pRec->aMem[p->iVal]; } #else @@ -84299,12 +81497,9 @@ static int valueFromFunction( if( pList ) nVal = pList->nExpr; assert( !ExprHasProperty(p, EP_IntValue) ); pFunc = 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|SQLITE_FUNC_RUNONLY))!=0 + || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) ){ return SQLITE_OK; } @@ -84327,6 +81522,8 @@ 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; @@ -84339,16 +81536,16 @@ static int valueFromFunction( sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8); assert( rc==SQLITE_OK ); rc = sqlite3VdbeChangeEncoding(pVal, enc); - if( NEVER(rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal)) ){ + if( rc==SQLITE_OK && 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; ipLeft, 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 sqlite3VdbeMemCast(*ppVal, aff, enc); sqlite3ValueApplyAffinity(*ppVal, affinity, enc); } @@ -84420,20 +81610,14 @@ static int valueFromExpr( } /* Handle negative integers in a single step. This is needed in the - ** 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 = "-"; - } - } + ** case when the value is -9223372036854775808. + */ + if( op==TK_UMINUS + && (pExpr->pLeft->op==TK_INTEGER || pExpr->pLeft->op==TK_FLOAT) ){ + pExpr = pExpr->pLeft; + op = pExpr->op; + negInt = -1; + zNeg = "-"; } if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){ @@ -84442,26 +81626,12 @@ static int valueFromExpr( if( ExprHasProperty(pExpr, EP_IntValue) ){ sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue*negInt); }else{ - i64 iVal; - if( op==TK_INTEGER && 0==sqlite3DecOrHexToI64(pExpr->u.zToken, &iVal) ){ - sqlite3VdbeMemSetInt64(pVal, iVal*negInt); - }else{ - zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken); - if( zVal==0 ) goto no_mem; - sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC); - } + zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken); + if( zVal==0 ) goto no_mem; + sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC); } - if( affinity==SQLITE_AFF_BLOB ){ - if( op==TK_FLOAT ){ - assert( pVal && pVal->z && pVal->flags==(MEM_Str|MEM_Term) ); - 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 - ** sqlite3DecOrHexToI64() call above. */ - sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8); - } + if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_BLOB ){ + sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8); }else{ sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8); } @@ -84525,7 +81695,6 @@ static int valueFromExpr( if( pVal ){ pVal->flags = MEM_Int; pVal->u.i = pExpr->u.zToken[4]==0; - sqlite3ValueApplyAffinity(pVal, affinity, enc); } } @@ -84731,17 +81900,17 @@ SQLITE_PRIVATE int sqlite3Stat4Column( sqlite3_value **ppVal /* OUT: Extracted value */ ){ u32 t = 0; /* a column type code */ - 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 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 */ 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>(u32)nRec || iHdr>=nHdr ) return SQLITE_CORRUPT_BKPT; + if( nHdr>nRec || iHdr>=nHdr ) return SQLITE_CORRUPT_BKPT; iField = nHdr; for(i=0; i<=iCol; i++){ iHdr += getVarint32(&a[iHdr], t); @@ -85048,43 +82217,11 @@ static int growOpArray(Vdbe *v, int nOp){ ** sqlite3CantopenError(lineno) */ static void test_addop_breakpoint(int pc, Op *pOp){ - static u64 n = 0; - (void)pc; - (void)pOp; + static int n = 0; n++; - if( n==LARGEST_UINT64 ) abort(); /* so that n is used, preventing a warning */ } #endif -/* -** Slow paths for sqlite3VdbeAddOp3() and 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 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 = 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. @@ -85095,16 +82232,17 @@ static SQLITE_NOINLINE int addOp4IntSlow( ** ** op The opcode for this instruction ** -** p1, p2, p3, p4 Operands +** p1, p2, p3 Operands +** +** Use the sqlite3VdbeResolveLabel() function to fix an address and +** the sqlite3VdbeChangeP4() function to change the value of the P4 +** operand. */ -SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe *p, int op){ - return sqlite3VdbeAddOp3(p, op, 0, 0, 0); -} -SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe *p, int op, int p1){ - return sqlite3VdbeAddOp3(p, op, p1, 0, 0); -} -SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe *p, int op, int p1, int p2){ - return sqlite3VdbeAddOp3(p, op, p1, p2, 0); +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 sqlite3VdbeAddOp3(p, op, p1, p2, p3); } SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ int i; @@ -85127,79 +82265,33 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ pOp->p3 = p3; pOp->p4.p = 0; pOp->p4type = P4_NOTUSED; - - /* Replicate this logic in 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 ){ sqlite3VdbePrintOp(0, i, &p->aOp[i]); test_addop_breakpoint(i, &p->aOp[i]); } #endif -#ifdef SQLITE_VDBE_COVERAGE - pOp->iSrcLine = 0; -#endif - /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ** Replicate in sqlite3VdbeAddOp4Int() */ - - return i; -} -SQLITE_PRIVATE int 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 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 ){ - sqlite3VdbePrintOp(0, i, &p->aOp[i]); - test_addop_breakpoint(i, &p->aOp[i]); - } +#ifdef VDBE_PROFILE + pOp->cycles = 0; + pOp->cnt = 0; #endif #ifdef SQLITE_VDBE_COVERAGE pOp->iSrcLine = 0; #endif - /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ** Replicate in sqlite3VdbeAddOp3() */ - return i; } +SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe *p, int op){ + return sqlite3VdbeAddOp3(p, op, 0, 0, 0); +} +SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe *p, int op, int p1){ + return sqlite3VdbeAddOp3(p, op, p1, 0, 0); +} +SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe *p, int op, int p1, int p2){ + return sqlite3VdbeAddOp3(p, op, p1, p2, 0); +} /* Generate code for an unconditional jump to instruction iDest */ @@ -85353,12 +82445,11 @@ SQLITE_PRIVATE void sqlite3ExplainBreakpoint(const char *z1, const char *z2){ ** If the bPush flag is true, then make this opcode the parent for ** subsequent Explains until sqlite3VdbeExplainPop() is called. */ -SQLITE_PRIVATE int sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){ - int addr = 0; -#if !defined(SQLITE_DEBUG) +SQLITE_PRIVATE void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){ +#ifndef 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 || IS_STMT_SCANSTATUS(pParse->db) ) + if( pParse->explain==2 ) #endif { char *zMsg; @@ -85370,15 +82461,13 @@ SQLITE_PRIVATE int sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, va_end(ap); v = pParse->pVdbe; iThis = v->nOp; - addr = sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0, + sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0, zMsg, P4_DYNAMIC); sqlite3ExplainBreakpoint(bPush?"PUSH":"", sqlite3VdbeGetLastOp(v)->p4.z); if( bPush){ pParse->addrExplain = iThis; } - sqlite3VdbeScanStatus(v, iThis, -1, -1, 0, 0); } - return addr; } /* @@ -85406,6 +82495,26 @@ SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere, sqlite3MayAbort(p->pParse); } +/* +** Add an opcode that includes the p4 value as an integer. +*/ +SQLITE_PRIVATE int 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 = 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 sqlite3VdbeEndCoroutine(Vdbe *v, int regYield){ @@ -85466,9 +82575,6 @@ static SQLITE_NOINLINE void resizeResolveLabel(Parse *p, Vdbe *v, int j){ int i; for(i=p->nLabelAlloc; iaLabel[i] = -1; #endif - if( nNewSize>=100 && (nNewSize/100)>(p->nLabelAlloc/100) ){ - sqlite3ProgressCheck(p); - } p->nLabelAlloc = nNewSize; p->aLabel[j] = v->nOp; } @@ -85712,13 +82818,11 @@ 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 terminates when it reaches the OP_Init opcode */ ){ + while( 1 /* Loop termates 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 @@ -85773,18 +82877,8 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ ** have non-negative values for P2. */ assert( (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 - || (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP0)!=0 ); - - /* Jumps never go off the end of the bytecode array */ - assert( pOp->p2nOp - || (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)==0 ); break; } } @@ -85849,10 +82943,6 @@ SQLITE_PRIVATE void 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 ); @@ -86030,83 +83120,20 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus( LogEst nEst, /* Estimated number of output rows */ const char *zName /* Name of table or index being scanned */ ){ - if( IS_STMT_SCANSTATUS(p->db) ){ - sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus); - ScanStatus *aNew; - aNew = (ScanStatus*)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 = sqlite3DbStrDup(p->db, zName); - p->aScan = aNew; - } + sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus); + ScanStatus *aNew; + aNew = (ScanStatus*)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 = sqlite3DbStrDup(p->db, zName); + p->aScan = aNew; } } - -/* -** Add the range of instructions from addrStart to addrEnd (inclusive) to -** the set of those corresponding to the sqlite3_stmt_scanstatus() counters -** associated with the OP_Explain instruction at addrExplain. The -** sum of the sqlite3Hwtime() values for each of these instructions -** will be returned for SQLITE_SCANSTAT_NCYCLE requests. -*/ -SQLITE_PRIVATE void 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 = sqlite3VdbeCurrentAddr(p)-1; - for(ii=0; iiaAddrRange); 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 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) */ +#endif /* @@ -86185,7 +83212,7 @@ SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe *p, int addr){ /* ** If the input FuncDef structure is ephemeral, then free it. If -** the FuncDef is not ephemeral, then do nothing. +** the FuncDef is not ephermal, then do nothing. */ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){ assert( db!=0 ); @@ -86246,10 +83273,6 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){ if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4); break; } - case P4_TABLEREF: { - if( db->pnBytesFreed==0 ) sqlite3DeleteTable(db, (Table*)p4); - break; - } } } @@ -86353,6 +83376,7 @@ SQLITE_PRIVATE void 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 @@ -86377,7 +83401,7 @@ static void SQLITE_NOINLINE vdbeChangeP4Full( int n ){ if( pOp->p4type ){ - assert( pOp->p4type > P4_FREE_IF_LE ); + freeP4(p->db, pOp->p4type, pOp->p4.p); pOp->p4type = 0; pOp->p4.p = 0; } @@ -86533,7 +83557,7 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){ /* Return the most recently added opcode */ -SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetLastOp(Vdbe *p){ +VdbeOp * sqlite3VdbeGetLastOp(Vdbe *p){ return sqlite3VdbeGetOp(p, p->nOp - 1); } @@ -87238,6 +84262,7 @@ SQLITE_PRIVATE int sqlite3VdbeList( ** 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 sqlite3_column_text() or @@ -87273,7 +84298,7 @@ SQLITE_PRIVATE int sqlite3VdbeList( sqlite3VdbeMemSetInt64(pMem+1, pOp->p2); sqlite3VdbeMemSetInt64(pMem+2, pOp->p3); sqlite3VdbeMemSetStr(pMem+3, zP4, -1, SQLITE_UTF8, sqlite3_free); - assert( p->nResColumn==4 ); + p->nResColumn = 4; }else{ sqlite3VdbeMemSetInt64(pMem+0, i); sqlite3VdbeMemSetStr(pMem+1, (char*)sqlite3OpcodeName(pOp->opcode), @@ -87292,9 +84317,9 @@ SQLITE_PRIVATE int sqlite3VdbeList( sqlite3VdbeMemSetNull(pMem+7); #endif sqlite3VdbeMemSetStr(pMem+5, zP4, -1, SQLITE_UTF8, sqlite3_free); - assert( p->nResColumn==8 ); + p->nResColumn = 8; } - p->pResultRow = pMem; + p->pResultSet = pMem; if( db->mallocFailed ){ p->rc = SQLITE_NOMEM; rc = SQLITE_ERROR; @@ -87405,7 +84430,7 @@ static void *allocSpace( ** running it. */ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){ -#if defined(SQLITE_DEBUG) +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) int i; #endif assert( p!=0 ); @@ -87434,8 +84459,8 @@ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){ p->nFkConstraint = 0; #ifdef VDBE_PROFILE for(i=0; inOp; i++){ - p->aOp[i].nExec = 0; - p->aOp[i].nCycle = 0; + p->aOp[i].cnt = 0; + p->aOp[i].cycles = 0; } #endif } @@ -87506,9 +84531,26 @@ SQLITE_PRIVATE void 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; - p->nResColumn = 12 - 4*p->explain; + if( pParse->explain==2 ){ + sqlite3VdbeSetNumCols(p, 4); + iFirst = 8; + mx = 12; + }else{ + sqlite3VdbeSetNumCols(p, 8); + iFirst = 0; + mx = 8; + } + for(i=iFirst; iexpired = 0; @@ -87527,6 +84569,9 @@ SQLITE_PRIVATE void 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 = sqlite3DbMallocRawNN(db, x.nNeeded); x.nFree = x.nNeeded; @@ -87535,6 +84580,9 @@ SQLITE_PRIVATE void 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 } } @@ -87549,6 +84597,9 @@ SQLITE_PRIVATE void 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 } sqlite3VdbeRewind(p); } @@ -87560,23 +84611,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady( SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ if( pCx ) 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 ){ - sqlite3RCStrUnref(pCache->pCValue); - pCache->pCValue = 0; - } - sqlite3DbFree(p->db, pCache); - sqlite3VdbeFreeCursorNN(p, pCx); -} SQLITE_PRIVATE void sqlite3VdbeFreeCursorNN(Vdbe *p, VdbeCursor *pCx){ - if( pCx->colCache ){ - freeCursorWithCache(p, pCx); - return; - } switch( pCx->eCurType ){ case CURTYPE_SORTER: { sqlite3VdbeSorterClose(p->db, pCx); @@ -87622,6 +84657,9 @@ static void closeCursorsInFrame(Vdbe *p){ SQLITE_PRIVATE int 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; @@ -87677,12 +84715,12 @@ SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){ int n; sqlite3 *db = p->db; - if( p->nResAlloc ){ - releaseMemArray(p->aColName, p->nResAlloc*COLNAME_N); + if( p->nResColumn ){ + releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); sqlite3DbFree(db, p->aColName); } n = nResColumn*COLNAME_N; - p->nResColumn = p->nResAlloc = (u16)nResColumn; + p->nResColumn = (u16)nResColumn; p->aColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n ); if( p->aColName==0 ) return; initMemArray(p->aColName, n, db, MEM_Null); @@ -87707,14 +84745,14 @@ SQLITE_PRIVATE int sqlite3VdbeSetColName( ){ int rc; Mem *pColName; - assert( idxnResAlloc ); + assert( idxnResColumn ); assert( vardb->mallocFailed ){ assert( !zName || xDel!=SQLITE_DYNAMIC ); return SQLITE_NOMEM_BKPT; } assert( p->aColName!=0 ); - pColName = &(p->aColName[idx+var*p->nResAlloc]); + pColName = &(p->aColName[idx+var*p->nResColumn]); rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, xDel); assert( rc!=0 || !zName || (pColName->flags&MEM_Term)!=0 ); return rc; @@ -88192,7 +85230,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ /* Check for immediate foreign key violations. */ if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ - (void)sqlite3VdbeCheckFk(p, 0); + sqlite3VdbeCheckFk(p, 0); } /* If the auto-commit flag is set and this is the only active writer @@ -88227,7 +85265,6 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ sqlite3VdbeLeave(p); return SQLITE_BUSY; }else if( rc!=SQLITE_OK ){ - sqlite3SystemError(db, rc); p->rc = rc; sqlite3RollbackAll(db, SQLITE_OK); p->nChange = 0; @@ -88237,8 +85274,6 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ db->flags &= ~(u64)SQLITE_DeferFKs; sqlite3CommitInternalChanges(db); } - }else if( p->rc==SQLITE_SCHEMA && db->nVdbeActive>1 ){ - p->nChange = 0; }else{ sqlite3RollbackAll(db, SQLITE_OK); p->nChange = 0; @@ -88428,7 +85463,7 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; } - p->pResultRow = 0; + p->pResultSet = 0; #ifdef SQLITE_DEBUG p->nWrite = 0; #endif @@ -88456,12 +85491,10 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ } for(i=0; inOp; i++){ char zHdr[100]; - i64 cnt = p->aOp[i].nExec; - i64 cycles = p->aOp[i].nCycle; sqlite3_snprintf(sizeof(zHdr), zHdr, "%6u %12llu %8llu ", - cnt, - cycles, - cnt>0 ? cycles/cnt : 0 + p->aOp[i].cnt, + p->aOp[i].cycles, + p->aOp[i].cnt>0 ? p->aOp[i].cycles/p->aOp[i].cnt : 0 ); fprintf(out, "%s", zHdr); sqlite3VdbePrintOp(out, i, &p->aOp[i]); @@ -88539,7 +85572,7 @@ static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ assert( db!=0 ); assert( p->db==0 || p->db==db ); if( p->aColName ){ - releaseMemArray(p->aColName, p->nResAlloc*COLNAME_N); + releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); sqlite3DbNNFreeNN(db, p->aColName); } for(pSub=p->pProgram; pSub; pSub=pNext){ @@ -88557,9 +85590,9 @@ static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ #ifdef SQLITE_ENABLE_NORMALIZE sqlite3DbFree(db, p->zNormSql); { - DblquoteStr *pThis, *pNxt; - for(pThis=p->pDblStr; pThis; pThis=pNxt){ - pNxt = pThis->pNextStr; + DblquoteStr *pThis, *pNext; + for(pThis=p->pDblStr; pThis; pThis=pNext){ + pNext = pThis->pNextStr; sqlite3DbFree(db, pThis); } } @@ -88906,23 +85939,6 @@ 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 sqlite3VdbeSerialGet( const unsigned char *buf, /* Buffer to deserialize from */ u32 serial_type, /* Serial type to deserialize */ @@ -89156,15 +86172,6 @@ static int vdbeRecordCompareDebug( if( d1+(u64)serial_type1+2>(u64)nKey1 && d1+(u64)sqlite3VdbeSerialTypeLen(serial_type1)>(u64)nKey1 ){ - if( serial_type1>=1 - && serial_type1<=7 - && d1+(u64)sqlite3VdbeSerialTypeLen(serial_type1)<=(u64)nKey1+8 - && CORRUPT_DB - ){ - return 1; /* corrupt record not detected by - ** sqlite3VdbeRecordCompareWithSkip(). Return true - ** to avoid firing the assert() */ - } break; } @@ -89333,44 +86340,32 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem 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 a8 ){ LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i; testcase( xr ); testcase( x==r ); - return (xr); + if( xr ) return +1; /*NO_TEST*/ /* work around bugs in gcov */ + return 0; /*NO_TEST*/ /* work around bugs in gcov */ }else{ i64 y; + double s; if( r<-9223372036854775808.0 ) return +1; if( r>=9223372036854775808.0 ) return -1; y = (i64)r; if( iy ) return +1; - testcase( doubleLt(((double)i),r) ); - testcase( doubleLt(r,((double)i)) ); - testcase( doubleEq(r,((double)i)) ); - return (((double)i)r); + s = (double)i; + if( sr ) return +1; + return 0; } } @@ -89600,7 +86595,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( }else if( serial_type==0 ){ rc = -1; }else if( serial_type==7 ){ - serialGet7(&aKey1[d1], &mem1); + sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r); }else{ i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]); @@ -89620,23 +86615,19 @@ SQLITE_PRIVATE int 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 numeric values are. */ + ** them to numberic values are. */ rc = serial_type==10 ? -1 : +1; }else if( serial_type==0 ){ rc = -1; }else{ + sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); if( serial_type==7 ){ - if( serialGet7(&aKey1[d1], &mem1) ){ - rc = -1; /* mem1 is a NaN */ - }else if( mem1.u.ru.r ){ + if( mem1.u.ru.r ){ rc = -1; }else if( mem1.u.r>pRhs->u.r ){ rc = +1; - }else{ - assert( rc==0 ); } }else{ - sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r); } } @@ -89706,14 +86697,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( /* RHS is null */ else{ serial_type = aKey1[idx1]; - if( serial_type==0 - || serial_type==10 - || (serial_type==7 && serialGet7(&aKey1[d1], &mem1)!=0) - ){ - assert( rc==0 ); - }else{ - rc = 1; - } + rc = (serial_type!=0 && serial_type!=10); } if( rc!=0 ){ @@ -90173,8 +87157,7 @@ SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff assert( iVar>0 ); if( v ){ Mem *pMem = &v->aVar[iVar-1]; - assert( (v->db->flags & SQLITE_EnableQPSG)==0 - || (v->db->mDbFlags & DBFLAG_InternalFunc)!=0 ); + assert( (v->db->flags & SQLITE_EnableQPSG)==0 ); if( 0==(pMem->flags & MEM_Null) ){ sqlite3_value *pRet = sqlite3ValueNew(v->db); if( pRet ){ @@ -90194,8 +87177,7 @@ SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff */ SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){ assert( iVar>0 ); - assert( (v->db->flags & SQLITE_EnableQPSG)==0 - || (v->db->mDbFlags & DBFLAG_InternalFunc)!=0 ); + assert( (v->db->flags & SQLITE_EnableQPSG)==0 ); if( iVar>=32 ){ v->expmask |= 0x80000000; }else{ @@ -90237,20 +87219,6 @@ SQLITE_PRIVATE int sqlite3NotPureFunc(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 -** sqlite3BtreeCursorHint() with opcode BTREE_HINT_RANGE have -** byte-code register values correctly initialized. -*/ -SQLITE_PRIVATE int 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 sqlite3_vtab.zErrMsg (text stored @@ -90313,16 +87281,6 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( PreUpdate preupdate; const char *zTbl = pTab->zName; static const u8 fakeSortOrder = 0; -#ifdef SQLITE_DEBUG - int nRealCol; - if( pTab->tabFlags & TF_WithoutRowid ){ - nRealCol = 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)); @@ -90339,8 +87297,8 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( assert( pCsr!=0 ); assert( pCsr->eCurType==CURTYPE_BTREE ); - assert( pCsr->nField==nRealCol - || (pCsr->nField==nRealCol+1 && op==SQLITE_DELETE && iReg==-1) + assert( pCsr->nField==pTab->nCol + || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1) ); preupdate.v = v; @@ -90391,7 +87349,6 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( */ /* #include "sqliteInt.h" */ /* #include "vdbeInt.h" */ -/* #include "opcodes.h" */ #ifndef SQLITE_OMIT_DEPRECATED /* @@ -90528,15 +87485,7 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){ int rc = SQLITE_OK; Vdbe *p = (Vdbe*)pStmt; #if SQLITE_THREADSAFE - sqlite3_mutex *mutex; -#endif -#ifdef SQLITE_ENABLE_API_ARMOR - if( pStmt==0 ){ - return SQLITE_MISUSE_BKPT; - } -#endif -#if SQLITE_THREADSAFE - mutex = p->db->mutex; + sqlite3_mutex *mutex = ((Vdbe*)pStmt)->db->mutex; #endif sqlite3_mutex_enter(mutex); for(i=0; inVar; i++){ @@ -90655,7 +87604,7 @@ SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){ SQLITE_NULL, /* 0x1f (not possible) */ SQLITE_FLOAT, /* 0x20 INTREAL */ SQLITE_NULL, /* 0x21 (not possible) */ - SQLITE_FLOAT, /* 0x22 INTREAL + TEXT */ + SQLITE_TEXT, /* 0x22 INTREAL + TEXT */ SQLITE_NULL, /* 0x23 (not possible) */ SQLITE_FLOAT, /* 0x24 (not possible) */ SQLITE_NULL, /* 0x25 (not possible) */ @@ -90759,7 +87708,7 @@ SQLITE_API void sqlite3_value_free(sqlite3_value *pOld){ ** is too big or if an OOM occurs. ** ** The invokeValueDestructor(P,X) routine invokes destructor function X() -** on value P if P is not going to be used and need to be destroyed. +** on value P is not going to be used and need to be destroyed. */ static void setResultStrOrError( sqlite3_context *pCtx, /* Function context */ @@ -90789,7 +87738,7 @@ static void setResultStrOrError( static int invokeValueDestructor( const void *p, /* Value to destroy */ void (*xDel)(void*), /* The destructor */ - sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if not NULL */ + sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if no NULL */ ){ assert( xDel!=SQLITE_DYNAMIC ); if( xDel==0 ){ @@ -90799,14 +87748,7 @@ static int invokeValueDestructor( }else{ xDel((void*)p); } -#ifdef SQLITE_ENABLE_API_ARMOR - if( pCtx!=0 ){ - sqlite3_result_error_toobig(pCtx); - } -#else - assert( pCtx!=0 ); sqlite3_result_error_toobig(pCtx); -#endif return SQLITE_TOOBIG; } SQLITE_API void sqlite3_result_blob( @@ -90815,12 +87757,6 @@ SQLITE_API void 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( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, 0, xDel); @@ -90831,14 +87767,8 @@ SQLITE_API void sqlite3_result_blob64( sqlite3_uint64 n, void (*xDel)(void *) ){ - assert( xDel!=SQLITE_DYNAMIC ); -#ifdef SQLITE_ENABLE_API_ARMOR - if( pCtx==0 ){ - invokeValueDestructor(z, xDel, 0); - return; - } -#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + assert( xDel!=SQLITE_DYNAMIC ); if( n>0x7fffffff ){ (void)invokeValueDestructor(z, xDel, pCtx); }else{ @@ -90846,48 +87776,30 @@ SQLITE_API void sqlite3_result_blob64( } } SQLITE_API void sqlite3_result_double(sqlite3_context *pCtx, double rVal){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( pCtx==0 ) return; -#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetDouble(pCtx->pOut, rVal); } SQLITE_API void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( pCtx==0 ) return; -#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_ERROR; sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( pCtx==0 ) return; -#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_ERROR; sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT); } #endif SQLITE_API void sqlite3_result_int(sqlite3_context *pCtx, int iVal){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( pCtx==0 ) return; -#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetInt64(pCtx->pOut, (i64)iVal); } SQLITE_API void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( pCtx==0 ) return; -#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetInt64(pCtx->pOut, iVal); } SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( pCtx==0 ) return; -#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetNull(pCtx->pOut); } @@ -90897,37 +87809,14 @@ SQLITE_API void sqlite3_result_pointer( const char *zPType, void (*xDestructor)(void*) ){ - Mem *pOut; -#ifdef SQLITE_ENABLE_API_ARMOR - if( pCtx==0 ){ - invokeValueDestructor(pPtr, xDestructor, 0); - return; - } -#endif - pOut = pCtx->pOut; + Mem *pOut = pCtx->pOut; assert( sqlite3_mutex_held(pOut->db->mutex) ); sqlite3VdbeMemRelease(pOut); pOut->flags = MEM_Null; sqlite3VdbeMemSetPointer(pOut, pPtr, zPType, xDestructor); } SQLITE_API void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){ - 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]; - sqlite3_snprintf(sizeof(zErr), zErr, - "misuse of sqlite3_result_subtype() by %s()", - pCtx->pFunc->zName); - sqlite3_result_error(pCtx, zErr, -1); - return; - } -#endif /* SQLITE_STRICT_SUBTYPE */ - pOut = pCtx->pOut; + Mem *pOut = pCtx->pOut; assert( sqlite3_mutex_held(pOut->db->mutex) ); pOut->eSubtype = eSubtype & 0xff; pOut->flags |= MEM_Subtype; @@ -90938,12 +87827,6 @@ SQLITE_API void sqlite3_result_text( int n, void (*xDel)(void *) ){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( pCtx==0 ){ - invokeValueDestructor(z, xDel, 0); - return; - } -#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel); } @@ -90954,23 +87837,13 @@ SQLITE_API void sqlite3_result_text64( void (*xDel)(void *), unsigned char enc ){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( pCtx==0 ){ - invokeValueDestructor(z, xDel, 0); - return; - } -#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); assert( xDel!=SQLITE_DYNAMIC ); - if( enc!=SQLITE_UTF8 ){ - if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; - n &= ~(u64)1; - } + if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; if( n>0x7fffffff ){ (void)invokeValueDestructor(z, xDel, pCtx); }else{ setResultStrOrError(pCtx, z, (int)n, enc, xDel); - sqlite3VdbeMemZeroTerminateIfAble(pCtx->pOut); } } #ifndef SQLITE_OMIT_UTF16 @@ -90981,7 +87854,7 @@ SQLITE_API void sqlite3_result_text16( void (*xDel)(void *) ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); - setResultStrOrError(pCtx, z, n & ~(u64)1, SQLITE_UTF16NATIVE, xDel); + setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel); } SQLITE_API void sqlite3_result_text16be( sqlite3_context *pCtx, @@ -90990,7 +87863,7 @@ SQLITE_API void sqlite3_result_text16be( void (*xDel)(void *) ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); - setResultStrOrError(pCtx, z, n & ~(u64)1, SQLITE_UTF16BE, xDel); + setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel); } SQLITE_API void sqlite3_result_text16le( sqlite3_context *pCtx, @@ -90999,20 +87872,11 @@ SQLITE_API void sqlite3_result_text16le( void (*xDel)(void *) ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); - setResultStrOrError(pCtx, z, n & ~(u64)1, SQLITE_UTF16LE, xDel); + setResultStrOrError(pCtx, z, n, SQLITE_UTF16LE, xDel); } #endif /* SQLITE_OMIT_UTF16 */ SQLITE_API void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){ - Mem *pOut; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( pCtx==0 ) return; - if( pValue==0 ){ - sqlite3_result_null(pCtx); - return; - } -#endif - pOut = pCtx->pOut; + Mem *pOut = pCtx->pOut; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemCopy(pOut, pValue); sqlite3VdbeChangeEncoding(pOut, pCtx->enc); @@ -91024,12 +87888,7 @@ SQLITE_API void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){ sqlite3_result_zeroblob64(pCtx, n>0 ? n : 0); } SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){ - Mem *pOut; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( pCtx==0 ) return SQLITE_MISUSE_BKPT; -#endif - pOut = pCtx->pOut; + Mem *pOut = pCtx->pOut; assert( sqlite3_mutex_held(pOut->db->mutex) ); if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){ sqlite3_result_error_toobig(pCtx); @@ -91043,9 +87902,6 @@ SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){ #endif } SQLITE_API void sqlite3_result_error_code(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; @@ -91058,9 +87914,6 @@ SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){ /* Force an SQLITE_TOOBIG error. */ SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( pCtx==0 ) return; -#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_TOOBIG; sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1, @@ -91069,9 +87922,6 @@ SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){ /* An SQLITE_NOMEM error. */ SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( pCtx==0 ) return; -#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetNull(pCtx->pOut); pCtx->isError = SQLITE_NOMEM_BKPT; @@ -91233,7 +88083,7 @@ static int 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); @@ -91324,9 +88174,6 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ ** pointer to it. */ SQLITE_API void *sqlite3_user_data(sqlite3_context *p){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( p==0 ) return 0; -#endif assert( p && p->pFunc ); return p->pFunc->pUserData; } @@ -91342,11 +88189,7 @@ SQLITE_API void *sqlite3_user_data(sqlite3_context *p){ ** application defined function. */ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( p==0 ) return 0; -#else assert( p && p->pOut ); -#endif return p->pOut->db; } @@ -91365,25 +88208,10 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){ ** value, as a signal to the xUpdate routine that the column is unchanged. */ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context *p){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( p==0 ) return 0; -#else assert( p ); -#endif return 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 sqlite3_vtab_in_first()/sqlite3_vtab_in_next() that are not -** preceded by activation of IN processing via sqlite3_vtab_int() do not -** try to access a fake ValueList object inserted by a hostile extension. -*/ -SQLITE_PRIVATE void sqlite3VdbeValueListFree(void *pToDelete){ - sqlite3_free(pToDelete); -} - /* ** Implementation of sqlite3_vtab_in_first() (if bNext==0) and ** sqlite3_vtab_in_next() (if bNext!=0). @@ -91397,16 +88225,9 @@ static int valueFromValueList( ValueList *pRhs; *ppOut = 0; - if( pVal==0 ) return SQLITE_MISUSE_BKPT; - if( (pVal->flags & MEM_Dyn)==0 || pVal->xDel!=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( pVal==0 ) return SQLITE_MISUSE; + pRhs = (ValueList*)sqlite3_value_pointer(pVal, "ValueList"); + if( pRhs==0 ) return SQLITE_MISUSE; if( bNext ){ rc = sqlite3BtreeNext(pRhs->pCsr, 0); }else{ @@ -91528,9 +88349,6 @@ SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ AuxData *pAuxData; -#ifdef SQLITE_ENABLE_API_ARMOR - if( pCtx==0 ) return 0; -#endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); #if SQLITE_ENABLE_STAT4 if( pCtx->pVdbe==0 ) return 0; @@ -91563,12 +88381,8 @@ SQLITE_API void sqlite3_set_auxdata( void (*xDelete)(void*) ){ AuxData *pAuxData; - Vdbe *pVdbe; + Vdbe *pVdbe = pCtx->pVdbe; -#ifdef SQLITE_ENABLE_API_ARMOR - if( pCtx==0 ) return; -#endif - pVdbe= pCtx->pVdbe; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); #ifdef SQLITE_ENABLE_STAT4 if( pVdbe==0 ) goto failed; @@ -91624,8 +88438,7 @@ SQLITE_API int sqlite3_aggregate_count(sqlite3_context *p){ */ SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt){ Vdbe *pVm = (Vdbe *)pStmt; - if( pVm==0 ) return 0; - return pVm->nResColumn; + return pVm ? pVm->nResColumn : 0; } /* @@ -91634,7 +88447,7 @@ SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt){ */ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt){ Vdbe *pVm = (Vdbe *)pStmt; - if( pVm==0 || pVm->pResultRow==0 ) return 0; + if( pVm==0 || pVm->pResultSet==0 ) return 0; return pVm->nResColumn; } @@ -91689,8 +88502,8 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){ if( pVm==0 ) return (Mem*)columnNullValue(); assert( pVm->db ); sqlite3_mutex_enter(pVm->db->mutex); - if( pVm->pResultRow!=0 && inResColumn && i>=0 ){ - pOut = &pVm->pResultRow[i]; + if( pVm->pResultSet!=0 && inResColumn && i>=0 ){ + pOut = &pVm->pResultSet[i]; }else{ sqlite3Error(pVm->db, SQLITE_RANGE); pOut = (Mem*)columnNullValue(); @@ -91714,7 +88527,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){ ** sqlite3_column_real() ** sqlite3_column_bytes() ** sqlite3_column_bytes16() -** sqlite3_column_blob() +** sqiite3_column_blob() */ static void columnMallocFailure(sqlite3_stmt *pStmt) { @@ -91798,32 +88611,6 @@ SQLITE_API int sqlite3_column_type(sqlite3_stmt *pStmt, int i){ return iType; } -/* -** 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. @@ -91856,29 +88643,15 @@ static const void *columnName( return 0; } #endif - if( N<0 ) return 0; ret = 0; p = (Vdbe *)pStmt; db = p->db; assert( db!=0 ); - 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( NmallocFailed; + n = sqlite3_column_count(pStmt); + if( N=0 ){ N += useType*n; + sqlite3_mutex_enter(db->mutex); + assert( db->mallocFailed==0 ); #ifndef SQLITE_OMIT_UTF16 if( useUtf16 ){ ret = sqlite3_value_text16((sqlite3_value*)&p->aColName[N]); @@ -91890,14 +88663,12 @@ 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. */ - assert( db->mallocFailed==0 || db->mallocFailed==1 ); - if( db->mallocFailed > prior_mallocFailed ){ + if( db->mallocFailed ){ sqlite3OomClear(db); ret = 0; } + sqlite3_mutex_leave(db->mutex); } -columnName_end: - sqlite3_mutex_leave(db->mutex); return ret; } @@ -91990,7 +88761,7 @@ SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){ /* ** 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. Otherwise SQLITE_OK. +** out of range, then SQLITE_RANGE is returned. Othewise SQLITE_OK. ** ** A successful evaluation of this routine acquires the mutex on p. ** the mutex is released if any kind of error occurs. @@ -92005,7 +88776,7 @@ static int vdbeUnbind(Vdbe *p, unsigned int i){ } sqlite3_mutex_enter(p->db->mutex); if( p->eVdbeState!=VDBE_READY_STATE ){ - sqlite3Error(p->db, SQLITE_MISUSE_BKPT); + sqlite3Error(p->db, SQLITE_MISUSE); sqlite3_mutex_leave(p->db->mutex); sqlite3_log(SQLITE_MISUSE, "bind on a busy prepared statement: [%s]", p->zSql); @@ -92166,10 +88937,7 @@ SQLITE_API int sqlite3_bind_text64( unsigned char enc ){ assert( xDel!=SQLITE_DYNAMIC ); - if( enc!=SQLITE_UTF8 ){ - if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; - nData &= ~(u16)1; - } + if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; return bindText(pStmt, i, zData, nData, xDel, enc); } #ifndef SQLITE_OMIT_UTF16 @@ -92177,10 +88945,10 @@ SQLITE_API int sqlite3_bind_text16( sqlite3_stmt *pStmt, int i, const void *zData, - int n, + int nData, void (*xDel)(void*) ){ - return bindText(pStmt, i, zData, n & ~(u64)1, xDel, SQLITE_UTF16NATIVE); + return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE); } #endif /* SQLITE_OMIT_UTF16 */ SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){ @@ -92234,9 +89002,6 @@ SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){ SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint64 n){ int rc; Vdbe *p = (Vdbe *)pStmt; -#ifdef SQLITE_ENABLE_API_ARMOR - if( p==0 ) return SQLITE_MISUSE_BKPT; -#endif sqlite3_mutex_enter(p->db->mutex); if( n>(u64)p->db->aLimit[SQLITE_LIMIT_LENGTH] ){ rc = SQLITE_TOOBIG; @@ -92357,42 +89122,6 @@ SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt){ return pStmt ? ((Vdbe*)pStmt)->explain : 0; } -/* -** Set the explain mode for a statement. -*/ -SQLITE_API int sqlite3_stmt_explain(sqlite3_stmt *pStmt, int eMode){ - Vdbe *v = (Vdbe*)pStmt; - int rc; -#ifdef SQLITE_ENABLE_API_ARMOR - if( pStmt==0 ) return SQLITE_MISUSE_BKPT; -#endif - 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 = sqlite3Reprepare(v); - v->haveEqpOps = eMode==2; - } - if( v->explain ){ - v->nResColumn = 12 - 4*v->explain; - }else{ - v->nResColumn = v->nResAlloc; - } - sqlite3_mutex_leave(v->db->mutex); - return rc; -} - /* ** Return true if the prepared statement is in need of being reset. */ @@ -92532,16 +89261,10 @@ static UnpackedRecord *vdbeUnpackRecord( ** a field of the row currently being updated or deleted. */ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ - PreUpdate *p; + PreUpdate *p = db->pPreUpdate; 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 ){ @@ -92602,12 +89325,7 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa ** the number of columns in the row being updated, deleted or inserted. */ SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){ - PreUpdate *p; -#ifdef SQLITE_ENABLE_API_ARMOR - p = db!=0 ? db->pPreUpdate : 0; -#else - p = db->pPreUpdate; -#endif + PreUpdate *p = db->pPreUpdate; return (p ? p->keyinfo.nKeyField : 0); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ @@ -92625,12 +89343,7 @@ SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){ ** or SET DEFAULT action is considered a trigger. */ SQLITE_API int sqlite3_preupdate_depth(sqlite3 *db){ - PreUpdate *p; -#ifdef SQLITE_ENABLE_API_ARMOR - p = db!=0 ? db->pPreUpdate : 0; -#else - p = db->pPreUpdate; -#endif + PreUpdate *p = db->pPreUpdate; return (p ? p->v->nFrame : 0); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ @@ -92641,12 +89354,7 @@ SQLITE_API int sqlite3_preupdate_depth(sqlite3 *db){ ** only. */ SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *db){ - PreUpdate *p; -#ifdef SQLITE_ENABLE_API_ARMOR - p = db!=0 ? db->pPreUpdate : 0; -#else - p = db->pPreUpdate; -#endif + PreUpdate *p = db->pPreUpdate; return (p ? p->iBlobWrite : -1); } #endif @@ -92657,16 +89365,10 @@ SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *db){ ** a field of the row currently being updated or inserted. */ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ - PreUpdate *p; + PreUpdate *p = db->pPreUpdate; 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; @@ -92737,79 +89439,23 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppVa /* ** Return status data for a single loop within query pStmt. */ -SQLITE_API int sqlite3_stmt_scanstatus_v2( +SQLITE_API int sqlite3_stmt_scanstatus( sqlite3_stmt *pStmt, /* Prepared statement being queried */ - int iScan, /* Index of loop to report on */ + int idx, /* 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; - VdbeOp *aOp; - int nOp; - ScanStatus *pScan = 0; - int idx; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( p==0 || pOut==0 - || iScanStatusOpSQLITE_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; iinScan; 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] ); + ScanStatus *pScan; + if( idx<0 || idx>=p->nScan ) return 1; pScan = &p->aScan[idx]; - switch( iScanStatusOp ){ case SQLITE_SCANSTAT_NLOOP: { - if( pScan->addrLoop>0 ){ - *(sqlite3_int64*)pOut = aOp[pScan->addrLoop].nExec; - }else{ - *(sqlite3_int64*)pOut = -1; - } + *(sqlite3_int64*)pOut = p->anExec[pScan->addrLoop]; break; } case SQLITE_SCANSTAT_NVISIT: { - if( pScan->addrVisit>0 ){ - *(sqlite3_int64*)pOut = aOp[pScan->addrVisit].nExec; - }else{ - *(sqlite3_int64*)pOut = -1; - } + *(sqlite3_int64*)pOut = p->anExec[pScan->addrVisit]; break; } case SQLITE_SCANSTAT_EST: { @@ -92828,7 +89474,7 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2( } case SQLITE_SCANSTAT_EXPLAIN: { if( pScan->addrExplain ){ - *(const char**)pOut = aOp[ pScan->addrExplain ].p4.z; + *(const char**)pOut = p->aOp[ pScan->addrExplain ].p4.z; }else{ *(const char**)pOut = 0; } @@ -92836,51 +89482,12 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2( } case SQLITE_SCANSTAT_SELECTID: { if( pScan->addrExplain ){ - *(int*)pOut = aOp[ pScan->addrExplain ].p1; - }else{ - *(int*)pOut = -1; - } - break; - } - case SQLITE_SCANSTAT_PARENTID: { - if( pScan->addrExplain ){ - *(int*)pOut = aOp[ pScan->addrExplain ].p2; + *(int*)pOut = p->aOp[ pScan->addrExplain ].p1; }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; iiaAddrRange); 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; iOpp1!=iEnd ) continue; - if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_NCYCLE)==0 ){ - continue; - } - res += aOp[iOp].nCycle; - } - } - } - } - *(i64*)pOut = res; - break; - } default: { return 1; } @@ -92888,29 +89495,12 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2( return 0; } -/* -** Return status data for a single loop within query pStmt. -*/ -SQLITE_API int sqlite3_stmt_scanstatus( - 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 sqlite3_stmt_scanstatus_v2(pStmt, iScan, iScanStatusOp, 0, pOut); -} - /* ** Zero all counters associated with the sqlite3_stmt_scanstatus() data. */ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){ Vdbe *p = (Vdbe*)pStmt; - int ii; - for(ii=0; p!=0 && iinOp; ii++){ - Op *pOp = &p->aOp[ii]; - pOp->nExec = 0; - pOp->nCycle = 0; - } + memset(p->anExec, 0, p->nOp * sizeof(i64)); } #endif /* SQLITE_ENABLE_STMT_SCANSTATUS */ @@ -93245,12 +89835,8 @@ SQLITE_API int sqlite3_found_count = 0; ** sqlite3CantopenError(lineno) */ static void test_trace_breakpoint(int pc, Op *pOp, Vdbe *v){ - static u64 n = 0; - (void)pc; - (void)pOp; - (void)v; + static int n = 0; n++; - if( n==LARGEST_UINT64 ) abort(); /* So that n is used, preventing a warning */ } #endif @@ -93488,10 +90074,6 @@ 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. ** @@ -93506,11 +90088,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_FLEXNUM ); + || affinity==SQLITE_AFF_NUMERIC ); if( (pRec->flags & MEM_Int)==0 ){ /*OPTIMIZATION-IF-FALSE*/ - if( (pRec->flags & (MEM_Real|MEM_IntReal))==0 ){ + if( (pRec->flags & MEM_Real)==0 ){ if( pRec->flags & MEM_Str ) applyNumericAffinity(pRec,1); - }else if( affinity<=SQLITE_AFF_REAL ){ + }else{ sqlite3VdbeIntegerAffinity(pRec); } } @@ -93670,9 +90252,6 @@ SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr){ sqlite3_str_appendchar(pStr, 1, (c>=0x20&&c<=0x7f) ? c : '.'); } sqlite3_str_appendf(pStr, "]%s", encnames[pMem->enc]); - if( f & MEM_Term ){ - sqlite3_str_appendf(pStr, "(0-term)"); - } } } #endif @@ -93741,6 +90320,17 @@ SQLITE_PRIVATE void 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 @@ -93800,102 +90390,13 @@ static u64 filterHash(const Mem *aMem, const Op *pOp){ }else if( p->flags & MEM_Real ){ h += sqlite3VdbeIntValue(p); }else if( p->flags & (MEM_Str|MEM_Blob) ){ - /* 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)); + h += p->n; + if( p->flags & MEM_Zero ) h += p->u.nZero; } } 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; - sqlite3 *db = pDest->db; - int encoding = pDest->enc; - int len = 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 = 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!=sqlite3BtreeOffset(pC->uc.pCursor) - ){ - if( pCache->pCValue ) sqlite3RCStrUnref(pCache->pCValue); - pBuf = pCache->pCValue = sqlite3RCStrNew( len+3 ); - if( pBuf==0 ) return SQLITE_NOMEM; - rc = 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 = sqlite3BtreeOffset(pC->uc.pCursor); - }else{ - pBuf = pCache->pCValue; - } - assert( t>=12 ); - sqlite3RCStrRef(pBuf); - if( t&1 ){ - rc = sqlite3VdbeMemSetStr(pDest, pBuf, len, encoding, - sqlite3RCStrUnref); - pDest->flags |= MEM_Term; - }else{ - rc = sqlite3VdbeMemSetStr(pDest, pBuf, len, 0, - sqlite3RCStrUnref); - } - }else{ - rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, iOffset, len, pDest); - if( rc ) return rc; - 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 */ @@ -93919,10 +90420,11 @@ SQLITE_PRIVATE int sqlite3VdbeExec( ){ Op *aOp = p->aOp; /* Copy of p->aOp */ Op *pOp = aOp; /* Current operation */ -#ifdef SQLITE_DEBUG +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) Op *pOrigOp; /* Value of pOp at the top of the loop */ +#endif +#ifdef SQLITE_DEBUG int nExtraDelete = 0; /* Verifies FORDELETE and AUXDELETE flags */ - u8 iCompareIsInit = 0; /* iCompare is initialized */ #endif int rc = SQLITE_OK; /* Value to return */ sqlite3 *db = p->db; /* The database */ @@ -93938,17 +90440,13 @@ SQLITE_PRIVATE int 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; +#ifdef VDBE_PROFILE + u64 start; /* CPU clock count at start of opcode */ #endif /*** INSERT STACK UNION HERE ***/ assert( p->eVdbeState==VDBE_RUN_STATE ); /* sqlite3_step() verifies this */ - if( DbMaskNonZero(p->lockMask) ){ - sqlite3VdbeEnter(p); - } + sqlite3VdbeEnter(p); #ifndef SQLITE_OMIT_PROGRESS_CALLBACK if( db->xProgress ){ u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP]; @@ -93969,6 +90467,7 @@ SQLITE_PRIVATE int 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; sqlite3VdbeIOTraceSql(p); @@ -94005,18 +90504,12 @@ SQLITE_PRIVATE int sqlite3VdbeExec( assert( rc==SQLITE_OK ); assert( pOp>=aOp && pOp<&aOp[p->nOp]); +#ifdef VDBE_PROFILE + start = sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime(); +#endif nVmStep++; - -#if defined(VDBE_PROFILE) - pOp->nExec++; - pnCycle = &pOp->nCycle; - if( sqlite3NProfileCnt==0 ) *pnCycle -= sqlite3Hwtime(); -#elif defined(SQLITE_ENABLE_STMT_SCANSTATUS) - if( bStmtScanStatus ){ - pOp->nExec++; - pnCycle = &pOp->nCycle; - *pnCycle -= sqlite3Hwtime(); - } +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + if( p->anExec ) p->anExec[(int)(pOp-aOp)]++; #endif /* Only allow tracing if SQLITE_DEBUG is defined. @@ -94078,7 +90571,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec( } } #endif -#ifdef SQLITE_DEBUG +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) pOrigOp = pOp; #endif @@ -94134,8 +90627,8 @@ SQLITE_PRIVATE int sqlite3VdbeExec( case OP_Goto: { /* jump */ #ifdef SQLITE_DEBUG - /* 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 + /* 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 ** instruction. */ if( pOp->p5 ){ assert( pOp->p2 < (int)(pOp - aOp) ); @@ -94242,7 +90735,7 @@ case OP_Return: { /* in1 */ ** ** See also: EndCoroutine */ -case OP_InitCoroutine: { /* jump0 */ +case OP_InitCoroutine: { /* jump */ assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); assert( pOp->p2>=0 && pOp->p2nOp ); assert( pOp->p3>=0 && pOp->p3nOp ); @@ -94265,9 +90758,7 @@ 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, the value register P1 is left with a value -** such that subsequent OP_Yields go back to the this same -** OP_EndCoroutine instruction. +** After the jump, register P1 becomes undefined. ** ** See also: InitCoroutine */ @@ -94279,8 +90770,8 @@ case OP_EndCoroutine: { /* in1 */ pCaller = &aOp[pIn1->u.i]; assert( pCaller->opcode==OP_Yield ); assert( pCaller->p2>=0 && pCaller->p2nOp ); - pIn1->u.i = (int)(pOp - p->aOp) - 1; pOp = &aOp[pCaller->p2 - 1]; + pIn1->flags = MEM_Undefined; break; } @@ -94297,7 +90788,7 @@ case OP_EndCoroutine: { /* in1 */ ** ** See also: InitCoroutine */ -case OP_Yield: { /* in1, jump0 */ +case OP_Yield: { /* in1, jump */ int pcDest; pIn1 = &aMem[pOp->p1]; assert( VdbeMemDynamic(pIn1)==0 ); @@ -94345,7 +90836,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 constraint failed: P4 +** 1: NOT NULL contraint failed: P4 ** 2: UNIQUE constraint failed: P4 ** 3: CHECK constraint failed: P4 ** 4: FOREIGN KEY constraint failed: P4 @@ -94364,12 +90855,6 @@ case OP_Halt: { #ifdef SQLITE_DEBUG if( pOp->p2==OE_Abort ){ 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; @@ -94627,15 +91112,19 @@ case OP_Blob: { /* out2 */ break; } -/* Opcode: Variable P1 P2 * * * -** Synopsis: r[P2]=parameter(P1) +/* Opcode: Variable P1 P2 * P4 * +** Synopsis: r[P2]=parameter(P1,P4) ** ** 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 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==sqlite3VListNumToName(p->pVList,pOp->p1) ); pVar = &p->aVar[pOp->p1 - 1]; if( sqlite3VdbeMemTooBig(pVar) ){ goto too_big; @@ -94807,10 +91296,10 @@ case OP_ResultRow: { assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); p->cacheCtr = (p->cacheCtr + 2)|1; - p->pResultRow = &aMem[pOp->p1]; + p->pResultSet = &aMem[pOp->p1]; #ifdef SQLITE_DEBUG { - Mem *pMem = p->pResultRow; + Mem *pMem = p->pResultSet; int i; for(i=0; ip2; i++){ assert( memIsValid(&pMem[i]) ); @@ -95145,7 +91634,7 @@ case OP_AddImm: { /* in1 */ pIn1 = &aMem[pOp->p1]; memAboutToChange(p, pIn1); sqlite3VdbeMemIntegerify(pIn1); - *(u64*)&pIn1->u.i += (u64)pOp->p2; + pIn1->u.i += pOp->p2; break; } @@ -95156,7 +91645,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: { /* jump0, in1 */ +case OP_MustBeInt: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; if( (pIn1->flags & MEM_Int)==0 ){ applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding); @@ -95197,7 +91686,7 @@ case OP_RealAffinity: { /* in1 */ } #endif -#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_ANALYZE) +#ifndef SQLITE_OMIT_CAST /* Opcode: Cast P1 P2 * * * ** Synopsis: affinity(r[P1]) ** @@ -95340,6 +91829,7 @@ 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( sqlite3aGTb[pOp->opcode] ){ @@ -95347,21 +91837,18 @@ 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( sqlite3aLTb[pOp->opcode] ){ VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3); goto jump_to_p2; } iCompare = -1; - VVA_ONLY( iCompareIsInit = 1; ) }else{ if( 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; @@ -95393,7 +91880,6 @@ 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{ @@ -95404,28 +91890,24 @@ 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); - assert( flags3==pIn3->flags || CORRUPT_DB ); + testcase( flags3==pIn3->flags ); flags3 = pIn3->flags; } if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3,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 ){ + }else if( affinity==SQLITE_AFF_TEXT ){ + if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn1->flags & MEM_Int ); testcase( pIn1->flags & MEM_Real ); testcase( pIn1->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pIn1, encoding, 1); testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) ); flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask); - if( NEVER(pIn1==pIn3) ) flags3 = flags1 | MEM_Str; + if( pIn1==pIn3 ) flags3 = flags1 | MEM_Str; } - if( (flags3 & MEM_Str)!=0 ){ - pIn3->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal); - }else if( (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ + if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn3->flags & MEM_Int ); testcase( pIn3->flags & MEM_Real ); testcase( pIn3->flags & MEM_IntReal ); @@ -95454,7 +91936,6 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ res2 = 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) ); @@ -95476,10 +91957,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 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. +** 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. */ case OP_ElseEq: { /* same as TK_ESCAPE, jump */ @@ -95493,7 +91974,6 @@ 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; @@ -95588,7 +92068,6 @@ case OP_Compare: { pColl = pKeyInfo->aColl[i]; bRev = (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_DESC); iCompare = 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)) @@ -95606,14 +92085,13 @@ 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 ){ @@ -95833,12 +92311,6 @@ 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. @@ -95909,7 +92381,7 @@ case OP_IsType: { /* jump */ /* Opcode: ZeroOrNull P1 P2 P3 * * ** Synopsis: r[P2] = 0 OR NULL ** -** If both registers P1 and P3 are NOT NULL, then store a zero in +** If all 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. */ @@ -95952,7 +92424,7 @@ case OP_IfNullRow: { /* jump */ VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; - if( pC && pC->nullRow ){ + if( ALWAYS(pC) && pC->nullRow ){ sqlite3VdbeMemSetNull(aMem + pOp->p3); goto jump_to_p2; } @@ -96019,7 +92491,7 @@ case OP_Offset: { /* out3 */ ** 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: { /* ncycle */ +case OP_Column: { u32 p2; /* column number to retrieve */ VdbeCursor *pC; /* The VDBE cursor */ BtCursor *pCrsr; /* The B-Tree cursor corresponding to pC */ @@ -96263,16 +92735,11 @@ 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( ((p5 = (pOp->p5 & OPFLAG_BYTELENARG))!=0 - && (p5==OPFLAG_TYPEOFARG - || (t>=12 && ((t&1)==0 || p5==OPFLAG_BYTELENARG)) - ) - ) - || sqlite3VdbeSerialTypeLen(t)==0 + if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0 + && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)) + || (len = sqlite3VdbeSerialTypeLen(t))==0 ){ /* Content is irrelevant for ** 1. the typeof() function, @@ -96289,13 +92756,11 @@ op_column_restart: */ sqlite3VdbeSerialGet((u8*)sqlite3CtypeMap, t, pDest); }else{ - 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; - } + if( len>db->aLimit[SQLITE_LIMIT_LENGTH] ) goto too_big; + rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest); + if( rc!=SQLITE_OK ) goto abort_due_to_error; + sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest); + pDest->flags &= ~MEM_Ephem; } } @@ -96375,7 +92840,7 @@ case OP_TypeCheck: { } case COLTYPE_REAL: { testcase( (pIn1->flags & (MEM_Real|MEM_IntReal))==MEM_Real ); - assert( (pIn1->flags & MEM_IntReal)==0 ); + testcase( (pIn1->flags & (MEM_Real|MEM_IntReal))==MEM_IntReal ); 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 @@ -96454,7 +92919,7 @@ case OP_Affinity: { }else{ pIn1->u.r = (double)pIn1->u.i; pIn1->flags |= MEM_Real; - pIn1->flags &= ~(MEM_Int|MEM_Str); + pIn1->flags &= ~MEM_Int; } } REGISTER_TRACE((int)(pIn1-aMem), pIn1); @@ -96757,6 +93222,7 @@ 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)); @@ -96764,22 +93230,12 @@ case OP_MakeRecord: { }else{ v = pRec->u.i; } - len = 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); + len = i = sqlite3SmallTypeSizes[serial_type]; + assert( i>0 ); + while( 1 /*exit-by-break*/ ){ + zPayload[--i] = (u8)(v&0xFF); + if( i==0 ) break; + v >>= 8; } zPayload += len; } @@ -97387,7 +93843,7 @@ case OP_SetCookie: { ** ** See also: OP_OpenRead, OP_ReopenIdx */ -case OP_ReopenIdx: { /* ncycle */ +case OP_ReopenIdx: { int nField; KeyInfo *pKeyInfo; u32 p2; @@ -97408,7 +93864,7 @@ case OP_ReopenIdx: { /* ncycle */ } /* 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: /* ncycle */ +case OP_OpenRead: case OP_OpenWrite: assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ ); @@ -97502,7 +93958,7 @@ open_cursor_set_hints: ** ** Duplicate ephemeral cursors are used for self-joins of materialized views. */ -case OP_OpenDup: { /* ncycle */ +case OP_OpenDup: { VdbeCursor *pOrig; /* The original cursor to be duplicated */ VdbeCursor *pCx; /* The new cursor */ @@ -97564,8 +94020,8 @@ case OP_OpenDup: { /* ncycle */ ** by this opcode will be used for automatically created transient ** indices in joins. */ -case OP_OpenAutoindex: /* ncycle */ -case OP_OpenEphemeral: { /* ncycle */ +case OP_OpenAutoindex: +case OP_OpenEphemeral: { VdbeCursor *pCx; KeyInfo *pKeyInfo; @@ -97588,7 +94044,7 @@ case OP_OpenEphemeral: { /* ncycle */ } pCx = p->apCsr[pOp->p1]; if( pCx && !pCx->noReuse && ALWAYS(pOp->p2<=pCx->nField) ){ - /* If the ephemeral table is already open and has no duplicates from + /* If the ephermeral 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 ); @@ -97697,8 +94153,7 @@ 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. If P2 is 0 or negative then the pseudo-cursor -** will return NULL for every column. +** the pseudo-table. */ case OP_OpenPseudo: { VdbeCursor *pCx; @@ -97724,7 +94179,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: { /* ncycle */ +case OP_Close: { assert( pOp->p1>=0 && pOp->p1nCursor ); sqlite3VdbeFreeCursor(p, p->apCsr[pOp->p1]); p->apCsr[pOp->p1] = 0; @@ -97841,10 +94296,10 @@ case OP_ColumnsUsed: { ** ** See also: Found, NotFound, SeekGt, SeekGe, SeekLt */ -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 */ +case OP_SeekLT: /* jump, in3, group */ +case OP_SeekLE: /* jump, in3, group */ +case OP_SeekGE: /* jump, in3, group */ +case OP_SeekGT: { /* jump, in3, group */ int res; /* Comparison result */ int oc; /* Opcode */ VdbeCursor *pC; /* The cursor to seek */ @@ -98080,7 +94535,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 constraint. The jump to SeekGE.P2 ends the loop. The P5!=0 case +** the IN constraing. 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 @@ -98088,7 +94543,7 @@ seek_not_found: ** ** Possible outcomes from this opcode:
      ** -**
    1. If the cursor is initially not pointed to any valid row, then +**
    2. If the cursor is initally not pointed to any valid row, then ** fall through into the subsequent OP_SeekGE opcode. ** **
    3. If the cursor is left pointing to a row that is before the target @@ -98110,7 +94565,7 @@ seek_not_found: ** jump to SeekOP.P2 if This.P5==0 or to This.P2 if This.P5>0. **
    */ -case OP_SeekScan: { /* ncycle */ +case OP_SeekScan: { VdbeCursor *pC; int res; int nStep; @@ -98203,7 +94658,6 @@ case OP_SeekScan: { /* ncycle */ break; } nStep--; - pC->cacheStatus = CACHE_STALE; rc = sqlite3BtreeNext(pC->uc.pCursor, 0); if( rc ){ if( rc==SQLITE_DONE ){ @@ -98233,7 +94687,7 @@ case OP_SeekScan: { /* ncycle */ ** ** P1 must be a valid b-tree cursor. */ -case OP_SeekHit: { /* ncycle */ +case OP_SeekHit: { VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; @@ -98320,13 +94774,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 work +** falls through, the correct answer is still obtained, but extra works ** 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 skip some work. So if seekHit +** index. If it is not possible, we can skips some work. So if seekHit ** is less than P4, attempt to find out if a match is possible by running ** OP_NotFound. ** @@ -98365,7 +94819,7 @@ case OP_IfNotOpen: { /* jump */ ** ** See also: NotFound, Found, NotExists */ -case OP_IfNoHope: { /* jump, in3, ncycle */ +case OP_IfNoHope: { /* jump, in3 */ VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; @@ -98379,9 +94833,9 @@ case OP_IfNoHope: { /* jump, in3, ncycle */ /* Fall through into OP_NotFound */ /* no break */ deliberate_fall_through } -case OP_NoConflict: /* jump, in3, ncycle */ -case OP_NotFound: /* jump, in3, ncycle */ -case OP_Found: { /* jump, in3, ncycle */ +case OP_NoConflict: /* jump, in3 */ +case OP_NotFound: /* jump, in3 */ +case OP_Found: { /* jump, in3 */ int alreadyExists; int ii; VdbeCursor *pC; @@ -98511,7 +94965,7 @@ case OP_Found: { /* jump, in3, ncycle */ ** ** See also: Found, NotFound, NoConflict, SeekRowid */ -case OP_SeekRowid: { /* jump0, in3, ncycle */ +case OP_SeekRowid: { /* jump, in3 */ VdbeCursor *pC; BtCursor *pCrsr; int res; @@ -98536,7 +94990,7 @@ case OP_SeekRowid: { /* jump0, in3, ncycle */ } /* Fall through into OP_NotExists */ /* no break */ deliberate_fall_through -case OP_NotExists: /* jump, in3, ncycle */ +case OP_NotExists: /* jump, in3 */ pIn3 = &aMem[pOp->p3]; assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid ); assert( pOp->p1>=0 && pOp->p1nCursor ); @@ -98816,11 +95270,8 @@ case OP_Insert: { if( pOp->p5 & OPFLAG_ISNOOP ) break; #endif - 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; - } + 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; @@ -98831,14 +95282,12 @@ case OP_Insert: { x.nZero = 0; } x.pKey = 0; - assert( BTREE_PREFORMAT==OPFLAG_PREFORMAT ); rc = 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; @@ -98892,18 +95341,13 @@ case OP_RowCell: { ** left in an undefined state. ** ** If the OPFLAG_AUXDELETE bit is set on P5, that indicates that this -** 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). +** delete one of several associated with deleting a table row and all its +** associated index entries. Exactly one of those deletes is the "primary" +** delete. The others are all on OPFLAG_FORDELETE cursors or else are +** marked with the AUXDELETE flag. ** -** If the OPFLAG_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. +** If the OPFLAG_NCHANGE flag of P2 (NB: P2 not P5) is set, then the row +** change count is incremented (otherwise not). ** ** P1 must not be pseudo-table. It has to be a real table with ** multiple rows. @@ -99004,7 +95448,6 @@ case OP_Delete: { rc = sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5); pC->cacheStatus = CACHE_STALE; - colCacheCtr++; pC->seekResult = 0; if( rc ) goto abort_due_to_error; @@ -99072,13 +95515,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 used to move a record out of the sorter and into +** This opcode is normally use 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: { /* ncycle */ +case OP_SorterData: { VdbeCursor *pC; pOut = &aMem[pOp->p2]; @@ -99170,7 +95613,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, ncycle */ +case OP_Rowid: { /* out2 */ VdbeCursor *pC; i64 v; sqlite3_vtab *pVtab; @@ -99269,8 +95712,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: /* ncycle */ -case OP_Last: { /* jump0, ncycle */ +case OP_SeekEnd: +case OP_Last: { /* jump */ VdbeCursor *pC; BtCursor *pCrsr; int res; @@ -99304,38 +95747,28 @@ case OP_Last: { /* jump0, ncycle */ break; } -/* Opcode: IfSizeBetween P1 P2 P3 P4 * +/* Opcode: IfSmaller P1 P2 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. +** Estimate the number of rows in the table P1. Jump to P2 if that +** estimate is less than approximately 2**(0.1*P3). */ -case OP_IfSizeBetween: { /* jump */ +case OP_IfSmaller: { /* jump */ VdbeCursor *pC; BtCursor *pCrsr; int res; i64 sz; assert( pOp->p1>=0 && pOp->p1nCursor ); - 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 = sqlite3BtreeFirst(pCrsr, &res); if( rc ) goto abort_due_to_error; - if( res!=0 ){ - sz = -1; /* -Infinity encoding */ - }else{ + if( res==0 ){ sz = sqlite3BtreeRowCountEst(pCrsr); - assert( sz>0 ); - sz = sqlite3LogEst((u64)sz); + if( ALWAYS(sz>=0) && sqlite3LogEst((u64)sz)p3 ) res = 1; } - res = sz>=pOp->p3 && sz<=pOp->p4.i; VdbeBranchTaken(res!=0,2); if( res ) goto jump_to_p2; break; @@ -99363,8 +95796,8 @@ case OP_IfSizeBetween: { /* jump */ ** regression tests can determine whether or not the optimizer is ** correctly optimizing out sorts. */ -case OP_SorterSort: /* jump ncycle */ -case OP_Sort: { /* jump ncycle */ +case OP_SorterSort: /* jump */ +case OP_Sort: { /* jump */ #ifdef SQLITE_TEST sqlite3_sort_count++; sqlite3_search_count--; @@ -99381,22 +95814,17 @@ case OP_Sort: { /* jump ncycle */ ** 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: { /* jump0, ncycle */ +case OP_Rewind: { /* jump */ VdbeCursor *pC; BtCursor *pCrsr; int res; assert( pOp->p1>=0 && pOp->p1nCursor ); assert( pOp->p5==0 ); - assert( pOp->p2>=0 && pOp->p2nOp ); - pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) ); @@ -99416,10 +95844,9 @@ case OP_Rewind: { /* jump0, ncycle */ } if( rc ) goto abort_due_to_error; pC->nullRow = (u8)res; - if( pOp->p2>0 ){ - VdbeBranchTaken(res!=0,2); - if( res ) goto jump_to_p2; - } + assert( pOp->p2>0 && pOp->p2nOp ); + VdbeBranchTaken(res!=0,2); + if( res ) goto jump_to_p2; break; } @@ -99485,7 +95912,7 @@ case OP_SorterNext: { /* jump */ rc = sqlite3VdbeSorterNext(db, pC); goto next_tail; -case OP_Prev: /* jump, ncycle */ +case OP_Prev: /* jump */ assert( pOp->p1>=0 && pOp->p1nCursor ); assert( pOp->p5==0 || pOp->p5==SQLITE_STMTSTATUS_FULLSCAN_STEP @@ -99500,7 +95927,7 @@ case OP_Prev: /* jump, ncycle */ rc = sqlite3BtreePrevious(pC->uc.pCursor, pOp->p3); goto next_tail; -case OP_Next: /* jump, ncycle */ +case OP_Next: /* jump */ assert( pOp->p1>=0 && pOp->p1nCursor ); assert( pOp->p5==0 || pOp->p5==SQLITE_STMTSTATUS_FULLSCAN_STEP @@ -99692,8 +96119,8 @@ case OP_IdxDelete: { ** ** See also: Rowid, MakeRecord. */ -case OP_DeferredSeek: /* ncycle */ -case OP_IdxRowid: { /* out2, ncycle */ +case OP_DeferredSeek: +case OP_IdxRowid: { /* out2 */ VdbeCursor *pC; /* The P1 index cursor */ VdbeCursor *pTabCur; /* The P2 table cursor (OP_DeferredSeek only) */ i64 rowid; /* Rowid that P1 current points to */ @@ -99755,8 +96182,8 @@ case OP_IdxRowid: { /* out2, ncycle */ ** seek operation now, without further delay. If the cursor seek has ** already occurred, this instruction is a no-op. */ -case OP_FinishSeek: { /* ncycle */ - VdbeCursor *pC; /* The P1 index cursor */ +case OP_FinishSeek: { + VdbeCursor *pC; /* The P1 index cursor */ assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; @@ -99811,10 +96238,10 @@ case OP_FinishSeek: { /* ncycle */ ** 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, ncycle */ -case OP_IdxGT: /* jump, ncycle */ -case OP_IdxLT: /* jump, ncycle */ -case OP_IdxGE: { /* jump, ncycle */ +case OP_IdxLE: /* jump */ +case OP_IdxGT: /* jump */ +case OP_IdxLT: /* jump */ +case OP_IdxGE: { /* jump */ VdbeCursor *pC; int res; UnpackedRecord r; @@ -99891,7 +96318,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 destroyed is in the auxiliary database file +** P3==1 then the table to be clear 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 @@ -99951,8 +96378,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 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 +** 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 ** 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 @@ -100035,57 +96462,16 @@ case OP_CreateBtree: { /* out2 */ break; } -/* Opcode: SqlExec P1 P2 * P4 * +/* Opcode: SqlExec * * * 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 - sqlite3_xauth xAuth; -#endif - u8 mTrace; - int savedAnalysisLimit; - sqlite3VdbeIncrWriteCounter(p, 0); db->nSqlExec++; - 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 = sqlite3_exec(db, pOp->p4.z, 0, 0, &zErr); + rc = sqlite3_exec(db, pOp->p4.z, 0, 0, 0); db->nSqlExec--; -#ifndef SQLITE_OMIT_AUTHORIZATION - db->xAuth = xAuth; -#endif - db->mTrace = mTrace; - db->nAnalysisLimit = savedAnalysisLimit; - if( zErr || rc ){ - sqlite3VdbeError(p, "%s", zErr); - sqlite3_free(zErr); - if( rc==SQLITE_NOMEM ) goto no_mem; - goto abort_due_to_error; - } + if( rc ) goto abort_due_to_error; break; } @@ -100231,11 +96617,11 @@ case OP_DropTrigger: { /* Opcode: IntegrityCk P1 P2 P3 P4 P5 ** ** Do an analysis of the currently open database. Store in -** register (P1+1) the text of an error message describing any problems. -** If no problems are found, store a NULL in register (P1+1). +** register P1 the text of an error message describing any problems. +** If no problems are found, store a NULL in register P1. ** -** The register (P1) contains one less than the maximum number of allowed -** errors. At most reg(P1) errors will be reported. +** The register P3 contains one less than the maximum number of allowed errors. +** At most reg(P3) 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. ** @@ -100255,27 +96641,24 @@ 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->p1>0 && (pOp->p1+1)<=(p->nMem+1 - p->nCursor) ); - pnErr = &aMem[pOp->p1]; + assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); + pnErr = &aMem[pOp->p3]; assert( (pnErr->flags & MEM_Int)!=0 ); assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 ); - pIn1 = &aMem[pOp->p1+1]; + pIn1 = &aMem[pOp->p1]; assert( pOp->p5nDb ); assert( DbMaskTest(p->btreeMask, pOp->p5) ); - rc = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], - &aMem[pOp->p3], nRoot, (int)pnErr->u.i+1, &nErr, &z); + z = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], nRoot, + (int)pnErr->u.i+1, &nErr); sqlite3VdbeMemSetNull(pIn1); if( nErr==0 ){ assert( z==0 ); - }else if( rc ){ - sqlite3_free(z); - goto abort_due_to_error; + }else if( z==0 ){ + goto no_mem; }else{ pnErr->u.i -= nErr-1; sqlite3VdbeMemSetStr(pIn1, z, -1, SQLITE_UTF8, sqlite3_free); @@ -100396,9 +96779,7 @@ 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. P2 might be zero, if there is -** no possibility that an IGNORE exception will be raised. -** Register P3 contains the address +** exception using the RAISE() function. 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. ** @@ -100406,7 +96787,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */ ** ** If P5 is non-zero, then recursive program invocation is enabled. */ -case OP_Program: { /* jump0 */ +case OP_Program: { /* jump */ 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 */ @@ -100481,6 +96862,9 @@ case OP_Program: { /* jump0 */ 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 @@ -100517,6 +96901,9 @@ case OP_Program: { /* jump0 */ 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. */ @@ -100823,7 +97210,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 relevant parts of the sqlite3_context object */ + ** reinitializes the relavant parts of the sqlite3_context object */ if( pCtx->pMem != pMem ){ pCtx->pMem = pMem; for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i]; @@ -100918,7 +97305,6 @@ case OP_AggFinal: { } sqlite3VdbeChangeEncoding(pMem, encoding); UPDATE_MAX_BLOBSIZE(pMem); - REGISTER_TRACE((int)(pMem-aMem), pMem); break; } @@ -101274,7 +97660,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: { /* ncycle */ +case OP_VOpen: { VdbeCursor *pCur; sqlite3_vtab_cursor *pVCur; sqlite3_vtab *pVtab; @@ -101310,52 +97696,6 @@ 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; - sqlite3_vtab *pVtab; - const sqlite3_module *pModule; - char *zErr = 0; - - pOut = &aMem[pOp->p2]; - 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 ); - sqlite3VtabLock(pTab->u.vtab.p); - assert( pOp->p1>=0 && pOp->p1nDb ); - rc = pModule->xIntegrity(pVtab, db->aDb[pOp->p1].zDbSName, pTab->zName, - pOp->p3, &zErr); - sqlite3VtabUnlock(pTab->u.vtab.p); - if( rc ){ - sqlite3_free(zErr); - goto abort_due_to_error; - } - if( zErr ){ - sqlite3VdbeMemSetStr(pOut, zErr, -1, SQLITE_UTF8, sqlite3_free); - } - break; -} -#endif /* SQLITE_OMIT_VIRTUALTABLE */ - #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VInitIn P1 P2 P3 * * ** Synopsis: r[P2]=ValueList(P1,P3) @@ -101367,7 +97707,7 @@ case OP_VCheck: { /* out2 */ ** cursor. Register P3 is used to hold the values returned by ** sqlite3_vtab_in_first() and sqlite3_vtab_in_next(). */ -case OP_VInitIn: { /* out2, ncycle */ +case OP_VInitIn: { /* out2 */ VdbeCursor *pC; /* The cursor containing the RHS values */ ValueList *pRhs; /* New ValueList object to put in reg[P2] */ @@ -101378,7 +97718,7 @@ case OP_VInitIn: { /* out2, ncycle */ pRhs->pOut = &aMem[pOp->p3]; pOut = out2Prerelease(p, pOp); pOut->flags = MEM_Null; - sqlite3VdbeMemSetPointer(pOut, pRhs, "ValueList", sqlite3VdbeValueListFree); + sqlite3VdbeMemSetPointer(pOut, pRhs, "ValueList", sqlite3_free); break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -101404,7 +97744,7 @@ case OP_VInitIn: { /* out2, ncycle */ ** ** A jump is made to P2 if the result set after filtering would be empty. */ -case OP_VFilter: { /* jump, ncycle */ +case OP_VFilter: { /* jump */ int nArg; int iQuery; const sqlite3_module *pModule; @@ -101464,12 +97804,11 @@ case OP_VFilter: { /* jump, ncycle */ ** bits (OPFLAG_LENGTHARG or OPFLAG_TYPEOFARG) but those bits are ** unused by OP_VColumn. */ -case OP_VColumn: { /* ncycle */ +case OP_VColumn: { sqlite3_vtab *pVtab; const sqlite3_module *pModule; Mem *pDest; sqlite3_context sContext; - FuncDef nullFunc; VdbeCursor *pCur = p->apCsr[pOp->p1]; assert( pCur!=0 ); @@ -101487,9 +97826,6 @@ 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 ){ sqlite3VdbeMemSetNull(pDest); @@ -101520,7 +97856,7 @@ case OP_VColumn: { /* ncycle */ ** 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, ncycle */ +case OP_VNext: { /* jump */ sqlite3_vtab *pVtab; const sqlite3_module *pModule; int res; @@ -101751,7 +98087,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 deterministic of non-deterministic, depending on their arguments. +** either determinitic 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. @@ -101769,7 +98105,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 relevant parts of the sqlite3_context object */ + ** reinitializes the relavant parts of the sqlite3_context object */ pOut = &aMem[pOp->p3]; if( pCtx->pOut != pOut ){ pCtx->pVdbe = p; @@ -101822,42 +98158,6 @@ 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 ){ - sqlite3VdbeMemSetInt64(pOut, pIn1->eSubtype); - }else{ - 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) ** @@ -101881,7 +98181,7 @@ case OP_FilterAdd: { printf("hash: %llu modulo %d -> %u\n", h, pIn1->n, (int)(h%pIn1->n)); } #endif - h %= (pIn1->n*8); + h %= pIn1->n; pIn1->z[h/8] |= 1<<(h&7); break; } @@ -101917,7 +98217,7 @@ case OP_Filter: { /* jump */ printf("hash: %llu modulo %d -> %u\n", h, pIn1->n, (int)(h%pIn1->n)); } #endif - h %= (pIn1->n*8); + h %= pIn1->n; if( (pIn1->z[h/8] & (1<<(h&7)))==0 ){ VdbeBranchTaken(1, 2); p->aCounter[SQLITE_STMTSTATUS_FILTER_HIT]++; @@ -101955,7 +98255,7 @@ case OP_Filter: { /* jump */ ** error is encountered. */ case OP_Trace: -case OP_Init: { /* jump0 */ +case OP_Init: { /* jump */ int i; #ifndef SQLITE_OMIT_TRACE char *zTrace; @@ -102139,13 +98439,11 @@ default: { /* This is really OP_Noop, OP_Explain */ *****************************************************************************/ } -#if defined(VDBE_PROFILE) - *pnCycle += sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime(); - pnCycle = 0; -#elif defined(SQLITE_ENABLE_STMT_SCANSTATUS) - if( pnCycle ){ - *pnCycle += sqlite3Hwtime(); - pnCycle = 0; +#ifdef VDBE_PROFILE + { + u64 endTime = sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime(); + if( endTime>start ) pOrigOp->cycles += endTime - start; + pOrigOp->cnt++; } #endif @@ -102169,7 +98467,7 @@ default: { /* This is really OP_Noop, OP_Explain */ } if( opProperty==0xff ){ /* Never happens. This code exists to avoid a harmless linkage - ** warning about sqlite3VdbeRegisterDump() being defined but not + ** warning aboud sqlite3VdbeRegisterDump() being defined but not ** used. */ sqlite3VdbeRegisterDump(p); } @@ -102222,18 +98520,6 @@ abort_due_to_error: ** release the mutexes on btrees that were acquired at the ** top. */ vdbe_return: -#if defined(VDBE_PROFILE) - if( pnCycle ){ - *pnCycle += sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime(); - pnCycle = 0; - } -#elif defined(SQLITE_ENABLE_STMT_SCANSTATUS) - if( pnCycle ){ - *pnCycle += sqlite3Hwtime(); - pnCycle = 0; - } -#endif - #ifndef SQLITE_OMIT_PROGRESS_CALLBACK while( nVmStep>=nProgressLimit && db->xProgress!=0 ){ nProgressLimit += db->nProgressOps; @@ -102245,9 +98531,7 @@ vdbe_return: } #endif p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep; - if( DbMaskNonZero(p->lockMask) ){ - sqlite3VdbeLeave(p); - } + sqlite3VdbeLeave(p); assert( rc!=SQLITE_OK || nExtraDelete==0 || sqlite3_strlike("DELETE%",p->zSql,0)!=0 ); @@ -102342,7 +98626,8 @@ static int blobSeekToRow(Incrblob *p, 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 */ - sqlite3VdbeMemSetInt64(&v->aMem[1], iRow); + v->aMem[1].flags = MEM_Int; + v->aMem[1].u.i = 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 @@ -102425,7 +98710,7 @@ SQLITE_API int sqlite3_blob_open( #endif *ppBlob = 0; #ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || zTable==0 || zColumn==0 ){ + if( !sqlite3SafetyCheckOk(db) || zTable==0 ){ return SQLITE_MISUSE_BKPT; } #endif @@ -102624,7 +98909,7 @@ blob_open_out: if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt); sqlite3DbFree(db, pBlob); } - sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : (char*)0), zErr); + sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); sqlite3ParseObjectReset(&sParse); rc = sqlite3ApiExit(db, rc); @@ -102783,7 +99068,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ ((Vdbe*)p->pStmt)->rc = SQLITE_OK; rc = blobSeekToRow(p, iRow, &zErr); if( rc!=SQLITE_OK ){ - sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : (char*)0), zErr); + sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); } assert( rc!=SQLITE_SCHEMA ); @@ -102886,7 +99171,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ ** 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" multiplied by +** the value returned by "PRAGMA main.page_size" multipled by ** that returned by "PRAGMA main.cache_size", in bytes. ** ** If the sorter is running in single-threaded mode, then all PMAs generated @@ -102909,7 +99194,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ ** ** 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 retrieved from the sorter by the VDBE. The +** incrementally as keys are retreived from the sorter by the VDBE. The ** MergeEngine object, described in further detail below, performs this ** merge. ** @@ -102987,7 +99272,7 @@ struct SorterFile { struct SorterList { SorterRecord *pList; /* Linked list of records */ u8 *aMemory; /* If non-NULL, bulk memory to hold pList */ - i64 szPMA; /* Size of pList as PMA in bytes */ + int szPMA; /* Size of pList as PMA in bytes */ }; /* @@ -103072,7 +99357,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 requeries its own UnpackedRecord object to unpack records in +** each thread requries 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, @@ -103096,10 +99381,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 */ @@ -103144,7 +99429,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 point to aAlloc. +** and the key is copied into aAlloc and aKey is made to poitn to aAlloc. ** ** pFd==0 at EOF. */ @@ -104515,7 +100800,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 preferred as they use background threads - the final + ** sub-tasks are prefered as they use background threads - the final ** sub-task uses the main thread. */ for(i=0; iiPrev + i + 1) % nWorker; @@ -104573,8 +100858,8 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite( int rc = SQLITE_OK; /* Return Code */ SorterRecord *pNew; /* New list element */ int bFlush; /* True to flush contents of memory to PMA */ - i64 nReq; /* Bytes of memory required */ - i64 nPMA; /* Bytes of PMA space required */ + int nReq; /* Bytes of memory required */ + int nPMA; /* Bytes of PMA space required */ int t; /* serial type of first record field */ assert( pCsr->eCurType==CURTYPE_SORTER ); @@ -104999,7 +101284,7 @@ static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){ rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode); - /* Set up the required files for pIncr. A multi-threaded IncrMerge object + /* Set up the required files for pIncr. A multi-theaded IncrMerge object ** requires two temp files to itself, whereas a single-threaded object ** only requires a region of pTask->file2. */ if( rc==SQLITE_OK ){ @@ -105639,8 +101924,6 @@ static int bytecodevtabConnect( "p5 INT," "comment TEXT," "subprog TEXT," - "nexec INT," - "ncycle INT," "stmt HIDDEN" ");", @@ -105655,9 +101938,6 @@ static int bytecodevtabConnect( ");" }; - (void)argc; - (void)argv; - (void)pzErr; rc = sqlite3_declare_vtab(db, azSchema[isTabUsed]); if( rc==SQLITE_OK ){ pNew = sqlite3_malloc( sizeof(*pNew) ); @@ -105803,7 +102083,7 @@ static int bytecodevtabColumn( } } } - i += 20; + i += 10; } } switch( i ){ @@ -105853,31 +102133,16 @@ static int bytecodevtabColumn( } break; } - -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS - case 9: /* nexec */ - sqlite3_result_int64(ctx, pOp->nExec); - break; - case 10: /* ncycle */ - sqlite3_result_int64(ctx, pOp->nCycle); - break; -#else - case 9: /* nexec */ - case 10: /* ncycle */ - sqlite3_result_int(ctx, 0); - break; -#endif - - case 20: /* tables_used.type */ + case 10: /* tables_used.type */ sqlite3_result_text(ctx, pCur->zType, -1, SQLITE_STATIC); break; - case 21: /* tables_used.schema */ + case 11: /* tables_used.schema */ sqlite3_result_text(ctx, pCur->zSchema, -1, SQLITE_STATIC); break; - case 22: /* tables_used.name */ + case 12: /* tables_used.name */ sqlite3_result_text(ctx, pCur->zName, -1, SQLITE_STATIC); break; - case 23: /* tables_used.wr */ + case 13: /* tables_used.wr */ sqlite3_result_int(ctx, pOp->opcode==OP_OpenWrite); break; } @@ -105908,7 +102173,6 @@ 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; @@ -105951,7 +102215,7 @@ static int bytecodevtabBestIndex( int rc = SQLITE_CONSTRAINT; struct sqlite3_index_constraint *p; bytecodevtab *pVTab = (bytecodevtab*)tab; - int iBaseCol = pVTab->bTablesUsed ? 4 : 10; + int iBaseCol = pVTab->bTablesUsed ? 4 : 8; pIdxInfo->estimatedCost = (double)100; pIdxInfo->estimatedRows = 100; pIdxInfo->idxNum = 0; @@ -105998,8 +102262,7 @@ static sqlite3_module bytecodevtabModule = { /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, - /* xShadowName */ 0, - /* xIntegrity */ 0 + /* xShadowName */ 0 }; @@ -106523,7 +102786,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. */ -SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3WalkExprNN(Walker *pWalker, Expr *pExpr){ +static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){ int rc; testcase( ExprHasProperty(pExpr, EP_TokenOnly) ); testcase( ExprHasProperty(pExpr, EP_Reduced) ); @@ -106532,9 +102795,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3WalkExprNN(Walker *pWalker, Expr *pExp if( rc ) return rc & WRC_Abort; if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){ assert( pExpr->x.pList==0 || pExpr->pRight==0 ); - if( pExpr->pLeft && sqlite3WalkExprNN(pWalker, pExpr->pLeft) ){ - return WRC_Abort; - } + if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort; if( pExpr->pRight ){ assert( !ExprHasProperty(pExpr, EP_WinFunc) ); pExpr = pExpr->pRight; @@ -106558,7 +102819,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3WalkExprNN(Walker *pWalker, Expr *pExp return WRC_Continue; } SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){ - return pExpr ? sqlite3WalkExprNN(pWalker,pExpr) : WRC_Continue; + return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue; } /* @@ -106684,7 +102945,7 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){ } /* Increase the walkerDepth when entering a subquery, and -** decrease when leaving the subquery. +** descrease when leaving the subquery. */ SQLITE_PRIVATE int sqlite3WalkerDepthIncrease(Walker *pWalker, Select *pSelect){ UNUSED_PARAMETER(pSelect); @@ -106803,8 +103064,6 @@ static void resolveAlias( assert( iCol>=0 && iColnExpr ); pOrig = pEList->a[iCol].pExpr; assert( pOrig!=0 ); - assert( !ExprHasProperty(pExpr, EP_Reduced|EP_TokenOnly) ); - if( pExpr->pAggInfo ) return; db = pParse->db; pDup = sqlite3ExprDup(db, pOrig, 0); if( db->mallocFailed ){ @@ -106830,36 +103089,21 @@ static void resolveAlias( } /* -** 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.". 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. +** 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. */ SQLITE_PRIVATE int sqlite3MatchEName( const struct ExprList_item *pItem, const char *zCol, const char *zTab, - const char *zDb, - int *pbRowid + const char *zDb ){ int n; const char *zSpan; - int eEName = pItem->fg.eEName; - if( eEName!=ENAME_TAB && (eEName!=ENAME_ROWID || NEVER(pbRowid==0)) ){ - return 0; - } - assert( pbRowid==0 || *pbRowid==0 ); + if( pItem->fg.eEName!=ENAME_TAB ) return 0; zSpan = pItem->zEName; for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){} if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){ @@ -106871,11 +103115,9 @@ SQLITE_PRIVATE int sqlite3MatchEName( return 0; } zSpan += n+1; - if( zCol ){ - if( eEName==ENAME_TAB && sqlite3StrICmp(zSpan, zCol)!=0 ) return 0; - if( eEName==ENAME_ROWID && sqlite3IsRowid(zCol)==0 ) return 0; + if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){ + return 0; } - if( eEName==ENAME_ROWID ) *pbRowid = 1; return 1; } @@ -106908,7 +103150,6 @@ SQLITE_PRIVATE Bitmask 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 ){ @@ -106946,32 +103187,6 @@ 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( sqlite3StrNICmp(zTab, "sqlite_", 7)!=0 ) return 0; - zLegacy = pTab->zName; - if( strcmp(zLegacy+7, &LEGACY_TEMP_SCHEMA_TABLE[7])==0 ){ - if( sqlite3StrICmp(zTab+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 ){ - return 1; - } - if( zDb==0 ) return 0; - if( sqlite3StrICmp(zTab+7, &LEGACY_SCHEMA_TABLE[7])==0 ) return 1; - if( sqlite3StrICmp(zTab+7, &PREFERRED_SCHEMA_TABLE[7])==0 ) return 1; - }else{ - if( 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 @@ -107003,13 +103218,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 Expr *pRight, /* Name of the column. */ + const char *zCol, /* 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 potential "rowid" matches */ + int cntTab = 0; /* Number of matching table names */ int nSubquery = 0; /* How many levels of subquery */ sqlite3 *db = pParse->db; /* The database connection */ SrcItem *pItem; /* Use for looping over pSrcList items */ @@ -107020,7 +103235,6 @@ 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 */ @@ -107087,66 +103301,54 @@ static int lookupName( assert( pEList!=0 ); assert( pEList->nExpr==pTab->nCol ); for(j=0; jnExpr; j++){ - int bRowid = 0; /* True if possible rowid match */ - if( !sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb, &bRowid) ){ + if( !sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb) ){ continue; } - if( bRowid==0 ){ - if( cnt>0 ){ - if( pItem->fg.isUsing==0 - || 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. */ - 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; - sqlite3ExprListDelete(db, pFJMatch); - pFJMatch = 0; - }else{ - /* For a FULL JOIN, we must construct a coalesce() func */ - extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn); - } + if( cnt>0 ){ + if( pItem->fg.isUsing==0 + || 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. */ + 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; + 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; } - cntTab++; + cnt++; + cntTab = 2; pMatch = pItem; pExpr->iColumn = j; pEList->a[j].fg.bUsed = 1; - - /* rowid cannot be part of a USING clause - assert() this. */ - assert( bRowid==0 || pEList->a[j].fg.bUsingTerm==0 ); + hit = 1; 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; } - if( pItem->zAlias!=0 ){ - if( sqlite3StrICmp(zTab, pItem->zAlias)!=0 ){ - continue; - } - }else if( sqlite3StrICmp(zTab, pTab->zName)!=0 ){ - if( pTab->tnum!=1 ) continue; - if( !isValidSchemaTableName(zTab, pTab, zDb) ) continue; + zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName; + assert( zTabName!=0 ); + if( sqlite3StrICmp(zTabName, zTab)!=0 ){ + continue; } assert( ExprUseYTab(pExpr) ); if( IN_RENAME_OBJECT && pItem->zAlias ){ @@ -107193,37 +103395,8 @@ 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 ){ @@ -107251,9 +103424,7 @@ static int lookupName( assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT ); if( pParse->bReturning ){ if( (pNC->ncFlags & NC_UBaseReg)!=0 - && ALWAYS(zTab==0 - || sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0 - || isValidSchemaTableName(zTab, pParse->pTriggerTab, 0)) + && (zTab==0 || sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0) ){ pExpr->iTable = op!=TK_DELETE; pTab = pParse->pTriggerTab; @@ -107320,7 +103491,6 @@ 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 + sqlite3TableColumnToStorage(pTab, iCol) + 1; }else{ @@ -107350,19 +103520,14 @@ 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 && sqlite3IsRowid(zCol) - && ALWAYS(VisibleRowid(pMatch->pTab) || pMatch->fg.isNestedFrom) + && ALWAYS(VisibleRowid(pMatch->pTab)) ){ - 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; + cnt = 1; + pExpr->iColumn = -1; pExpr->affExpr = SQLITE_AFF_INTEGER; } @@ -107515,17 +103680,12 @@ static int lookupName( sqlite3ErrorMsg(pParse, "%s: %s.%s.%s", zErr, zDb, zTab, zCol); }else if( zTab ){ sqlite3ErrorMsg(pParse, "%s: %s.%s", zErr, zTab, zCol); - }else if( cnt==0 && ExprHasProperty(pRight,EP_DblQuoted) ){ - sqlite3ErrorMsg(pParse, "%s: \"%s\" - should this be a" - " string literal in single-quotes?", - zErr, zCol); }else{ sqlite3ErrorMsg(pParse, "%s: %s", zErr, zCol); } sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr); pParse->checkSchema = 1; pTopNC->nNcErr++; - eNewExprOp = TK_NULL; } assert( pFJMatch==0 ); @@ -107552,12 +103712,8 @@ static int lookupName( ** If a generated column is referenced, set bits for every column ** of the table. */ - if( pMatch ){ - if( pExpr->iColumn>=0 ){ - pMatch->colUsed |= sqlite3ExprColUsed(pExpr); - }else{ - pMatch->fg.rowidUsed = 1; - } + if( pExpr->iColumn>=0 && pMatch!=0 ){ + pMatch->colUsed |= sqlite3ExprColUsed(pExpr); } pExpr->op = eNewExprOp; @@ -107734,19 +103890,6 @@ 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: { @@ -107757,36 +103900,23 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ anRef[i] = p->nRef; } sqlite3WalkExpr(pWalker, pExpr->pLeft); - if( IN_RENAME_OBJECT ) return WRC_Prune; - if( 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. */ + if( 0==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 && ipNext, i++){ + p->nRef = anRef[i]; + } + sqlite3ExprDelete(pParse->db, pExpr->pLeft); + pExpr->pLeft = 0; } - testcase( ExprHasProperty(pExpr, EP_OuterON) ); - assert( !ExprHasProperty(pExpr, EP_IntValue) ); -#if TREETRACE_ENABLED - if( sqlite3TreeTrace & 0x80000 ){ - sqlite3DebugPrintf( - "NOT NULL strength reduction converts the following to %d:\n", - pExpr->op==TK_NOTNULL - ); - 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 && ipNext, i++){ - p->nRef = anRef[i]; - } - sqlite3ExprDelete(pParse->db, pExpr->pLeft); - pExpr->pLeft = 0; return WRC_Prune; } @@ -107800,6 +103930,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ */ case TK_ID: case TK_DOT: { + const char *zColumn; const char *zTable; const char *zDb; Expr *pRight; @@ -107808,7 +103939,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ zDb = 0; zTable = 0; assert( !ExprHasProperty(pExpr, EP_IntValue) ); - pRight = pExpr; + zColumn = pExpr->u.zToken; }else{ Expr *pLeft = pExpr->pLeft; testcase( pNC->ncFlags & NC_IdxExpr ); @@ -107827,13 +103958,14 @@ 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 ){ sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight); sqlite3RenameTokenRemap(pParse, (void*)&pExpr->y.pTab, (void*)pLeft); } } - return lookupName(pParse, zDb, zTable, pRight, pNC, pExpr); + return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr); } /* Resolve function names @@ -107852,7 +103984,6 @@ 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 = sqlite3FindFunction(pParse->db, zId, n, enc, 0); if( pDef==0 ){ @@ -107994,10 +104125,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pNC->nNcErr++; } #endif - else if( is_agg==0 && pExpr->pLeft ){ - 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 @@ -108009,18 +104136,15 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ #endif } } - else if( ExprHasProperty(pExpr, EP_WinFunc) || pExpr->pLeft ){ +#ifndef SQLITE_OMIT_WINDOWFUNC + else if( ExprHasProperty(pExpr, EP_WinFunc) ){ is_agg = 1; } +#endif sqlite3WalkExprList(pWalker, pList); if( is_agg ){ - if( pExpr->pLeft ){ - assert( pExpr->pLeft->op==TK_ORDER ); - assert( ExprUseXList(pExpr->pLeft) ); - 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) ); if( IN_RENAME_OBJECT==0 ){ @@ -108047,12 +104171,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ while( pNC2 && sqlite3ReferencesSrcList(pParse, pExpr, pNC2->pSrcList)==0 ){ - pExpr->op2 += (1 + pNC2->nNestedSelect); + pExpr->op2++; 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 ); @@ -108081,7 +104204,6 @@ 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{ @@ -108090,9 +104212,8 @@ 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_VarSelect; } - pNC->ncFlags |= NC_Subquery; } break; } @@ -108532,7 +104653,7 @@ static int resolveOrderGroupBy( } for(j=0; jpEList->nExpr; j++){ if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){ - /* Since this expression is being changed into a reference + /* Since this expresion 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); @@ -108585,8 +104706,10 @@ 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. */ @@ -108613,10 +104736,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ /* Recursively resolve names in all subqueries in the FROM clause */ - if( pOuterNC ) pOuterNC->nNestedSelect++; for(i=0; ipSrc->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; @@ -108639,9 +104760,6 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ } } } - if( pOuterNC && ALWAYS(pOuterNC->nNestedSelect>0) ){ - pOuterNC->nNestedSelect--; - } /* Set up the local name-context to pass to sqlite3ResolveExprNames() to ** resolve the result-set expression list. @@ -108685,9 +104803,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ } if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort; } - sNC.ncFlags |= NC_Where; if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort; - sNC.ncFlags &= ~NC_Where; /* Resolve names in table-valued-function arguments */ for(i=0; ipSrc->nSrc; i++){ @@ -108860,8 +104976,7 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames( return SQLITE_ERROR; } #endif - assert( pExpr!=0 ); - sqlite3WalkExprNN(&w, pExpr); + sqlite3WalkExpr(&w, pExpr); #if SQLITE_MAX_EXPR_DEPTH>0 w.pParse->nHeight -= pExpr->nHeight; #endif @@ -108878,9 +104993,6 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames( ** Resolve all names for all expression in an expression list. This is ** just like sqlite3ResolveExprNames() except that it works for an expression ** list rather than a single expression. -** -** The return value is SQLITE_OK (0) for success or SQLITE_ERROR (1) for a -** failure. */ SQLITE_PRIVATE int sqlite3ResolveExprListNames( NameContext *pNC, /* Namespace to resolve expressions in. */ @@ -108889,7 +105001,7 @@ SQLITE_PRIVATE int sqlite3ResolveExprListNames( int i; int savedHasAgg = 0; Walker w; - if( pList==0 ) return SQLITE_OK; + if( pList==0 ) return WRC_Continue; w.pParse = pNC->pParse; w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; @@ -108903,10 +105015,10 @@ SQLITE_PRIVATE int sqlite3ResolveExprListNames( #if SQLITE_MAX_EXPR_DEPTH>0 w.pParse->nHeight += pExpr->nHeight; if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){ - return SQLITE_ERROR; + return WRC_Abort; } #endif - sqlite3WalkExprNN(&w, pExpr); + sqlite3WalkExpr(&w, pExpr); #if SQLITE_MAX_EXPR_DEPTH>0 w.pParse->nHeight -= pExpr->nHeight; #endif @@ -108920,15 +105032,15 @@ SQLITE_PRIVATE int 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 SQLITE_ERROR; + if( w.pParse->nErr>0 ) return WRC_Abort; } pNC->ncFlags |= savedHasAgg; - return SQLITE_OK; + return WRC_Continue; } /* ** Resolve all names in all expressions of a SELECT and in all -** descendants of the SELECT, including compounds off of p->pPrior, +** decendents of the SELECT, including compounds off of p->pPrior, ** subqueries in expressions, and subqueries used as FROM clause ** terms. ** @@ -109055,122 +105167,48 @@ SQLITE_PRIVATE char sqlite3TableColumnAffinity(const Table *pTab, int iCol){ */ SQLITE_PRIVATE char 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; - 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 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 sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr); - } + if( op==TK_REGISTER ) op = pExpr->op2; + if( op==TK_COLUMN || op==TK_AGG_COLUMN ){ + assert( ExprUseYTab(pExpr) ); + assert( pExpr->y.pTab!=0 ); + return 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 sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr); + } #ifndef SQLITE_OMIT_CAST - if( op==TK_CAST ){ - assert( !ExprHasProperty(pExpr, EP_IntValue) ); - return sqlite3AffinityType(pExpr->u.zToken, 0); - } + if( op==TK_CAST ){ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + return 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->iColumn >= 0 ); - assert( pExpr->iTable==pExpr->pLeft->x.pSelect->pEList->nExpr ); - return sqlite3ExprAffinity( - pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr - ); - } - if( op==TK_VECTOR ){ - assert( ExprUseXList(pExpr) ); - return 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; + 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 sqlite3ExprAffinity( + pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr + ); + } + if( op==TK_VECTOR ){ + assert( ExprUseXList(pExpr) ); + return sqlite3ExprAffinity(pExpr->x.pList->a[0].pExpr); } 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 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 = 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; iinExpr; ii+=2){ - res |= sqlite3ExprDataType(pList->a[ii].pExpr); - } - if( pList->nExpr % 2 ){ - res |= 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 @@ -109229,10 +105267,9 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){ assert( pExpr->x.pList->nExpr>0 ); assert( pExpr->op==TK_FUNCTION ); pExpr = pExpr->x.pList->a[0].pExpr; - }else if( pExpr->op==TK_COLLATE ){ - pExpr = pExpr->pLeft; }else{ - break; + assert( pExpr->op==TK_COLLATE ); + pExpr = pExpr->pLeft; } } return pExpr; @@ -109259,9 +105296,7 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){ while( p ){ int op = p->op; if( op==TK_REGISTER ) op = p->op2; - if( (op==TK_AGG_COLUMN && p->y.pTab!=0) - || op==TK_COLUMN || op==TK_TRIGGER - ){ + if( op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER ){ int j; assert( ExprUseYTab(p) ); assert( p->y.pTab!=0 ); @@ -109291,10 +105326,11 @@ SQLITE_PRIVATE CollSeq *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) || p->x.pList==0 || p->pRight==0 ); - if( ExprUseXList(p) && p->x.pList!=0 && !db->mallocFailed ){ + assert( ExprUseXList(p) ); + assert( p->x.pList==0 || p->pRight==0 ); + if( p->x.pList!=0 && !db->mallocFailed ){ int i; - for(i=0; ix.pList->nExpr; i++){ + for(i=0; ALWAYS(ix.pList->nExpr); i++){ if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){ pNext = p->x.pList->a[i].pExpr; break; @@ -109316,7 +105352,7 @@ SQLITE_PRIVATE CollSeq *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 -** default collation sequence. +** defautl collation sequence. ** ** See also: sqlite3ExprCollSeq() ** @@ -109446,7 +105482,7 @@ SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq( return pColl; } -/* Expression p is a comparison operator. Return a collation sequence +/* Expresssion p is a comparison operator. Return a collation sequence ** appropriate for the comparison operator. ** ** This is normally just a wrapper around sqlite3BinaryCompareCollSeq(). @@ -109603,7 +105639,6 @@ SQLITE_PRIVATE Expr *sqlite3ExprForVectorField( */ pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0); if( pRet ){ - ExprSetProperty(pRet, EP_FullSize); pRet->iTable = nField; pRet->iColumn = iField; pRet->pLeft = pVector; @@ -109903,15 +105938,6 @@ SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){ #define exprSetHeight(y) #endif /* SQLITE_MAX_EXPR_DEPTH>0 */ -/* -** Set the error offset for an Expr node, if possible. -*/ -SQLITE_PRIVATE void 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. ** @@ -109926,12 +105952,11 @@ SQLITE_PRIVATE void sqlite3ExprSetErrorOffset(Expr *pExpr, int iOfst){ ** 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 (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 +** 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 ** is allocated to hold the integer text and the dequote flag is ignored. -** See also tag-20240227-b. */ SQLITE_PRIVATE Expr *sqlite3ExprAlloc( sqlite3 *db, /* Handle for sqlite3DbMallocRawNN() */ @@ -109947,7 +105972,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc( if( pToken ){ if( op!=TK_INTEGER || pToken->z==0 || sqlite3GetInt32(pToken->z, &iValue)==0 ){ - nExtra = pToken->n+1; /* tag-20240227-a */ + nExtra = pToken->n+1; assert( iValue>=0 ); } } @@ -110137,9 +106162,9 @@ SQLITE_PRIVATE Select *sqlite3ExprListToValues(Parse *pParse, int nElem, ExprLis ** 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, 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. +** If one side or the other of the AND is known to be false, then instead +** of returning an AND expression, just return a constant expression with +** a value of false. */ SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){ sqlite3 *db = pParse->db; @@ -110147,17 +106172,14 @@ SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){ return pRight; }else if( pRight==0 ){ return pLeft; + }else if( (ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight)) + && !IN_RENAME_OBJECT + ){ + sqlite3ExprDeferredDelete(pParse, pLeft); + sqlite3ExprDeferredDelete(pParse, pRight); + return sqlite3Expr(db, TK_INTEGER, "0"); }else{ - u32 f = pLeft->flags | pRight->flags; - if( (f&(EP_OuterON|EP_InnerON|EP_IsFalse))==EP_IsFalse - && !IN_RENAME_OBJECT - ){ - sqlite3ExprDeferredDelete(pParse, pLeft); - sqlite3ExprDeferredDelete(pParse, pRight); - return sqlite3Expr(db, TK_INTEGER, "0"); - }else{ - return sqlite3PExpr(pParse, TK_AND, pLeft, pRight); - } + return sqlite3PExpr(pParse, TK_AND, pLeft, pRight); } } @@ -110195,67 +106217,6 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction( return pNew; } -/* -** Report an error when attempting to use an ORDER BY clause within -** the arguments of a non-aggregate function. -*/ -SQLITE_PRIVATE void sqlite3ExprOrderByAggregateError(Parse *pParse, Expr *p){ - 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 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; - sqlite3 *db = pParse->db; - if( NEVER(pOrderBy==0) ){ - assert( db->mallocFailed ); - return; - } - if( pExpr==0 ){ - assert( db->mallocFailed ); - 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 */ - sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pOrderBy); - return; - } - if( IsWindowFunc(pExpr) ){ - sqlite3ExprOrderByAggregateError(pParse, pExpr); - sqlite3ExprListDelete(db, pOrderBy); - return; - } - - pOB = sqlite3ExprAlloc(db, TK_ORDER, 0, 0); - if( pOB==0 ){ - 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: @@ -110379,7 +106340,6 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n static SQLITE_NOINLINE void sqlite3ExprDeleteNN(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 ); @@ -110395,6 +106355,7 @@ exprDeleteRestart: 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 ) sqlite3ExprDeleteNN(db, p->pLeft); if( p->pRight ){ assert( !ExprHasProperty(p, EP_WinFunc) ); sqlite3ExprDeleteNN(db, p->pRight); @@ -110409,19 +106370,6 @@ exprDeleteRestart: } #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 */ - sqlite3DbNNFreeNN(db, p); - p = pLeft; - goto exprDeleteRestart; - }else{ - sqlite3ExprDeleteNN(db, pLeft); - } - } } if( !ExprHasProperty(p, EP_Static) ){ sqlite3DbNNFreeNN(db, p); @@ -110430,9 +106378,6 @@ exprDeleteRestart: SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){ if( p ) sqlite3ExprDeleteNN(db, p); } -SQLITE_PRIVATE void sqlite3ExprDeleteGeneric(sqlite3 *db, void *p){ - if( ALWAYS(p) ) sqlite3ExprDeleteNN(db, (Expr*)p); -} /* ** Clear both elements of an OnOrUsing object @@ -110450,15 +106395,17 @@ SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3 *db, OnOrUsing *p){ /* ** Arrange to cause pExpr to be deleted when the pParse is deleted. ** This is similar to sqlite3ExprDelete() except that the delete is -** deferred until the pParse is deleted. +** deferred untilthe pParse is deleted. ** ** The pExpr might be deleted immediately on an OOM error. ** -** Return 0 if the delete was successfully deferred. Return non-zero -** if the delete happened immediately because of an OOM. +** The deferred delete is (currently) implemented by adding the +** pExpr to the pParse->pConstExpr list with a register number of 0. */ -SQLITE_PRIVATE int sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){ - return 0==sqlite3ParserAddCleanup(pParse, sqlite3ExprDeleteGeneric, pExpr); +SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){ + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3ExprDelete, + pExpr); } /* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the @@ -110523,7 +106470,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 || ExprHasProperty(p, EP_FullSize) ){ + if( 0==flags || p->op==TK_SELECT_COLUMN +#ifndef SQLITE_OMIT_WINDOWFUNC + || ExprHasProperty(p, EP_WinFunc) +#endif + ){ nSize = EXPR_FULLSIZE; }else{ assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); @@ -110554,93 +106505,56 @@ 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. +** expression passed as the first argument. The second argument is a +** mask containing EXPRDUP_XXX flags. ** ** 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. ** -** 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. +** 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). */ -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) ); +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); + } + } return nByte; } /* -** 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 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. -*/ -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 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. +** This function is similar to 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. */ -static Expr *exprDup( - 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 */ -){ +static Expr *exprDup(sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){ Expr *pNew; /* Value to return */ - EdupBuf sEdupBuf; /* Memory space from which to build Expr object */ + u8 *zAlloc; /* 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( pEdupBuf==0 || dupFlags==EXPRDUP_REDUCE ); + assert( pzBuffer==0 || dupFlags==EXPRDUP_REDUCE ); /* Figure out where to write the new Expr structure. */ - if( pEdupBuf ){ - sEdupBuf.zAlloc = pEdupBuf->zAlloc; -#ifdef SQLITE_DEBUG - sEdupBuf.zEnd = pEdupBuf->zEnd; -#endif + if( pzBuffer ){ + zAlloc = *pzBuffer; staticFlag = EP_Static; - assert( sEdupBuf.zAlloc!=0 ); - assert( dupFlags==EXPRDUP_REDUCE ); + assert( zAlloc!=0 ); }else{ - int nAlloc; - if( dupFlags ){ - nAlloc = dupedExprSize(p); - }else if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){ - nToken = sqlite3Strlen30NN(p->u.zToken)+1; - nAlloc = ROUND8(EXPR_FULLSIZE + nToken); - }else{ - nToken = 0; - nAlloc = ROUND8(EXPR_FULLSIZE); - } - assert( nAlloc==ROUND8(nAlloc) ); - sEdupBuf.zAlloc = sqlite3DbMallocRawNN(db, nAlloc); -#ifdef SQLITE_DEBUG - sEdupBuf.zEnd = sEdupBuf.zAlloc ? sEdupBuf.zAlloc+nAlloc : 0; -#endif - + zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, dupFlags)); staticFlag = 0; } - pNew = (Expr *)sEdupBuf.zAlloc; - assert( EIGHT_BYTE_ALIGNMENT(pNew) ); + pNew = (Expr *)zAlloc; if( pNew ){ /* Set nNewSize to the size allocated for the structure pointed to @@ -110649,27 +106563,22 @@ static Expr *exprDup( ** by the copy of the p->u.zToken string (if any). */ const unsigned nStructSize = dupedExprStructSize(p, dupFlags); - int nNewSize = nStructSize & 0xfff; - if( nToken<0 ){ - if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){ - nToken = sqlite3Strlen30(p->u.zToken) + 1; - }else{ - nToken = 0; - } + const int nNewSize = nStructSize & 0xfff; + int nToken; + if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){ + nToken = sqlite3Strlen30(p->u.zToken) + 1; + }else{ + nToken = 0; } if( dupFlags ){ - assert( (int)(sEdupBuf.zEnd - sEdupBuf.zAlloc) >= nNewSize+nToken ); assert( ExprHasProperty(p, EP_Reduced)==0 ); - memcpy(sEdupBuf.zAlloc, p, nNewSize); + memcpy(zAlloc, p, nNewSize); }else{ u32 nSize = (u32)exprStructSize(p); - assert( (int)(sEdupBuf.zEnd - sEdupBuf.zAlloc) >= - (int)EXPR_FULLSIZE+nToken ); - memcpy(sEdupBuf.zAlloc, p, nSize); + memcpy(zAlloc, p, nSize); if( nSizeu.zToken string, if any. */ - assert( nToken>=0 ); - if( nToken>0 ){ - char *zToken = pNew->u.zToken = (char*)&sEdupBuf.zAlloc[nNewSize]; + if( nToken ){ + char *zToken = pNew->u.zToken = (char*)&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 = sqlite3SelectDup(db, p->x.pSelect, dupFlags); }else{ - pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, - p->op!=TK_ORDER ? dupFlags : 0); + pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags); } + } + /* 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 = sqlite3WindowDup(db, pNew, p->y.pWin); assert( ExprHasProperty(pNew, EP_WinFunc) ); } #endif /* SQLITE_OMIT_WINDOWFUNC */ - - /* 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 ){ + if( pzBuffer ){ + *pzBuffer = zAlloc; + } + }else{ + if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ + if( pNew->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 = sqlite3ExprDup(db, p->pLeft, 0); } @@ -110733,8 +106636,6 @@ static Expr *exprDup( } } } - if( pEdupBuf ) memcpy(pEdupBuf, &sEdupBuf, sizeof(sEdupBuf)); - assert( sEdupBuf.zAlloc <= sEdupBuf.zEnd ); return pNew; } @@ -110894,19 +106795,17 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int fla pNewItem->iCursor = pOldItem->iCursor; pNewItem->addrFillSub = pOldItem->addrFillSub; pNewItem->regReturn = pOldItem->regReturn; - pNewItem->regResult = pOldItem->regResult; if( pNewItem->fg.isIndexedBy ){ pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy); - }else if( pNewItem->fg.isTabFunc ){ - pNewItem->u1.pFuncArg = - 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 = + sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags); + } pTab = pNewItem->pTab = pOldItem->pTab; if( pTab ){ pTab->nTabRef++; @@ -111001,7 +106900,11 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *p, int flags) ** 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 sqlite3ExprListAppend(). +** obtained from a prior call to sqlite3ExprListAppend(). This routine +** may not be used with an ExprList obtained from sqlite3ExprListDup(). +** Reason: This routine assumes that the number of slots in pList->a[] +** is a power of two. That is true for sqlite3ExprListAppend() returns +** but is not necessarily true from the return value of sqlite3ExprListDup(). ** ** If a memory allocation error occurs, the entire list is freed and ** NULL is returned. If non-NULL is returned, then it is guaranteed @@ -111266,9 +107169,6 @@ static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){ SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){ if( pList ) exprListDeleteNN(db, pList); } -SQLITE_PRIVATE void sqlite3ExprListDeleteGeneric(sqlite3 *db, void *pList){ - if( ALWAYS(pList) ) exprListDeleteNN(db, (ExprList*)pList); -} /* ** Return the bitwise-OR of all Expr.flags fields in the given @@ -111337,7 +107237,7 @@ SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr *pExpr){ ** and 0 if it is FALSE. */ SQLITE_PRIVATE int sqlite3ExprTruthValue(const Expr *pExpr){ - pExpr = sqlite3ExprSkipCollateAndLikely((Expr*)pExpr); + pExpr = sqlite3ExprSkipCollate((Expr*)pExpr); assert( pExpr->op==TK_TRUEFALSE ); assert( !ExprHasProperty(pExpr, EP_IntValue) ); assert( sqlite3StrICmp(pExpr->u.zToken,"true")==0 @@ -111372,54 +107272,6 @@ SQLITE_PRIVATE Expr *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 */ - 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; - sqlite3WalkExprList(pWalker, pList); - if( pWalker->eCode==0 ) return WRC_Abort; - } - db = pWalker->pParse->db; - pDef = 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 @@ -111448,7 +107300,6 @@ static SQLITE_NOINLINE int exprNodeIsConstantFunction( ** 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 @@ -111468,8 +107319,6 @@ 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; @@ -111498,11 +107347,9 @@ 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: @@ -111524,15 +107371,15 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ return WRC_Continue; } } -static int exprIsConst(Parse *pParse, Expr *p, int initFlag){ +static int exprIsConst(Expr *p, int initFlag, int iCur){ Walker w; w.eCode = initFlag; - w.pParse = pParse; w.xExprCallback = exprNodeIsConstant; w.xSelectCallback = sqlite3SelectWalkFail; #ifdef SQLITE_DEBUG w.xSelectCallback2 = sqlite3SelectWalkAssert2; #endif + w.u.iCur = iCur; sqlite3WalkExpr(&w, p); return w.eCode; } @@ -111544,15 +107391,9 @@ static int exprIsConst(Parse *pParse, Expr *p, int initFlag){ ** 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 sqlite3ExprIsConstant(Parse *pParse, Expr *p){ - return exprIsConst(pParse, p, 1); +SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr *p){ + return exprIsConst(p, 1, 0); } /* @@ -111568,24 +107409,8 @@ SQLITE_PRIVATE int sqlite3ExprIsConstant(Parse *pParse, Expr *p){ ** can be added to the pParse->pConstExpr list and evaluated once when ** the prepared statement starts up. See sqlite3ExprCodeRunJustOnce(). */ -static int 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 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; +SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){ + return exprIsConst(p, 2, 0); } /* @@ -111593,79 +107418,35 @@ static int exprSelectWalkTableConstant(Walker *pWalker, Select *pSelect){ ** 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. */ -static int 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 = sqlite3SelectWalkFail; -#ifdef SQLITE_DEBUG - w.xSelectCallback2 = sqlite3SelectWalkAssert2; -#endif - } - w.u.iCur = iCur; - sqlite3WalkExpr(&w, p); - return w.eCode; +SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){ + return exprIsConst(p, 3, iCur); } /* -** 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. -** +** Check pExpr to see if it is an invariant constraint on data source pSrc. ** 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 single-source constraint, the following must be true: +** To be an invariant constraint, the following must be true: ** ** (1) pExpr cannot refer to any table other than pSrc->iCursor. ** -** (2a) pExpr cannot use subqueries unless the bAllowSubq parameter is -** true and the subquery is non-correlated -** -** (2b) pExpr cannot use non-deterministic functions. +** (2) pExpr cannot use subqueries or 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 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]; +SQLITE_PRIVATE int sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *pSrc){ if( pSrc->fg.jointype & JT_LTORJ ){ return 0; /* rule (3) */ } @@ -111675,21 +107456,7 @@ SQLITE_PRIVATE int sqlite3ExprIsSingleTableConstraint( }else{ if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* rule (5) */ } - 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; jjw.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 sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor, bAllowSubq); + return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor); /* rules (1), (2) */ } @@ -111774,7 +107541,7 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprLi */ SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){ assert( isInit==0 || isInit==1 ); - return exprIsConst(0, p, 4+isInit); + return exprIsConst(p, 4+isInit, 0); } #ifdef SQLITE_ENABLE_CURSOR_HINTS @@ -111864,14 +107631,10 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){ return 0; case TK_COLUMN: assert( ExprUseYTab(p) ); - 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 + return ExprHasProperty(p, EP_CanBeNull) || + p->y.pTab==0 || /* Reference to column of index on expression */ + (p->iColumn>=0 && p->y.pTab->aCol!=0 /* Possible due to prior error */ - && ALWAYS(p->iColumny.pTab->nCol) && p->y.pTab->aCol[p->iColumn].notNull==0); default: return 1; @@ -111931,32 +107694,11 @@ SQLITE_PRIVATE int sqlite3IsRowid(const char *z){ return 0; } -/* -** 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 *sqlite3RowidAlias(Table *pTab){ - const char *azOpt[] = {"_ROWID_", "ROWID", "OID"}; - int ii; - assert( VisibleRowid(pTab) ); - for(ii=0; iinCol; iCol++){ - if( 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 materialized into a transient +** or if the SELECT statement needs to be manifested into a transient ** table, then return NULL. */ #ifndef SQLITE_OMIT_SUBQUERY @@ -112022,13 +107764,13 @@ static void 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 sqlite3InRhsIsConstant(Parse *pParse, Expr *pIn){ +static int sqlite3InRhsIsConstant(Expr *pIn){ Expr *pLHS; int res; assert( !ExprHasProperty(pIn, EP_xIsSelect) ); pLHS = pIn->pLeft; pIn->pLeft = 0; - res = sqlite3ExprIsConstant(pParse, pIn); + res = sqlite3ExprIsConstant(pIn); pIn->pLeft = pLHS; return res; } @@ -112052,7 +107794,7 @@ static int sqlite3InRhsIsConstant(Parse *pParse, 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 ephemeral table. +** populated epheremal table. ** IN_INDEX_NOOP - No cursor was allocated. The IN operator must be ** implemented as a sequence of comparisons. ** @@ -112065,7 +107807,7 @@ static int sqlite3InRhsIsConstant(Parse *pParse, 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 -** ephemeral table might be put inside of a subroutine, the EP_Subrtn flag +** ephmeral 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. ** @@ -112077,12 +107819,12 @@ static int sqlite3InRhsIsConstant(Parse *pParse, 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 ephemeral table will be created unless the selected columns are guaranteed +** An epheremal 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 ephemeral table must +** for fast set membership tests) then an epheremal table must ** be used unless is a single INTEGER PRIMARY KEY column or an ** index can be found with the specified as its left-most. ** @@ -112242,6 +107984,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex( CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); int j; + assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr ); for(j=0; jaiColumn[j]!=pRhs->iColumn ) continue; assert( pIdx->azColl[j] ); @@ -112297,7 +108040,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex( if( eType==0 && (inFlags & IN_INDEX_NOOP_OK) && ExprUseXList(pX) - && (!sqlite3InRhsIsConstant(pParse,pX) || pX->x.pList->nExpr<=2) + && (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2) ){ pParse->nTab--; /* Back out the allocation of the unused cursor */ iTab = -1; /* Cursor is not allocated */ @@ -112415,7 +108158,7 @@ SQLITE_PRIVATE void 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 ephemeral table is returned. The first time the ephemeral +** constructed ephermeral 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. @@ -112580,7 +108323,7 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( ** this code only executes once. Because for a non-constant ** expression we need to rerun this code each time. */ - if( addrOnce && !sqlite3ExprIsConstant(pParse, pE2) ){ + if( addrOnce && !sqlite3ExprIsConstant(pE2) ){ sqlite3VdbeChangeToNoop(v, addrOnce-1); sqlite3VdbeChangeToNoop(v, addrOnce); ExprClearProperty(pExpr, EP_Subrtn); @@ -112635,9 +108378,6 @@ SQLITE_PRIVATE int 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 ); @@ -112690,9 +108430,8 @@ SQLITE_PRIVATE int 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. */ - ExplainQueryPlan2(addrExplain, (pParse, 1, "%sSCALAR SUBQUERY %d", + ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY %d", addrOnce?"":"CORRELATED ", pSel->selId)); - sqlite3VdbeScanStatusCounters(v, addrExplain, addrExplain, -1); nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1; sqlite3SelectDestInit(&dest, 0, pParse->nMem+1); pParse->nMem += nReg; @@ -112735,7 +108474,6 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ if( addrOnce ){ sqlite3VdbeJumpHere(v, addrOnce); } - sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1); /* Subroutine return */ assert( ExprUseYSub(pExpr) ); @@ -113144,7 +108882,6 @@ SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn( ){ int iAddr; Vdbe *v = pParse->pVdbe; - int nErr = pParse->nErr; assert( v!=0 ); assert( pParse->iSelfTab!=0 ); if( pParse->iSelfTab>0 ){ @@ -113157,7 +108894,6 @@ SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn( sqlite3VdbeAddOp4(v, OP_Affinity, regOut, 1, 0, &pCol->affinity, 1); } if( iAddr ) sqlite3VdbeJumpHere(v, iAddr); - if( pParse->nErr>nErr ) pParse->db->errByteOffset = -1; } #endif /* SQLITE_OMIT_GENERATED_COLUMNS */ @@ -113174,7 +108910,6 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable( Column *pCol; assert( v!=0 ); assert( pTab!=0 ); - assert( iCol!=XN_EXPR ); if( iCol<0 || iCol==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut); VdbeComment((v, "%s.rowid", pTab->zName)); @@ -113230,13 +108965,10 @@ SQLITE_PRIVATE int 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 ); sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pTab, iTable, iColumn, iReg); if( p5 ){ VdbeOp *pOp = sqlite3VdbeGetLastOp(pParse->pVdbe); if( pOp->opcode==OP_Column ) pOp->p5 = p5; - if( pOp->opcode==OP_VColumn ) pOp->p5 = (p5 & OPFLAG_NOCHNG); } return iReg; } @@ -113265,7 +108997,7 @@ static void exprToRegister(Expr *pExpr, int iReg){ /* ** Evaluate an expression (either a vector or a scalar expression) and store -** the result in contiguous temporary registers. Return the index of +** the result in continguous 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 @@ -113305,7 +109037,7 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){ */ static void setDoNotMergeFlagOnCopy(Vdbe *v){ if( sqlite3VdbeGetLastOp(v)->opcode==OP_Copy ){ - sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergeable */ + sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergable */ } } @@ -113395,13 +109127,13 @@ static int exprCodeInlineFunction( } case INLINEFUNC_implies_nonnull_row: { - /* Result of sqlite3ExprImpliesNonNullRow() */ + /* REsult of sqlite3ExprImpliesNonNullRow() */ Expr *pA1; assert( nFarg==2 ); pA1 = pFarg->a[1].pExpr; if( pA1->op==TK_COLUMN ){ sqlite3VdbeAddOp2(v, OP_Integer, - sqlite3ExprImpliesNonNullRow(pFarg->a[0].pExpr,pA1->iTable,1), + sqlite3ExprImpliesNonNullRow(pFarg->a[0].pExpr,pA1->iTable), target); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); @@ -113414,13 +109146,10 @@ 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", "flexnum" }; + const char *azAff[] = { "blob", "text", "numeric", "integer", "real" }; char aff; assert( nFarg==1 ); aff = sqlite3ExprAffinity(pFarg->a[0].pExpr); - assert( aff<=SQLITE_AFF_NONE - || (aff>=SQLITE_AFF_BLOB && aff<=SQLITE_AFF_FLEXNUM) ); sqlite3VdbeLoadString(v, target, (aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]); break; @@ -113431,7 +109160,7 @@ static int exprCodeInlineFunction( } /* -** Check to see if pExpr is one of the indexed expressions on pParse->pIdxEpr. +** Check to see if pExpr is one of the indexed expressions on pParse->pIdxExpr. ** 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. @@ -113443,8 +109172,7 @@ static SQLITE_NOINLINE int sqlite3IndexedExprLookup( ){ IndexedExpr *p; Vdbe *v; - for(p=pParse->pIdxEpr; p; p=p->pIENext){ - u8 exprAff; + for(p=pParse->pIdxExpr; p; p=p->pIENext){ int iDataCur = p->iDataCur; if( iDataCur<0 ) continue; if( pParse->iSelfTab ){ @@ -113452,16 +109180,6 @@ static SQLITE_NOINLINE int sqlite3IndexedExprLookup( iDataCur = -1; } if( sqlite3ExprCompare(0, pExpr, p->pExpr, iDataCur)!=0 ) continue; - assert( p->aff>=SQLITE_AFF_BLOB && p->aff<=SQLITE_AFF_NUMERIC ); - exprAff = 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 ){ @@ -113474,10 +109192,10 @@ static SQLITE_NOINLINE int sqlite3IndexedExprLookup( sqlite3VdbeAddOp3(v, OP_Column, p->iIdxCur, p->iIdxCol, target); VdbeComment((v, "%s expr-column %d", p->zIdxName, p->iIdxCol)); sqlite3VdbeGoto(v, 0); - p = pParse->pIdxEpr; - pParse->pIdxEpr = 0; + p = pParse->pIdxExpr; + pParse->pIdxExpr = 0; sqlite3ExprCode(pParse, pExpr, target); - pParse->pIdxEpr = p; + pParse->pIdxExpr = p; sqlite3VdbeJumpHere(v, addr+2); }else{ sqlite3VdbeAddOp3(v, OP_Column, p->iIdxCur, p->iIdxCol, target); @@ -113489,41 +109207,6 @@ static SQLITE_NOINLINE int 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 = sqlite3VdbeAddOp1(v, OP_IfNullRow, p->iIdxCur); - } - ret = sqlite3ExprCodeTarget(pParse, p->pExpr, iTarget); - sqlite3VdbeAddOp4(pParse->pVdbe, OP_Affinity, ret, 1, 0, - (const char*)&p->aff, 1); - if( addr ){ - sqlite3VdbeJumpHere(v, addr); - 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". @@ -113551,7 +109234,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) expr_code_doover: if( pExpr==0 ){ op = TK_NULL; - }else if( pParse->pIdxEpr!=0 + }else if( pParse->pIdxExpr!=0 && !ExprHasProperty(pExpr, EP_Leaf) && (r1 = sqlite3IndexedExprLookup(pParse, pExpr, target))>=0 ){ @@ -113560,37 +109243,23 @@ 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 ); - if( pExpr->iAgg>=pAggInfo->nColumn ){ - /* Happens when the left table of a RIGHT JOIN is null and - ** is using an expression index */ - sqlite3VdbeAddOp2(v, OP_Null, 0, target); -#ifdef SQLITE_VDBE_COVERAGE - /* Verify that the OP_Null above is exercised by tests - ** tag-20230325-2 */ - sqlite3VdbeAddOp3(v, OP_NotNull, target, 1, 20230325); - VdbeCoverageNeverTaken(v); -#endif - break; - } + assert( pExpr->iAgg>=0 && pExpr->iAggnColumn ); pCol = &pAggInfo->aCol[pExpr->iAgg]; if( !pAggInfo->directMode ){ - return AggInfoColumnReg(pAggInfo, pExpr->iAgg); + assert( pCol->iMem>0 ); + return pCol->iMem; }else if( pAggInfo->useSortingIdx ){ Table *pTab = pCol->pTab; sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab, pCol->iSorterColumn, target); - if( pTab==0 ){ - /* No comment added */ - }else if( pCol->iColumn<0 ){ + if( pCol->iColumn<0 ){ VdbeComment((v,"%s.rowid",pTab->zName)); - }else{ + }else if( ALWAYS(pTab!=0) ){ VdbeComment((v,"%s.%s", pTab->zName, pTab->aCol[pCol->iColumn].zCnName)); if( pTab->aCol[pCol->iColumn].affinity==SQLITE_AFF_REAL ){ @@ -113598,11 +109267,6 @@ 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() */ - sqlite3VdbeAddOp3(v, OP_Column, pExpr->iTable, pExpr->iColumn, target); - return target; } /* Otherwise, fall thru into the TK_COLUMN case */ /* no break */ deliberate_fall_through @@ -113613,7 +109277,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 - ** expression. However, make sure the constant has the correct + ** expresssion. However, make sure the constant has the correct ** datatype by applying the Affinity of the table column to the ** constant. */ @@ -113623,7 +109287,7 @@ expr_code_doover: assert( pExpr->y.pTab!=0 ); aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); if( aff>SQLITE_AFF_BLOB ){ - static const char zAff[] = "B\000C\000D\000E\000F"; + static const char zAff[] = "B\000C\000D\000E"; assert( SQLITE_AFF_BLOB=='A' ); assert( SQLITE_AFF_TEXT=='B' ); sqlite3VdbeAddOp4(v, OP_Affinity, iReg, 1, 0, @@ -113682,11 +109346,6 @@ 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 = sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab, @@ -113744,6 +109403,12 @@ expr_code_doover: assert( pExpr->u.zToken!=0 ); assert( pExpr->u.zToken[0]!=0 ); sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target); + if( pExpr->u.zToken[1]!=0 ){ + const char *z = 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 */ + sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC); + } return target; } case TK_REGISTER: { @@ -113752,8 +109417,11 @@ expr_code_doover: #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ - sqlite3ExprCode(pParse, pExpr->pLeft, target); - assert( inReg==target ); + inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); + if( inReg!=target ){ + sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target); + inReg = target; + } assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3VdbeAddOp2(v, OP_Cast, target, sqlite3AffinityType(pExpr->u.zToken, 0)); @@ -113896,7 +109564,7 @@ expr_code_doover: assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3ErrorMsg(pParse, "misuse of aggregate: %#T()", pExpr); }else{ - return AggInfoFuncReg(pInfo, pExpr->iAgg); + return pInfo->aFunc[pExpr->iAgg].iMem; } break; } @@ -113917,9 +109585,7 @@ expr_code_doover: } #endif - if( ConstFactorOk(pParse) - && sqlite3ExprIsConstantNotJoin(pParse,pExpr) - ){ + if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){ /* SQL functions can be expensive. So try to avoid running them ** multiple times if we know they always give the same result */ return sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1); @@ -113940,7 +109606,7 @@ expr_code_doover: sqlite3ErrorMsg(pParse, "unknown function: %#T()", pExpr); break; } - if( (pDef->funcFlags & SQLITE_FUNC_INLINE)!=0 && ALWAYS(pFarg!=0) ){ + if( pDef->funcFlags & SQLITE_FUNC_INLINE ){ assert( (pDef->funcFlags & SQLITE_FUNC_UNSAFE)==0 ); assert( (pDef->funcFlags & SQLITE_FUNC_DIRECT)==0 ); return exprCodeInlineFunction(pParse, pFarg, @@ -113950,7 +109616,7 @@ expr_code_doover: } for(i=0; ia[i].pExpr) ){ + if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){ testcase( i==31 ); constMask |= MASKBIT32(i); } @@ -113966,10 +109632,10 @@ expr_code_doover: r1 = sqlite3GetTempRange(pParse, nFarg); } - /* For length() and typeof() and octet_length() functions, + /* For length() and typeof() functions with a column argument, ** set the P5 parameter to the OP_Column opcode to OPFLAG_LENGTHARG - ** or OPFLAG_TYPEOFARG or OPFLAG_BYTELENARG respectively, to avoid - ** unnecessary data loading. + ** or OPFLAG_TYPEOFARG respectively, to avoid unnecessary data + ** loading. */ if( (pDef->funcFlags & (SQLITE_FUNC_LENGTH|SQLITE_FUNC_TYPEOF))!=0 ){ u8 exprOp; @@ -113979,16 +109645,14 @@ expr_code_doover: if( exprOp==TK_COLUMN || exprOp==TK_AGG_COLUMN ){ assert( SQLITE_FUNC_LENGTH==OPFLAG_LENGTHARG ); assert( SQLITE_FUNC_TYPEOF==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; + testcase( pDef->funcFlags & OPFLAG_LENGTHARG ); + pFarg->a[0].pExpr->op2 = + pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG); } } - sqlite3ExprCodeExprList(pParse, pFarg, r1, 0, SQLITE_ECEL_FACTOR); + sqlite3ExprCodeExprList(pParse, pFarg, r1, 0, + SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR); }else{ r1 = 0; } @@ -114089,17 +109753,17 @@ expr_code_doover: return target; } case TK_COLLATE: { - 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 ); - sqlite3ExprCode(pParse, pExpr->pLeft, target); - sqlite3VdbeAddOp1(v, OP_ClrSubtype, target); - return target; + if( !ExprHasProperty(pExpr, EP_Collate) + && ALWAYS(pExpr->pLeft) + && pExpr->pLeft->op==TK_FUNCTION + ){ + inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); + if( inReg!=target ){ + sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target); + inReg = target; + } + sqlite3VdbeAddOp1(v, OP_ClrSubtype, inReg); + return inReg; }else{ pExpr = pExpr->pLeft; goto expr_code_doover; /* 2018-04-28: Prevent deep recursion. */ @@ -114189,7 +109853,7 @@ expr_code_doover: if( pAggInfo ){ assert( pExpr->iAgg>=0 && pExpr->iAggnColumn ); if( !pAggInfo->directMode ){ - inReg = AggInfoColumnReg(pAggInfo, pExpr->iAgg); + inReg = pAggInfo->aCol[pExpr->iAgg].iMem; break; } if( pExpr->pAggInfo->useSortingIdx ){ @@ -114200,19 +109864,16 @@ expr_code_doover: break; } } - addrINR = 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 */ - sqlite3ExprCode(pParse, pExpr->pLeft, target); - assert( target==inReg ); + addrINR = 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 = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); pParse->okConstFactor = okConstFactor; sqlite3VdbeJumpHere(v, addrINR); + sqlite3VdbeChangeP3(v, addrINR, inReg); break; } @@ -114344,9 +110005,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 wherever it wants. The register where the expression +** store the value whereever 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 @@ -114359,7 +110020,6 @@ SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce( ){ ExprList *p; assert( ConstFactorOk(pParse) ); - assert( regDest!=0 ); p = pParse->pConstExpr; if( regDest<0 && p ){ struct ExprList_item *pItem; @@ -114418,7 +110078,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){ if( ConstFactorOk(pParse) && ALWAYS(pExpr!=0) && pExpr->op!=TK_REGISTER - && sqlite3ExprIsConstantNotJoin(pParse, pExpr) + && sqlite3ExprIsConstantNotJoin(pExpr) ){ *pReg = 0; r2 = sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1); @@ -114450,11 +110110,7 @@ SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ inReg = sqlite3ExprCodeTarget(pParse, pExpr, target); if( inReg!=target ){ u8 op; - Expr *pX = sqlite3ExprSkipCollateAndLikely(pExpr); - testcase( pX!=pExpr ); - if( ALWAYS(pX) - && (ExprHasProperty(pX,EP_Subquery) || pX->op==TK_REGISTER) - ){ + if( ALWAYS(pExpr) && ExprHasProperty(pExpr,EP_Subquery) ){ op = OP_Copy; }else{ op = OP_SCopy; @@ -114482,7 +110138,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse *pParse, Expr *pExpr, int target){ ** might choose to code the expression at initialization time. */ SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){ - if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pParse,pExpr) ){ + if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pExpr) ){ sqlite3ExprCodeRunJustOnce(pParse, pExpr, target); }else{ sqlite3ExprCodeCopy(pParse, pExpr, target); @@ -114541,7 +110197,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList( sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i); } }else if( (flags & SQLITE_ECEL_FACTOR)!=0 - && sqlite3ExprIsConstantNotJoin(pParse,pExpr) + && sqlite3ExprIsConstantNotJoin(pExpr) ){ sqlite3ExprCodeRunJustOnce(pParse, pExpr, target+i); }else{ @@ -115173,8 +110829,8 @@ SQLITE_PRIVATE int sqlite3ExprListCompare(const ExprList *pA, const ExprList *pB */ SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA,Expr *pB, int iTab){ return sqlite3ExprCompare(0, - sqlite3ExprSkipCollate(pA), - sqlite3ExprSkipCollate(pB), + sqlite3ExprSkipCollateAndLikely(pA), + sqlite3ExprSkipCollateAndLikely(pB), iTab); } @@ -115267,7 +110923,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 Result: false +** pE1: x IS ?2 pE2: x IS NOT NULL Reuslt: false ** ** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has ** Expr.iTable<0 then assume a table number given by iTab. @@ -115304,29 +110960,11 @@ SQLITE_PRIVATE int 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 ){ - sqlite3WalkExpr(pWalker, pE1); - if( pWalker->eCode ){ - pWalker->eCode = 0; - sqlite3WalkExpr(pWalker, pE2); - } - } -} - /* ** This is the Expr node callback for 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. @@ -115335,33 +110973,28 @@ 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; @@ -115369,38 +111002,21 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){ } return WRC_Prune; - case TK_OR: case TK_AND: - /* 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) ){ + if( pWalker->eCode==0 ){ sqlite3WalkExpr(pWalker, pExpr->pLeft); + if( pWalker->eCode ){ + pWalker->eCode = 0; + sqlite3WalkExpr(pWalker, pExpr->pRight); + } } return WRC_Prune; case TK_BETWEEN: - /* 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 ); - sqlite3WalkExpr(pWalker, pExpr->pLeft); - bothImplyNotNullRow(pWalker, pExpr->x.pList->a[0].pExpr, - pExpr->x.pList->a[1].pExpr); + if( sqlite3WalkExpr(pWalker, pExpr->pLeft)==WRC_Abort ){ + assert( pWalker->eCode ); + return WRC_Abort; + } return WRC_Prune; /* Virtual tables are allowed to use constraints like x=NULL. So @@ -115462,7 +111078,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 sqlite3ExprImpliesNonNullRow(Expr *p, int iTab, int isRJ){ +SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){ Walker w; p = sqlite3ExprSkipCollateAndLikely(p); if( p==0 ) return 0; @@ -115470,7 +111086,7 @@ SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab, int isRJ){ p = p->pLeft; }else{ while( p->op==TK_AND ){ - if( sqlite3ExprImpliesNonNullRow(p->pLeft, iTab, isRJ) ) return 1; + if( sqlite3ExprImpliesNonNullRow(p->pLeft, iTab) ) return 1; p = p->pRight; } } @@ -115478,7 +111094,6 @@ SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab, int isRJ){ w.xSelectCallback = 0; w.xSelectCallback2 = 0; w.eCode = 0; - w.mWFlags = isRJ!=0; w.u.iCur = iTab; sqlite3WalkExpr(&w, p); return w.eCode; @@ -115539,7 +111154,7 @@ SQLITE_PRIVATE int sqlite3ExprCoveredByIndex( } -/* Structure used to pass information throughout the Walker in order to +/* Structure used to pass information throught the Walker in order to ** implement sqlite3ReferencesSrcList(). */ struct RefSrcList { @@ -115646,12 +111261,6 @@ SQLITE_PRIVATE int sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList assert( pExpr->op==TK_AGG_FUNCTION ); assert( ExprUseXList(pExpr) ); sqlite3WalkExprList(&w, pExpr->x.pList); - if( pExpr->pLeft ){ - assert( pExpr->pLeft->op==TK_ORDER ); - assert( ExprUseXList(pExpr->pLeft) ); - assert( pExpr->pLeft->x.pList!=0 ); - sqlite3WalkExprList(&w, pExpr->pLeft->x.pList); - } #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(pExpr, EP_WinFunc) ){ sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter); @@ -115675,8 +111284,10 @@ SQLITE_PRIVATE int sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList ** it does, make a copy. This is done because the pExpr argument is ** subject to change. ** -** The copy is scheduled for deletion using the sqlite3ExprDeferredDelete() -** which builds on the sqlite3ParserAddCleanup() mechanism. +** 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. */ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){ if( ALWAYS(!ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced)) @@ -115686,24 +111297,24 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){ int iAgg = pExpr->iAgg; Parse *pParse = pWalker->pParse; sqlite3 *db = pParse->db; - assert( iAgg>=0 ); if( pExpr->op!=TK_AGG_FUNCTION ){ - if( iAggnColumn - && pAggInfo->aCol[iAgg].pCExpr==pExpr - ){ + assert( pExpr->op==TK_AGG_COLUMN || pExpr->op==TK_IF_NULL_ROW ); + assert( iAgg>=0 && iAggnColumn ); + if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){ pExpr = sqlite3ExprDup(db, pExpr, 0); - if( pExpr && !sqlite3ExprDeferredDelete(pParse, pExpr) ){ + if( pExpr ){ pAggInfo->aCol[iAgg].pCExpr = pExpr; + sqlite3ExprDeferredDelete(pParse, pExpr); } } }else{ assert( pExpr->op==TK_AGG_FUNCTION ); - if( ALWAYS(iAggnFunc) - && pAggInfo->aFunc[iAgg].pFExpr==pExpr - ){ + assert( iAgg>=0 && iAggnFunc ); + if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){ pExpr = sqlite3ExprDup(db, pExpr, 0); - if( pExpr && !sqlite3ExprDeferredDelete(pParse, pExpr) ){ + if( pExpr ){ pAggInfo->aFunc[iAgg].pFExpr = pExpr; + sqlite3ExprDeferredDelete(pParse, pExpr); } } } @@ -115754,74 +111365,6 @@ static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){ return i; } -/* -** 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; knColumn; 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; jpExpr; - 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 sqlite3ExprAnalyzeAggregates(). See sqlite3ExprAnalyzeAggregates @@ -115835,45 +111378,7 @@ 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( sqlite3ExprCompare(0, pExpr, pIEpr->pExpr, iDataCur)==0 ) break; - } - if( pIEpr==0 ) break; - if( NEVER(!ExprUseYTab(pExpr)) ) break; - for(i=0; inSrc; 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.iAggnColumn ); - 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: { @@ -115885,26 +111390,83 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ if( ALWAYS(pSrcList!=0) ){ SrcItem *pItem = pSrcList->a; for(i=0; inSrc; i++, pItem++){ + struct AggInfo_col *pCol; assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); if( pExpr->iTable==pItem->iCursor ){ - findOrCreateAggInfoColumn(pParse, pAggInfo, pExpr); + /* 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; knColumn; k++, pCol++){ + if( pCol->iTable==pExpr->iTable + && pCol->iColumn==pExpr->iColumn + && pExpr->op!=TK_IF_NULL_ROW + ){ + 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 && 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; jpExpr; + 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; + if( pExpr->op==TK_COLUMN ){ + pExpr->op = TK_AGG_COLUMN; + } + pExpr->iAgg = (i16)k; break; } /* endif pExpr->iTable==pItem->iCursor */ } /* end loop over pSrcList */ } - return WRC_Continue; + return WRC_Prune; } 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; inFunc; i++, pItem++){ - if( NEVER(pItem->pFExpr==pExpr) ) break; + if( pItem->pFExpr==pExpr ) break; if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){ break; } @@ -115915,44 +111477,15 @@ 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 = sqlite3FindFunction(pParse->db, - 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 - && 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 ){ + pExpr->u.zToken, + pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0); + if( pExpr->flags & EP_Distinct ){ pItem->iDistinct = pParse->nTab++; }else{ pItem->iDistinct = -1; @@ -116076,37 +111609,6 @@ SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse *pParse){ pParse->nRangeReg = 0; } -/* -** Make sure sufficient registers have been allocated so that -** iReg is a valid register number. -*/ -SQLITE_PRIVATE void sqlite3TouchRegister(Parse *pParse, int iReg){ - if( pParse->nMemnMem = 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 sqlite3FirstAvailableRegister(Parse *pParse, int iMin){ - const ExprList *pList = pParse->pConstExpr; - if( pList ){ - int i; - for(i=0; inExpr; 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() @@ -116126,14 +111628,6 @@ SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){ return 0; } } - if( pParse->pConstExpr ){ - ExprList *pList = pParse->pConstExpr; - for(i=0; inExpr; i++){ - int iReg = pList->a[i].u.iConstExprReg; - if( iReg==0 ) continue; - if( iReg>=iFirst && iReg<=iLast ) return 0; - } - } return 1; } #endif /* SQLITE_DEBUG */ @@ -116588,19 +112082,14 @@ SQLITE_PRIVATE void 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 ){ 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*'" - " OR quick_check GLOB 'non-* value in*'", + " WHERE quick_check GLOB 'CHECK*' OR quick_check GLOB 'NULL*'", zTab, zDb ); } @@ -116689,7 +112178,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ pNew->u.tab.pDfltList = sqlite3ExprListDup(db, pTab->u.tab.pDfltList, 0); pNew->pSchema = db->aDb[iDb].pSchema; pNew->u.tab.addColOffset = pTab->u.tab.addColOffset; - assert( pNew->nTabRef==1 ); + pNew->nTabRef = 1; exit_begin_add_column: sqlite3SrcListDelete(db, pSrc); @@ -116888,14 +112377,13 @@ static void renameTokenCheckAll(Parse *pParse, const void *pPtr){ assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 ); if( pParse->nErr==0 ){ const RenameToken *p; - u32 i = 1; + u8 i = 0; for(p=pParse->pRename; p; p=p->pNext){ if( p->p ){ assert( p->p!=pPtr ); - i += *(u8*)(p->p) | 1; + i += *(u8*)(p->p); } } - assert( i>0 ); } } #else @@ -117194,7 +112682,7 @@ static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){ } /* -** An error occurred while parsing or otherwise processing a database +** An error occured 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 @@ -117426,19 +112914,6 @@ static int renameEditSql( return rc; } -/* -** 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; inExpr; 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 @@ -117462,7 +112937,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 = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab)!=0; + rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab); } /* Resolve symbols in WHEN clause */ @@ -117486,17 +112961,7 @@ 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 - ** " = " 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); 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 ); @@ -118404,12 +113869,7 @@ SQLITE_PRIVATE void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, const T if( i==pTab->iPKey ){ 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; - } sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut); - pTab->aCol[i].affinity = aff; } nField++; } @@ -118720,9 +114180,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 */ @@ -118880,9 +114340,9 @@ static void statInit( /* Allocate the space required for the StatAccum object */ n = sizeof(*p) - + sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */ + + sizeof(tRowcnt)*nColUp /* StatAccum.anEq */ + + 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[] */ @@ -118903,9 +114363,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 */ @@ -119172,9 +114632,7 @@ static void statPush( if( p->nRow==0 ){ /* This is the first call to this function. Do initialization. */ -#ifdef SQLITE_ENABLE_STAT4 for(i=0; inCol; i++) p->current.anEq[i] = 1; -#endif }else{ /* Second and subsequent calls get processed here */ #ifdef SQLITE_ENABLE_STAT4 @@ -119183,17 +114641,15 @@ 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; icurrent.anEq[i]++; } -#endif for(i=iChng; inCol; i++){ p->current.anDLt[i]++; #ifdef SQLITE_ENABLE_STAT4 if( p->mxSample ) p->current.anLt[i] += p->current.anEq[i]; - p->current.anEq[i] = 1; #endif + p->current.anEq[i] = 1; } } @@ -119327,9 +114783,7 @@ static void statGet( u64 iVal = (p->nRow + nDistinct - 1) / nDistinct; if( iVal==2 && p->nRow*10 <= nDistinct*11 ) iVal = 1; sqlite3_str_appendf(&sStat, " %llu", iVal); -#ifdef SQLITE_ENABLE_STAT4 - assert( p->current.anEq[i] || p->nRow==0 ); -#endif + assert( p->current.anEq[i] ); } sqlite3ResultStrAccum(context, &sStat); } @@ -119456,15 +114910,11 @@ 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 - sqlite3TouchRegister(pParse, iMem); - assert( sqlite3NoTempsInRange(pParse, regNewRowid, iMem) ); + pParse->nMem = MAX(pParse->nMem, iMem); v = sqlite3GetVdbe(pParse); if( v==0 || NEVER(pTab==0) ){ return; @@ -119513,7 +114963,7 @@ static void analyzeOneTable( for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int nCol; /* Number of columns in pIdx. "N" */ - int addrGotoEnd; /* Address of "OP_Rewind iIdxCur" */ + int addrRewind; /* 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 */ @@ -119537,14 +114987,9 @@ static void analyzeOneTable( /* ** Pseudo-code for loop that calls stat_push(): ** - ** regChng = 0 ** Rewind csr - ** if eof(csr){ - ** stat_init() with count = 0; - ** goto end_of_scan; - ** } - ** count() - ** stat_init() + ** if eof(csr) goto end_of_scan; + ** regChng = 0 ** goto chng_addr_0; ** ** next_row: @@ -119575,7 +115020,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. */ - sqlite3TouchRegister(pParse, regPrev+nColTest); + pParse->nMem = MAX(pParse->nMem, regPrev+nColTest); /* Open a read-only cursor on the index being analyzed. */ assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) ); @@ -119583,36 +115028,41 @@ static void analyzeOneTable( sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "%s", pIdx->zName)); - /* Implementation of the following: + /* Invoke the stat_init() function. The arguments are: ** - ** 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 ); - 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, + */ sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat+1); assert( regRowid==regStat+2 ); sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regRowid); - sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp, - OptimizationDisabled(db, SQLITE_Stat4)); +#ifdef SQLITE_ENABLE_STAT4 + if( OptimizationEnabled(db, SQLITE_Stat4) ){ + sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regTemp); + addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur); + VdbeCoverage(v); + }else +#endif + { + addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp, 1); + } + assert( regTemp2==regStat+4 ); + sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2); sqlite3VdbeAddFunctionCall(pParse, 0, regStat+1, regStat, 4, &statInitFuncdef, 0); - addrGotoEnd = 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; + ** + */ sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng); addrNextRow = sqlite3VdbeCurrentAddr(v); @@ -119719,12 +115169,6 @@ 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. */ - sqlite3VdbeJumpHere(v, addrGotoEnd); - addrGotoEnd = 0; - } callStatGet(pParse, regStat, STAT_GET_STAT1, regStat1); assert( "BBB"[0]==SQLITE_AFF_TEXT ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0); @@ -119748,42 +115192,7 @@ static void analyzeOneTable( int addrIsNull; u8 seekOp = HasRowid(pTab) ? OP_NotExists : OP_NotFound; - /* No STAT4 data is generated if the number of rows is zero */ - if( addrGotoEnd==0 ){ - sqlite3VdbeAddOp2(v, OP_Cast, regStat1, SQLITE_AFF_INTEGER); - addrGotoEnd = 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 */ - sqlite3TouchRegister(pParse, regCol+mxCol); - doOnce = 0; -#ifdef SQLITE_DEBUG - /* Verify that the call to sqlite3ClearTempRegCache() below - ** really is needed. - ** https://sqlite.org/forum/forumpost/83cb4a95a0 (2023-03-25) - */ - testcase( !sqlite3NoTempsInRange(pParse, regEq, regCol+mxCol) ); -#endif - sqlite3ClearTempRegCache(pParse); /* tag-20230325-1 */ - assert( sqlite3NoTempsInRange(pParse, regEq, regCol+mxCol) ); - } - assert( sqlite3NoTempsInRange(pParse, regEq, regCol+nCol) ); + pParse->nMem = MAX(pParse->nMem, regCol+nCol); addrNext = sqlite3VdbeCurrentAddr(v); callStatGet(pParse, regStat, STAT_GET_ROWID, regSampleRowid); @@ -119807,7 +115216,7 @@ static void analyzeOneTable( #endif /* SQLITE_ENABLE_STAT4 */ /* End of analysis */ - if( addrGotoEnd ) sqlite3VdbeJumpHere(v, addrGotoEnd); + sqlite3VdbeJumpHere(v, addrRewind); } @@ -119864,11 +115273,6 @@ 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 = sqlite3FirstAvailableRegister(pParse, iMem); -#else - assert( iMem==sqlite3FirstAvailableRegister(pParse,iMem) ); -#endif } loadAnalysis(pParse, iDb); } @@ -120031,16 +115435,6 @@ 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; - } } } @@ -120119,8 +115513,6 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ ** and its contents. */ SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){ - assert( db!=0 ); - assert( pIdx!=0 ); #ifdef SQLITE_ENABLE_STAT4 if( pIdx->aSample ){ int j; @@ -120130,7 +115522,7 @@ SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){ } sqlite3DbFree(db, pIdx->aSample); } - if( db->pnBytesFreed==0 ){ + if( db && db->pnBytesFreed==0 ){ pIdx->nSample = 0; pIdx->aSample = 0; } @@ -120266,10 +115658,6 @@ 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; @@ -120277,7 +115665,6 @@ 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[] */ @@ -120317,11 +115704,6 @@ 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; @@ -120334,15 +115716,14 @@ static int loadStatTbl( decodeIntArray((char*)sqlite3_column_text(pStmt,2),nCol,pSample->anLt,0,0); decodeIntArray((char*)sqlite3_column_text(pStmt,3),nCol,pSample->anDLt,0,0); - /* Take a copy of the sample. Add 8 extra 0x00 bytes the end of the buffer. + /* Take a copy of the sample. Add two 0x00 bytes the end of the buffer. ** This is in case the sample record is corrupted. In that case, the ** sqlite3VdbeRecordCompare() may read up to two varints past the ** end of the allocated buffer before it realizes it is dealing with - ** 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 corrupt record. Adding the two 0x00 bytes prevents this from causing ** a buffer overread. */ pSample->n = sqlite3_column_bytes(pStmt, 4); - pSample->p = sqlite3DbMallocZero(db, pSample->n + 8); + pSample->p = sqlite3DbMallocZero(db, pSample->n + 2); if( pSample->p==0 ){ sqlite3_finalize(pStmt); return SQLITE_NOMEM_BKPT; @@ -120366,12 +115747,11 @@ static int loadStat4(sqlite3 *db, const char *zDb){ const Table *pStat4; assert( db->lookaside.bDisable ); - if( OptimizationEnabled(db, SQLITE_Stat4) - && (pStat4 = sqlite3FindTable(db, "sqlite_stat4", zDb))!=0 + if( (pStat4 = sqlite3FindTable(db, "sqlite_stat4", zDb))!=0 && IsOrdinaryTable(pStat4) ){ rc = loadStatTbl(db, - "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx COLLATE nocase", + "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx", "SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4", zDb ); @@ -120561,7 +115941,7 @@ static void attachFunc( char *zErr = 0; unsigned int flags; Db *aNew; /* New array of Db pointers */ - Db *pNew = 0; /* Db object for the newly attached database */ + Db *pNew; /* Db object for the newly attached database */ char *zErrDyn = 0; sqlite3_vfs *pVfs; @@ -120581,26 +115961,13 @@ static void attachFunc( /* This is not a real ATTACH. Instead, this routine is being called ** from sqlite3_deserialize() to close database db->init.iDb and ** reopen it as a MemDB */ - Btree *pNewBt = 0; pVfs = sqlite3_vfs_find("memdb"); if( pVfs==0 ) return; - rc = sqlite3BtreeOpen(pVfs, "x\0", db, &pNewBt, 0, SQLITE_OPEN_MAIN_DB); - if( rc==SQLITE_OK ){ - Schema *pNewSchema = 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) ) sqlite3BtreeClose(pNew->pBt); - pNew->pBt = pNewBt; - pNew->pSchema = pNewSchema; - }else{ - sqlite3BtreeClose(pNewBt); - rc = SQLITE_NOMEM; - } - } - if( rc ) goto attach_error; + pNew = &db->aDb[db->init.iDb]; + if( pNew->pBt ) sqlite3BtreeClose(pNew->pBt); + pNew->pBt = 0; + pNew->pSchema = 0; + rc = sqlite3BtreeOpen(pVfs, "x\0", db, &pNew->pBt, 0, SQLITE_OPEN_MAIN_DB); }else{ /* This is a real ATTACH ** @@ -120713,7 +116080,7 @@ static void attachFunc( } #endif if( rc ){ - if( ALWAYS(!REOPEN_AS_MEMDB(db)) ){ + if( !REOPEN_AS_MEMDB(db) ){ int iDb = db->nDb - 1; assert( iDb>=2 ); if( db->aDb[iDb].pBt ){ @@ -120830,8 +116197,6 @@ static void codeAttach( sqlite3* db = pParse->db; int regArgs; - if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto attach_end; - if( pParse->nErr ) goto attach_end; memset(&sName, 0, sizeof(NameContext)); sName.pParse = pParse; @@ -121300,7 +116665,7 @@ SQLITE_PRIVATE int sqlite3AuthCheck( sqlite3 *db = pParse->db; int rc; - /* Don't do any authorization checks if the database is initializing + /* Don't do any authorization checks if the database is initialising ** or if the parser is being invoked from within sqlite3_declare_vtab. */ assert( !IN_RENAME_OBJECT || db->xAuth==0 ); @@ -121556,7 +116921,7 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ } sqlite3VdbeAddOp0(v, OP_Halt); -#if SQLITE_USER_AUTHENTICATION && !defined(SQLITE_OMIT_SHARED_CACHE) +#if SQLITE_USER_AUTHENTICATION if( pParse->nTableLock>0 && db->init.busy==0 ){ sqlite3UserAuthInit(db); if( db->auth.authLevelnVtabLock = 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. */ - if( pParse->nTableLock ) codeTableLocks(pParse); -#endif + codeTableLocks(pParse); /* Initialize any AUTOINCREMENT data structures required. */ - if( pParse->pAinc ) sqlite3AutoincrementBegin(pParse); + sqlite3AutoincrementBegin(pParse); - /* Code constant expressions that were factored out of inner loops. + /* 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; inExpr; i++){ - assert( pEL->a[i].u.iConstExprReg>0 ); - sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg); + int iReg = pEL->a[i].u.iConstExprReg; + sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg); } } @@ -121671,7 +117039,6 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ 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 = sqlite3VMPrintf(db, zFormat, ap); @@ -122087,7 +117454,7 @@ SQLITE_PRIVATE void sqlite3ColumnSetExpr( */ SQLITE_PRIVATE Expr *sqlite3ColumnExpr(Table *pTab, Column *pCol){ if( pCol->iDflt==0 ) return 0; - if( !IsOrdinaryTable(pTab) ) return 0; + if( NEVER(!IsOrdinaryTable(pTab)) ) return 0; if( NEVER(pTab->u.tab.pDfltList==0) ) return 0; if( NEVER(pTab->u.tab.pDfltList->nExpriDflt) ) return 0; return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr; @@ -122119,7 +117486,7 @@ SQLITE_PRIVATE void sqlite3ColumnSetColl( } /* -** Return the collating sequence name for a column +** Return the collating squence name for a column */ SQLITE_PRIVATE const char *sqlite3ColumnColl(Column *pCol){ const char *z; @@ -122212,7 +117579,7 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){ if( IsOrdinaryTable(pTable) ){ sqlite3FkDelete(db, pTable); } -#ifndef SQLITE_OMIT_VIRTUALTABLE +#ifndef SQLITE_OMIT_VIRTUAL_TABLE else if( IsVirtual(pTable) ){ sqlite3VtabClear(db, pTable); } @@ -122240,9 +117607,6 @@ SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ if( db->pnBytesFreed==0 && (--pTable->nTabRef)>0 ) return; deleteTable(db, pTable); } -SQLITE_PRIVATE void sqlite3DeleteTableGeneric(sqlite3 *db, void *pTable){ - sqlite3DeleteTable(db, (Table*)pTable); -} /* @@ -122777,14 +118141,20 @@ SQLITE_PRIVATE void 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 sqlite3DeleteReturning(sqlite3 *db, void *pArg){ - Returning *pRet = (Returning*)pArg; +static void sqlite3DeleteReturning(sqlite3 *db, Returning *pRet){ Hash *pHash; pHash = &(db->aDb[1].pSchema->trigHash); - sqlite3HashInsert(pHash, pRet->zName, 0); + sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, 0); sqlite3ExprListDelete(db, pRet->pReturnEL); sqlite3DbFree(db, pRet); } @@ -122812,7 +118182,7 @@ SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){ if( pParse->pNewTrigger ){ sqlite3ErrorMsg(pParse, "cannot use RETURNING in a trigger"); }else{ - assert( pParse->bReturning==0 || pParse->ifNotExists ); + assert( pParse->bReturning==0 ); } pParse->bReturning = 1; pRet = sqlite3DbMallocZero(db, sizeof(*pRet)); @@ -122823,12 +118193,11 @@ SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){ pParse->u1.pReturning = pRet; pRet->pParse = pParse; pRet->pReturnEL = pList; - sqlite3ParserAddCleanup(pParse, sqlite3DeleteReturning, pRet); + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3DeleteReturning, pRet); testcase( pParse->earlyCleanup ); if( db->mallocFailed ) return; - sqlite3_snprintf(sizeof(pRet->zName), pRet->zName, - "sqlite_returning_%p", pParse); - pRet->retTrig.zName = pRet->zName; + pRet->retTrig.zName = RETURNING_TRIGGER_NAME; pRet->retTrig.op = TK_RETURNING; pRet->retTrig.tr_tm = TRIGGER_AFTER; pRet->retTrig.bReturning = 1; @@ -122839,9 +118208,8 @@ SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){ pRet->retTStep.pTrig = &pRet->retTrig; pRet->retTStep.pExprList = pList; pHash = &(db->aDb[1].pSchema->trigHash); - assert( sqlite3HashFind(pHash, pRet->zName)==0 - || pParse->nErr || pParse->ifNotExists ); - if( sqlite3HashInsert(pHash, pRet->zName, &pRet->retTrig) + assert( sqlite3HashFind(pHash, RETURNING_TRIGGER_NAME)==0 || pParse->nErr ); + if( sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, &pRet->retTrig) ==&pRet->retTrig ){ sqlite3OomFault(db); } @@ -122875,7 +118243,7 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){ } if( !IN_RENAME_OBJECT ) sqlite3DequoteToken(&sName); - /* Because keywords GENERATE ALWAYS can be converted into identifiers + /* Because keywords GENERATE ALWAYS can be converted into indentifiers ** 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. */ @@ -123022,8 +118390,7 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, Column *pCol){ assert( zIn!=0 ); while( zIn[0] ){ - u8 x = *(u8*)zIn; - h = (h<<8) + sqlite3UpperToLower[x]; + h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff]; zIn++; if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */ aff = SQLITE_AFF_TEXT; @@ -123097,7 +118464,7 @@ SQLITE_PRIVATE void 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 default value text */ + const char *zEnd /* First character past end of defaut value text */ ){ Table *p; Column *pCol; @@ -123369,14 +118736,6 @@ SQLITE_PRIVATE void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType 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 = sqlite3PExpr(pParse, TK_UPLUS, pExpr, 0); - } - if( pExpr && pExpr->op!=TK_RAISE ) pExpr->affExpr = pCol->affinity; sqlite3ColumnSetExpr(pParse, pTab, pCol, pExpr); pExpr = 0; goto generated_done; @@ -123445,7 +118804,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 alphanumeric +** If the string zSignedIdent consists entirely of alpha-numeric ** 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. @@ -123513,8 +118872,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){ /* SQLITE_AFF_TEXT */ " TEXT", /* SQLITE_AFF_NUMERIC */ " NUM", /* SQLITE_AFF_INTEGER */ " INT", - /* SQLITE_AFF_REAL */ " REAL", - /* SQLITE_AFF_FLEXNUM */ " NUM", + /* SQLITE_AFF_REAL */ " REAL" }; int len; const char *zType; @@ -123530,12 +118888,10 @@ static char *createTableStmt(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 = sqlite3Strlen30(zType); assert( pCol->affinity==SQLITE_AFF_BLOB - || pCol->affinity==SQLITE_AFF_FLEXNUM || pCol->affinity==sqlite3AffinityType(zType, 0) ); memcpy(&zStmt[k], zType, len); k += len; @@ -123597,7 +118953,7 @@ static void estimateIndexWidth(Index *pIdx){ for(i=0; inColumn; i++){ i16 x = pIdx->aiColumn[i]; assert( xpTable->nCol ); - wIndex += x<0 ? 1 : aCol[x].szEst; + wIndex += x<0 ? 1 : aCol[pIdx->aiColumn[i]].szEst; } pIdx->szIdxRow = sqlite3LogEst(wIndex*4); } @@ -123950,7 +119306,6 @@ SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName){ ** 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; } @@ -124195,20 +119550,20 @@ SQLITE_PRIVATE void 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); sqlite3MayAbort(pParse); - sqlite3VdbeAddOp3(v, OP_OpenWrite, iCsr, pParse->regRoot, iDb); + sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb); sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG); + pParse->nTab = 2; addrTop = sqlite3VdbeCurrentAddr(v) + 1; sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); if( pParse->nErr ) return; @@ -124229,11 +119584,11 @@ SQLITE_PRIVATE void sqlite3EndTable( VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_MakeRecord, dest.iSdst, dest.nSdst, regRec); sqlite3TableAffinity(v, p, 0); - sqlite3VdbeAddOp2(v, OP_NewRowid, iCsr, regRowid); - sqlite3VdbeAddOp3(v, OP_Insert, iCsr, regRec, regRowid); + sqlite3VdbeAddOp2(v, OP_NewRowid, 1, regRowid); + sqlite3VdbeAddOp3(v, OP_Insert, 1, regRec, regRowid); sqlite3VdbeGoto(v, addrInsLoop); sqlite3VdbeJumpHere(v, addrInsLoop); - sqlite3VdbeAddOp1(v, OP_Close, iCsr); + sqlite3VdbeAddOp1(v, OP_Close, 1); } /* Compute the complete text of the CREATE statement */ @@ -124286,14 +119641,6 @@ SQLITE_PRIVATE void sqlite3EndTable( /* Reparse everything to update our internal data structures */ sqlite3VdbeAddParseSchemaOp(v, iDb, 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 ){ - sqlite3VdbeAddOp4(v, OP_SqlExec, 0x0001, 0, 0, - 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. @@ -124370,12 +119717,9 @@ SQLITE_PRIVATE void 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. The ability can also be toggled - ** using sqlite3_config(SQLITE_CONFIG_ROWID_IN_VIEW,...) */ -#ifdef SQLITE_ALLOW_ROWID_IN_VIEW - p->tabFlags |= sqlite3Config.mNoVisibleRowid; /* Optional. Allow by default */ -#else - p->tabFlags |= TF_NoVisibleRowid; /* Never allow rowid in view */ + ** depend upon the old buggy behavior. */ +#ifndef SQLITE_ALLOW_ROWID_IN_VIEW + p->tabFlags |= TF_NoVisibleRowid; #endif sqlite3TwoPartName(pParse, pName1, pName2, &pName); @@ -124431,9 +119775,8 @@ 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 non-zero if -** there are errors. If an error is seen an error message is left -** in pParse->zErrMsg. +** 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. */ static SQLITE_NOINLINE int viewGetColumnNames(Parse *pParse, Table *pTable){ Table *pSelTab; /* A fake table from which we get the result set */ @@ -124529,7 +119872,8 @@ static SQLITE_NOINLINE int viewGetColumnNames(Parse *pParse, Table *pTable){ && pTable->nCol==pSel->pEList->nExpr ){ assert( db->mallocFailed==0 ); - sqlite3SubqueryColumnTypes(pParse, pTable, pSel, SQLITE_AFF_NONE); + sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel, + SQLITE_AFF_NONE); } }else{ /* CREATE VIEW name AS... without an argument list. Construct @@ -124556,7 +119900,7 @@ static SQLITE_NOINLINE int viewGetColumnNames(Parse *pParse, Table *pTable){ sqlite3DeleteColumnNames(db, pTable); } #endif /* SQLITE_OMIT_VIEW */ - return nErr + pParse->nErr; + return nErr; } SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ assert( pTable!=0 ); @@ -125347,7 +120691,7 @@ SQLITE_PRIVATE void 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 initializing a database schema. + ** if initialising a database schema. */ if( !db->init.busy ){ pTab = sqlite3SrcListLookup(pParse, pTblName); @@ -126889,7 +122233,7 @@ SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ if( iDb<0 ) return; z = sqlite3NameFromToken(db, pObjName); if( z==0 ) return; - zDb = pName2->n ? db->aDb[iDb].zDbSName : 0; + zDb = db->aDb[iDb].zDbSName; pTab = sqlite3FindTable(db, z, zDb); if( pTab ){ reindexTable(pParse, pTab, 0); @@ -126899,7 +122243,6 @@ SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ pIndex = sqlite3FindIndex(db, z, zDb); sqlite3DbFree(db, z); if( pIndex ){ - iDb = sqlite3SchemaToIndex(db, pIndex->pTable->pSchema); sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3RefillIndex(pParse, pIndex, -1); return; @@ -127005,7 +122348,7 @@ SQLITE_PRIVATE void sqlite3CteDelete(sqlite3 *db, Cte *pCte){ /* ** This routine is invoked once per CTE by the parser while parsing a -** WITH clause. The CTE described by the third argument is added to +** WITH clause. The CTE described by teh 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. */ @@ -127065,9 +122408,6 @@ SQLITE_PRIVATE void sqlite3WithDelete(sqlite3 *db, With *pWith){ sqlite3DbFree(db, pWith); } } -SQLITE_PRIVATE void sqlite3WithDeleteGeneric(sqlite3 *db, void *pWith){ - sqlite3WithDelete(db, (With*)pWith); -} #endif /* !defined(SQLITE_OMIT_CTE) */ /************** End of build.c ***********************************************/ @@ -127259,7 +122599,6 @@ SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8 enc){ ** strings is BINARY. */ db->pDfltColl = sqlite3FindCollSeq(db, enc, sqlite3StrBINARY, 0); - sqlite3ExpirePreparedStatements(db, 1); } /* @@ -127650,9 +122989,8 @@ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ Table *pTab; assert( pItem && pSrc->nSrc>=1 ); pTab = sqlite3LocateTableItem(pParse, 0, pItem); - if( pItem->pTab ) sqlite3DeleteTable(pParse->db, pItem->pTab); + sqlite3DeleteTable(pParse->db, pItem->pTab); pItem->pTab = pTab; - pItem->fg.notCte = 1; if( pTab ){ pTab->nTabRef++; if( pItem->fg.isIndexedBy && sqlite3IndexedByLookup(pParse, pItem) ){ @@ -127732,15 +123070,13 @@ 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 sqlite3IsReadOnly(Parse *pParse, Table *pTab, Trigger *pTrigger){ +SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){ if( tabIsReadOnly(pParse, pTab) ){ sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName); return 1; } #ifndef SQLITE_OMIT_VIEW - if( IsView(pTab) - && (pTrigger==0 || (pTrigger->bReturning && pTrigger->pNext==0)) - ){ + if( !viewOk && IsView(pTab) ){ sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName); return 1; } @@ -127805,7 +123141,7 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere( sqlite3 *db = pParse->db; Expr *pLhs = NULL; /* LHS of IN(SELECT...) operator */ Expr *pInClause = NULL; /* WHERE rowid IN ( select ) */ - ExprList *pEList = NULL; /* Expression list containing only pSelectRowid*/ + ExprList *pEList = NULL; /* Expression list contaning only pSelectRowid */ SrcList *pSelectSrc = NULL; /* SELECT rowid FROM x ... (dup of pSrc) */ Select *pSelect = NULL; /* Complete SELECT tree */ Table *pTab; @@ -127843,20 +123179,14 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere( ); }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); - assert( pPk!=0 ); - assert( pPk->nKeyCol>=1 ); if( pPk->nKeyCol==1 ){ - const char *zName; - assert( pPk->aiColumn[0]>=0 && pPk->aiColumn[0]nCol ); - zName = pTab->aCol[pPk->aiColumn[0]].zCnName; + const char *zName = pTab->aCol[pPk->aiColumn[0]].zCnName; pLhs = sqlite3Expr(db, TK_ID, zName); pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, zName)); }else{ int i; for(i=0; inKeyCol; i++){ - Expr *p; - assert( pPk->aiColumn[i]>=0 && pPk->aiColumn[i]nCol ); - p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zCnName); + Expr *p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zCnName); pEList = sqlite3ExprListAppend(pParse, pEList, p); } pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); @@ -127885,7 +123215,7 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere( pOrderBy,0,pLimit ); - /* now generate the new WHERE rowid IN clause for the DELETE/UPDATE */ + /* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */ pInClause = sqlite3PExpr(pParse, TK_IN, pLhs, 0); sqlite3PExprAddSelect(pParse, pInClause, pSelect); return pInClause; @@ -128000,7 +123330,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( goto delete_from_cleanup; } - if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){ + if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){ goto delete_from_cleanup; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); @@ -128109,12 +123439,12 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( #endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */ { u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK; - if( sNC.ncFlags & NC_Subquery ) bComplex = 1; + if( sNC.ncFlags & NC_VarSelect ) bComplex = 1; wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW); if( HasRowid(pTab) ){ /* For a rowid table, initialize the RowSet to an empty set */ pPk = 0; - assert( nPk==1 ); + nPk = 1; iRowSet = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet); }else{ @@ -128142,8 +123472,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( if( pWInfo==0 ) goto delete_from_cleanup; eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI ); - assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF - || OptimizationDisabled(db, SQLITE_OnePass) ); + assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF ); if( eOnePass!=ONEPASS_SINGLE ) sqlite3MultiWrite(pParse); if( sqlite3WhereUsesDeferredSeek(pWInfo) ){ sqlite3VdbeAddOp1(v, OP_FinishSeek, iTabCur); @@ -128480,11 +123809,9 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete( sqlite3FkActions(pParse, pTab, 0, iOld, 0, 0); /* Invoke AFTER DELETE trigger programs. */ - if( pTrigger ){ - sqlite3CodeRowTrigger(pParse, pTrigger, - TK_DELETE, 0, TRIGGER_AFTER, pTab, iOld, onconf, iLabel - ); - } + 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 @@ -128797,42 +124124,6 @@ static void lengthFunc( } } -/* -** Implementation of the octet_length() function -*/ -static void bytelengthFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - assert( argc==1 ); - UNUSED_PARAMETER(argc); - switch( sqlite3_value_type(argv[0]) ){ - case SQLITE_BLOB: { - sqlite3_result_int(context, sqlite3_value_bytes(argv[0])); - break; - } - case SQLITE_INTEGER: - case SQLITE_FLOAT: { - i64 m = sqlite3_context_db_handle(context)->enc<=SQLITE_UTF8 ? 1 : 2; - sqlite3_result_int64(context, sqlite3_value_bytes(argv[0])*m); - break; - } - case SQLITE_TEXT: { - if( sqlite3_value_encoding(argv[0])<=SQLITE_UTF8 ){ - sqlite3_result_int(context, sqlite3_value_bytes(argv[0])); - }else{ - sqlite3_result_int(context, sqlite3_value_bytes16(argv[0])); - } - break; - } - default: { - sqlite3_result_null(context); - break; - } - } -} - /* ** Implementation of the abs() function. ** @@ -129109,7 +124400,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ }else if( n==0 ){ r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5))); }else{ - zBuf = sqlite3_mprintf("%!.*f",n,r); + zBuf = sqlite3_mprintf("%.*f",n,r); if( zBuf==0 ){ sqlite3_result_error_nomem(context); return; @@ -129309,7 +124600,7 @@ struct compareInfo { /* ** For LIKE and GLOB matching on EBCDIC machines, assume that every -** character is exactly one byte in size. Also, provide the Utf8Read() +** character is exactly one byte in size. Also, provde the Utf8Read() ** macro for fast reading of the next character in the common case where ** the next character is ASCII. */ @@ -129542,7 +124833,7 @@ SQLITE_API int sqlite3_like_count = 0; /* ** Implementation of the like() SQL function. This function implements -** the built-in LIKE operator. The first argument to the function is the +** the build-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 @@ -129749,13 +125040,13 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){ double r1, r2; const char *zVal; r1 = sqlite3_value_double(pValue); - sqlite3_str_appendf(pStr, "%!0.15g", r1); + sqlite3_str_appendf(pStr, "%!.15g", r1); zVal = sqlite3_str_value(pStr); if( zVal ){ sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8); if( r1!=r2 ){ sqlite3_str_reset(pStr); - sqlite3_str_appendf(pStr, "%!0.20e", r1); + sqlite3_str_appendf(pStr, "%!.20e", r1); } } break; @@ -129766,7 +125057,7 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){ } case SQLITE_BLOB: { char const *zBlob = sqlite3_value_blob(pValue); - i64 nBlob = sqlite3_value_bytes(pValue); + int nBlob = sqlite3_value_bytes(pValue); assert( zBlob==sqlite3_value_blob(pValue) ); /* No encoding change */ sqlite3StrAccumEnlarge(pStr, nBlob*2 + 4); if( pStr->accError==0 ){ @@ -129875,7 +125166,6 @@ static void charFunc( *zOut++ = 0x80 + (u8)(c & 0x3F); } \ } - *zOut = 0; sqlite3_result_text64(context, (char*)z, zOut-z, sqlite3_free, SQLITE_UTF8); } @@ -129904,101 +125194,10 @@ static void hexFunc( *(z++) = hexdigits[c&0xf]; } *z = 0; - sqlite3_result_text64(context, zHex, (u64)(z-zHex), - 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( z0 ){ - const char *v = (const char*)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 ); - sqlite3_result_text64(context, z, j, sqlite3_free, SQLITE_UTF8); -} - -/* -** The CONCAT(...) function. Generate a string result that is the -** concatentation of all non-null arguments. -*/ -static void concatFunc( - sqlite3_context *context, - int argc, - 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( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - int nSep = sqlite3_value_bytes(argv[0]); - const char *zSep = (const char*)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_SQL_FUNCTION compile-time option is used. +** when the SQLITE_ENABLE_UNKNOWN_FUNCTION compile-time option is used. ** When the "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 @@ -130291,9 +125415,6 @@ static void unknownFunc( sqlite3_value **argv ){ /* no-op */ - (void)context; - (void)argc; - (void)argv; } #endif /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/ @@ -130395,68 +125516,13 @@ static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){ */ typedef struct SumCtx SumCtx; struct SumCtx { - 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 */ + double rSum; /* Floating point sum */ + i64 iSum; /* Integer sum */ i64 cnt; /* Number of elements summed */ - u8 approx; /* True if any non-integer value was input to the sum */ - u8 ovrfl; /* Integer overflow seen */ + u8 overflow; /* True if integer overflow seen */ + u8 approx; /* True if non-integer value was input to the sum */ }; -/* -** 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. ** @@ -130476,29 +125542,15 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){ type = sqlite3_value_numeric_type(argv[0]); if( p && type!=SQLITE_NULL ){ p->cnt++; - if( p->approx==0 ){ - if( type!=SQLITE_INTEGER ){ - kahanBabuskaNeumaierInit(p, p->iSum); - p->approx = 1; - kahanBabuskaNeumaierStep(p, sqlite3_value_double(argv[0])); - }else{ - i64 x = p->iSum; - if( sqlite3AddInt64(&x, sqlite3_value_int64(argv[0]))==0 ){ - p->iSum = x; - }else{ - p->ovrfl = 1; - kahanBabuskaNeumaierInit(p, p->iSum); - p->approx = 1; - kahanBabuskaNeumaierStepInt64(p, sqlite3_value_int64(argv[0])); - } + if( type==SQLITE_INTEGER ){ + i64 v = sqlite3_value_int64(argv[0]); + p->rSum += v; + if( (p->approx|p->overflow)==0 && sqlite3AddInt64(&p->iSum, v) ){ + p->approx = p->overflow = 1; } }else{ - if( type==SQLITE_INTEGER ){ - kahanBabuskaNeumaierStepInt64(p, sqlite3_value_int64(argv[0])); - }else{ - p->ovrfl = 0; - kahanBabuskaNeumaierStep(p, sqlite3_value_double(argv[0])); - } + p->rSum += sqlite3_value_double(argv[0]); + p->approx = 1; } } } @@ -130515,18 +125567,13 @@ static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){ if( ALWAYS(p) && type!=SQLITE_NULL ){ assert( p->cnt>0 ); p->cnt--; - if( !p->approx ){ - p->iSum -= sqlite3_value_int64(argv[0]); - }else if( type==SQLITE_INTEGER ){ - i64 iVal = sqlite3_value_int64(argv[0]); - if( iVal!=SMALLEST_INT64 ){ - kahanBabuskaNeumaierStepInt64(p, -iVal); - }else{ - kahanBabuskaNeumaierStepInt64(p, LARGEST_INT64); - kahanBabuskaNeumaierStepInt64(p, 1); - } + assert( type==SQLITE_INTEGER || p->approx ); + if( type==SQLITE_INTEGER && p->approx==0 ){ + i64 v = sqlite3_value_int64(argv[0]); + p->rSum -= v; + p->iSum -= v; }else{ - kahanBabuskaNeumaierStep(p, -sqlite3_value_double(argv[0])); + p->rSum -= sqlite3_value_double(argv[0]); } } } @@ -130537,14 +125584,10 @@ static void sumFinalize(sqlite3_context *context){ SumCtx *p; p = sqlite3_aggregate_context(context, 0); if( p && p->cnt>0 ){ - if( p->approx ){ - if( p->ovrfl ){ - sqlite3_result_error(context,"integer overflow",-1); - }else if( !sqlite3IsOverflow(p->rErr) ){ - sqlite3_result_double(context, p->rSum+p->rErr); - }else{ - sqlite3_result_double(context, p->rSum); - } + if( p->overflow ){ + sqlite3_result_error(context,"integer overflow",-1); + }else if( p->approx ){ + sqlite3_result_double(context, p->rSum); }else{ sqlite3_result_int64(context, p->iSum); } @@ -130554,29 +125597,14 @@ static void avgFinalize(sqlite3_context *context){ SumCtx *p; p = sqlite3_aggregate_context(context, 0); if( p && p->cnt>0 ){ - double r; - if( p->approx ){ - r = p->rSum; - if( !sqlite3IsOverflow(p->rErr) ) r += p->rErr; - }else{ - r = (double)(p->iSum); - } - sqlite3_result_double(context, r/(double)p->cnt); + sqlite3_result_double(context, p->rSum/(double)p->cnt); } } static void totalFinalize(sqlite3_context *context){ SumCtx *p; - double r = 0.0; p = sqlite3_aggregate_context(context, 0); - if( p ){ - if( p->approx ){ - r = p->rSum; - if( !sqlite3IsOverflow(p->rErr) ) r += p->rErr; - }else{ - r = (double)(p->iSum); - } - } - sqlite3_result_double(context, r); + /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ + sqlite3_result_double(context, p ? p->rSum : (double)0); } /* @@ -130695,7 +125723,6 @@ static void minMaxFinalize(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 @@ -130799,7 +125826,7 @@ static void groupConcatInverse( if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC)); /* pGCC is always non-NULL since groupConcatStep() will have always - ** run first to initialize it */ + ** run frist to initialize it */ if( ALWAYS(pGCC) ){ int nVS; /* Must call sqlite3_value_text() to convert the argument into text prior @@ -130854,8 +125881,6 @@ static void groupConcatValue(sqlite3_context *context){ sqlite3_result_error_toobig(context); }else if( pAccum->accError==SQLITE_NOMEM ){ sqlite3_result_error_nomem(context); - }else if( pGCC->nAccum>0 && pAccum->nChar==0 ){ - sqlite3_result_text(context, "", 1, SQLITE_STATIC); }else{ const char *zText = sqlite3_str_value(pAccum); sqlite3_result_text(context, zText, pAccum->nChar, SQLITE_TRANSIENT); @@ -130885,10 +125910,8 @@ SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){ ** sensitive. */ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(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; @@ -130896,13 +125919,10 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive) pInfo = (struct compareInfo*)&likeInfoNorm; flags = SQLITE_FUNC_LIKE; } - for(nArg=2; nArg<=3; nArg++){ - sqlite3CreateFunc(db, "like", nArg, SQLITE_UTF8, pInfo, likeFunc, - 0, 0, 0, 0, 0); - pDef = sqlite3FindFunction(db, "like", nArg, SQLITE_UTF8, 0); - pDef->funcFlags |= flags; - pDef->funcFlags &= ~SQLITE_FUNC_UNSAFE; - } + sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0); + sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0); + sqlite3FindFunction(db, "like", 2, SQLITE_UTF8, 0)->funcFlags |= flags; + sqlite3FindFunction(db, "like", 3, SQLITE_UTF8, 0)->funcFlags |= flags; } /* @@ -131023,18 +126043,6 @@ static void ceilingFunc( 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: ** @@ -131073,15 +126081,17 @@ static void logFunc( } ans = log(x)/b; }else{ + ans = log(x); switch( SQLITE_PTR_TO_INT(sqlite3_user_data(context)) ){ case 1: - ans = log10(x); + /* Convert from natural logarithm to log base 10 */ + ans /= M_LN10; break; case 2: - ans = log2(x); + /* Convert from natural logarithm to log base 2 */ + ans /= M_LN2; break; default: - ans = log(x); break; } } @@ -131150,7 +126160,6 @@ static void piFunc( sqlite3_value **argv ){ assert( argc==0 ); - (void)argv; sqlite3_result_double(context, M_PI); } @@ -131174,37 +126183,6 @@ static void signFunc( 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( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - FpDecode s; - double x; - int y, z; - char zBuf[100]; - UNUSED_PARAMETER(argc); - assert( argc==3 ); - x = sqlite3_value_double(argv[0]); - y = sqlite3_value_int(argv[1]); - z = sqlite3_value_int(argv[2]); - sqlite3FpDecode(&s, x, y, z); - if( s.isSpecial==2 ){ - sqlite3_snprintf(sizeof(zBuf), zBuf, "NaN"); - }else{ - sqlite3_snprintf(sizeof(zBuf), zBuf, "%c%.*s/%d", s.sign, s.n, s.z, s.iDP); - } - 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 @@ -131269,16 +126247,12 @@ SQLITE_PRIVATE void 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 ), @@ -131286,13 +126260,6 @@ SQLITE_PRIVATE void 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 ), @@ -131322,8 +126289,6 @@ SQLITE_PRIVATE void 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 @@ -132266,7 +127231,6 @@ 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; } } @@ -132461,8 +127425,6 @@ SQLITE_PRIVATE void 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 @@ -132578,11 +127540,7 @@ SQLITE_PRIVATE int sqlite3FkRequired( /* Check if any parent key columns are being modified. */ for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ if( fkParentIsModified(pTab, p, aChange, chngRowid) ){ - if( (pParse->db->flags & SQLITE_FkNoAction)==0 - && p->aAction[1]!=OE_None - ){ - return 2; - } + if( p->aAction[1]!=OE_None ) return 2; bHaveFK = 1; } } @@ -132632,7 +127590,6 @@ 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; } @@ -132733,22 +127690,22 @@ static Trigger *fkActionTrigger( if( action==OE_Restrict ){ int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); - SrcList *pSrc; + Token tFrom; + Token tDb; Expr *pRaise; + tFrom.z = zFrom; + tFrom.n = nFrom; + tDb.z = db->aDb[iDb].zDbSName; + tDb.n = sqlite3Strlen30(tDb.z); + pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed"); if( pRaise ){ pRaise->affExpr = OE_Abort; } - pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); - if( pSrc ){ - assert( pSrc->nSrc==1 ); - pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom); - pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); - } pSelect = sqlite3SelectNew(pParse, sqlite3ExprListAppend(pParse, 0, pRaise), - pSrc, + sqlite3SrcListAppend(pParse, 0, &tDb, &tFrom), pWhere, 0, 0, 0, 0, 0 ); @@ -132864,8 +127821,9 @@ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){ if( pFKey->pPrevTo ){ pFKey->pPrevTo->pNextTo = pFKey->pNextTo; }else{ - const char *z = (pFKey->pNextTo ? pFKey->pNextTo->zTo : pFKey->zTo); - sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, pFKey->pNextTo); + void *p = (void *)pFKey->pNextTo; + const char *z = (p ? pFKey->pNextTo->zTo : pFKey->zTo); + sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, p); } if( pFKey->pNextTo ){ pFKey->pNextTo->pPrevTo = pFKey->pPrevTo; @@ -132928,10 +127886,8 @@ SQLITE_PRIVATE void sqlite3OpenTable( assert( pParse->pVdbe!=0 ); v = pParse->pVdbe; assert( opcode==OP_OpenWrite || opcode==OP_OpenRead ); - if( !pParse->db->noSharedCache ){ - sqlite3TableLock(pParse, iDb, pTab->tnum, - (opcode==OP_OpenWrite)?1:0, pTab->zName); - } + sqlite3TableLock(pParse, iDb, pTab->tnum, + (opcode==OP_OpenWrite)?1:0, pTab->zName); if( HasRowid(pTab) ){ sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nNVCol); VdbeComment((v, "%s", pTab->zName)); @@ -132965,48 +127921,46 @@ SQLITE_PRIVATE void sqlite3OpenTable( ** is managed along with the rest of the Index structure. It will be ** released when sqlite3DeleteIndex() is called. */ -static SQLITE_NOINLINE const char *computeIndexAffStr(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 *)sqlite3DbMallocRaw(0, pIdx->nColumn+1); +SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){ if( !pIdx->zColAff ){ - sqlite3OomFault(db); - return 0; - } - for(n=0; nnColumn; 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 = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr); + /* 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 *)sqlite3DbMallocRaw(0, pIdx->nColumn+1); + if( !pIdx->zColAff ){ + sqlite3OomFault(db); + return 0; + } + for(n=0; nnColumn; 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 = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr); + } + if( affSQLITE_AFF_NUMERIC) aff = SQLITE_AFF_NUMERIC; + pIdx->zColAff[n] = aff; } - if( affSQLITE_AFF_NUMERIC) aff = SQLITE_AFF_NUMERIC; - pIdx->zColAff[n] = aff; + pIdx->zColAff[n] = 0; } - pIdx->zColAff[n] = 0; - return pIdx->zColAff; -} -SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(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 sqlite3DbMalloc(). The caller is responsible for freeing @@ -133060,7 +128014,7 @@ SQLITE_PRIVATE char *sqlite3TableAffinityStr(sqlite3 *db, const Table *pTab){ ** For STRICT tables: ** ------------------ ** -** Generate an appropriate OP_TypeCheck opcode that will verify the +** Generate an appropropriate 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 @@ -133470,196 +128424,6 @@ SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){ # define autoIncStep(A,B,C) #endif /* SQLITE_OMIT_AUTOINCREMENT */ -/* -** If argument pVal is a Select object returned by an sqlite3MultiValues() -** that was able to use the co-routine optimization, finish coding the -** co-routine. -*/ -SQLITE_PRIVATE void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){ - if( ALWAYS(pVal) && pVal->pSrc->nSrc>0 ){ - SrcItem *pItem = &pVal->pSrc->a[0]; - sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->regReturn); - 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; iinExpr; ii++){ - if( 0==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; iinExpr; ii++){ - Expr *pExpr = pRow->a[ii].pExpr; - assert( pExpr->op!=TK_RAISE ); - assert( pExpr->affExpr==0 ); - if( 0!=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 -** 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 *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 ){ - 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 = 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 = sqlite3GetVdbe(pParse); - Select *pRet = 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 ){ - 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 = sqlite3VdbeCurrentAddr(v) + 1; - p->regReturn = ++pParse->nMem; - p->iCursor = -1; - p->u1.nRow = 2; - sqlite3VdbeAddOp3(v,OP_InitCoroutine,p->regReturn,0,p->addrFillSub); - 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 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; - 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 ){ - sqlite3SelectWrongNumTermsError(pParse, p->pSelect); - }else{ - sqlite3ExprCodeExprList(pParse, pRow, p->regResult, 0, 0); - sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, p->regReturn); - } - } - sqlite3ExprListDelete(pParse->db, pRow); - } - - return pLeft; -} /* Forward declaration */ static int xferOptimization( @@ -133881,7 +128645,7 @@ SQLITE_PRIVATE void sqlite3Insert( /* Cannot insert into a read-only table. */ - if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){ + if( sqlite3IsReadOnly(pParse, pTab, tmask) ){ goto insert_cleanup; } @@ -133996,40 +128760,25 @@ SQLITE_PRIVATE void 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 */ - 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 = sqlite3VdbeCurrentAddr(v) + 1; - sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); - sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); - dest.iSdst = bIdListInOrder ? regData : 0; - dest.nSdst = pTab->nCol; - rc = sqlite3Select(pParse, pSelect, &dest); - regFromSelect = dest.iSdst; - assert( db->pParse==pParse ); - if( rc || pParse->nErr ) goto insert_cleanup; - assert( db->mallocFailed==0 ); - sqlite3VdbeEndCoroutine(v, regYield); - sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */ - assert( pSelect->pEList ); - nColumn = pSelect->pEList->nExpr; - } + regYield = ++pParse->nMem; + addrTop = sqlite3VdbeCurrentAddr(v) + 1; + sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); + sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); + dest.iSdst = bIdListInOrder ? regData : 0; + dest.nSdst = pTab->nCol; + rc = sqlite3Select(pParse, pSelect, &dest); + regFromSelect = dest.iSdst; + assert( db->pParse==pParse ); + if( rc || pParse->nErr ) goto insert_cleanup; + assert( db->mallocFailed==0 ); + sqlite3VdbeEndCoroutine(v, regYield); + 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 @@ -134184,7 +128933,7 @@ SQLITE_PRIVATE void sqlite3Insert( pNx->iDataCur = iDataCur; pNx->iIdxCur = iIdxCur; if( pNx->pUpsertTarget ){ - if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx, pUpsert) ){ + if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx) ){ goto insert_cleanup; } } @@ -134343,7 +129092,7 @@ SQLITE_PRIVATE void sqlite3Insert( } /* Copy the new data already generated. */ - assert( pTab->nNVCol>0 || pParse->nErr>0 ); + assert( pTab->nNVCol>0 ); sqlite3VdbeAddOp3(v, OP_Copy, regRowid+1, regCols+1, pTab->nNVCol-1); #ifndef SQLITE_OMIT_GENERATED_COLUMNS @@ -134557,7 +129306,7 @@ insert_cleanup: /* This is the Walker callback from 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 modified by an UPDATE statement. +** columns that are being modifed by an UPDATE statement. */ static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_COLUMN ){ @@ -134780,7 +129529,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( int *aiChng, /* column i is unchanged if aiChng[i]<0 */ Upsert *pUpsert /* ON CONFLICT clauses, if any. NULL otherwise */ ){ - Vdbe *v; /* VDBE under construction */ + Vdbe *v; /* VDBE under constrution */ Index *pIdx; /* Pointer to one of the indices */ Index *pPk = 0; /* The PRIMARY KEY index for WITHOUT ROWID tables */ sqlite3 *db; /* Database connection */ @@ -134895,7 +129644,6 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( case OE_Fail: { char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName, pCol->zCnName); - testcase( zMsg==0 && db->mallocFailed==0 ); sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError, iReg); sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC); @@ -135263,7 +130011,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( pIdx; pIdx = indexIteratorNext(&sIdxIter, &ix) ){ - int regIdx; /* Range of registers holding content for pIdx */ + int regIdx; /* Range of registers hold conent 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 */ @@ -135758,8 +130506,6 @@ SQLITE_PRIVATE int 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 @@ -135772,18 +130518,18 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices( assert( v!=0 ); if( iBase<0 ) iBase = pParse->nTab; iDataCur = iBase++; - *piDataCur = iDataCur; + if( piDataCur ) *piDataCur = iDataCur; if( HasRowid(pTab) && (aToOpen==0 || aToOpen[0]) ){ sqlite3OpenTable(pParse, iDataCur, iDb, pTab, op); - }else if( pParse->db->noSharedCache==0 ){ + }else{ sqlite3TableLock(pParse, iDb, pTab->tnum, op==OP_OpenWrite, pTab->zName); } - *piIdxCur = iBase; + if( piIdxCur ) *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) ){ - *piDataCur = iIdxCur; + if( piDataCur ) *piDataCur = iIdxCur; p5 = 0; } if( aToOpen==0 || aToOpen[i+1] ){ @@ -136076,15 +130822,12 @@ static int xferOptimization( } } #ifndef SQLITE_OMIT_CHECK - if( pDest->pCheck - && (db->mDbFlags & DBFLAG_Vacuum)==0 - && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) - ){ + if( pDest->pCheck && 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 contains + /* Disallow the transfer optimization if the destination table constains ** 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 @@ -136792,13 +131535,6 @@ struct sqlite3_api_routines { const char *(*db_name)(sqlite3*,int); /* Version 3.40.0 and later */ int (*value_encoding)(sqlite3_value*); - /* Version 3.41.0 and later */ - int (*is_interrupted)(sqlite3*); - /* Version 3.43.0 and later */ - int (*stmt_explain)(sqlite3_stmt*,int); - /* Version 3.44.0 and later */ - void *(*get_clientdata)(sqlite3*,const char*); - int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*)); }; /* @@ -137125,13 +131861,6 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_db_name sqlite3_api->db_name /* Version 3.40.0 and later */ #define sqlite3_value_encoding sqlite3_api->value_encoding -/* Version 3.41.0 and later */ -#define sqlite3_is_interrupted sqlite3_api->is_interrupted -/* Version 3.43.0 and later */ -#define sqlite3_stmt_explain sqlite3_api->stmt_explain -/* Version 3.44.0 and later */ -#define sqlite3_get_clientdata sqlite3_api->get_clientdata -#define sqlite3_set_clientdata sqlite3_api->set_clientdata #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) @@ -137646,14 +132375,7 @@ static const sqlite3_api_routines sqlite3Apis = { #endif sqlite3_db_name, /* Version 3.40.0 and later */ - sqlite3_value_encoding, - /* Version 3.41.0 and later */ - sqlite3_is_interrupted, - /* Version 3.43.0 and later */ - sqlite3_stmt_explain, - /* Version 3.44.0 and later */ - sqlite3_get_clientdata, - sqlite3_set_clientdata + sqlite3_value_encoding }; /* True if x is the directory separator character @@ -137726,25 +132448,15 @@ static int 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 - ** - ** Later (2023-03-25): Save an extra 6 bytes for the filename suffix. - ** See https://sqlite.org/forum/forumpost/24083b579d. - */ + ** https://sqlite.org/forum/forumpost/08a0d6d9bf */ if( nMsg>SQLITE_MAX_PATHLEN ) goto extension_not_found; - /* Do not allow 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 = sqlite3OsDlOpen(pVfs, zFile); #if SQLITE_OS_UNIX || SQLITE_OS_WIN for(ii=0; iimutex); if( onoff ){ db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc; @@ -137921,9 +132630,6 @@ SQLITE_API int 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 = sqlite3_initialize(); if( rc ){ @@ -137976,9 +132682,6 @@ SQLITE_API int sqlite3_cancel_auto_extension( int i; int n = 0; wsdAutoextInit; -#ifdef SQLITE_ENABLE_API_ARMOR - if( xInit==0 ) return 0; -#endif sqlite3_mutex_enter(mutex); for(i=(int)wsdAutoext.nExt-1; i>=0; i--){ if( wsdAutoext.aExt[i]==xInit ){ @@ -138754,34 +133457,6 @@ static const PragmaName aPragmaName[] = { /************** End of pragma.h **********************************************/ /************** 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 @@ -139606,7 +134281,7 @@ SQLITE_PRIVATE void 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 turning cache spill on, the size is set to the + ** or off. When turnning cache spill on, the size is set to the ** current cache_size. The third form sets a spill size that ** may be different form the cache size. ** If N is positive then that is the @@ -139876,11 +134551,7 @@ SQLITE_PRIVATE void sqlite3Pragma( #endif if( sqlite3GetBoolean(zRight, 0) ){ - if( (mask & SQLITE_WriteSchema)==0 - || (db->flags & SQLITE_Defensive)==0 - ){ - db->flags |= mask; - } + db->flags |= mask; }else{ db->flags &= ~mask; if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; @@ -140280,7 +134951,7 @@ SQLITE_PRIVATE void sqlite3Pragma( zDb = db->aDb[iDb].zDbSName; sqlite3CodeVerifySchema(pParse, iDb); sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); - sqlite3TouchRegister(pParse, pTab->nCol+regRow); + if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow; sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead); sqlite3VdbeLoadString(v, regResult, pTab->zName); assert( IsOrdinaryTable(pTab) ); @@ -140321,7 +134992,7 @@ SQLITE_PRIVATE void 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. */ - sqlite3TouchRegister(pParse, regRow + pFK->nCol); + if( regRow+pFK->nCol>pParse->nMem ) pParse->nMem = regRow+pFK->nCol; for(j=0; jnCol; j++){ int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom; sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j); @@ -140388,9 +135059,9 @@ SQLITE_PRIVATE void 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 whereas integrity_check is O(NlogN). + ** is linear time wherease integrity_check is O(NlogN). ** - ** The maximum number of errors is 100 by default. A different default + ** The maximum nubmer 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 @@ -140427,7 +135098,7 @@ SQLITE_PRIVATE void sqlite3Pragma( /* Set the maximum error count */ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; if( zRight ){ - if( sqlite3GetInt32(pValue->z, &mxErr) ){ + if( sqlite3GetInt32(zRight, &mxErr) ){ if( mxErr<=0 ){ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; } @@ -140444,12 +135115,12 @@ SQLITE_PRIVATE void 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; sqlite3CodeVerifySchema(pParse, i); - pParse->okConstFactor = 0; /* tag-20230327-1 */ /* Do an integrity check of the B-Tree ** @@ -140465,6 +135136,7 @@ SQLITE_PRIVATE void 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++; @@ -140484,11 +135156,11 @@ SQLITE_PRIVATE void sqlite3Pragma( aRoot[0] = cnt; /* Make sure sufficient number of registers have been allocated */ - sqlite3TouchRegister(pParse, 8+cnt); + pParse->nMem = MAX( pParse->nMem, 8+mxIdx ); sqlite3ClearTempRegCache(pParse); /* Do the b-tree integrity checks */ - sqlite3VdbeAddOp4(v, OP_IntegrityCk, 1, cnt, 8, (char*)aRoot,P4_INTARRAY); + sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY); sqlite3VdbeChangeP5(v, (u8)i); addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, @@ -140498,36 +135170,6 @@ SQLITE_PRIVATE void sqlite3Pragma( integrityCheckResultRow(v); sqlite3VdbeJumpHere(v, addr); - /* Check that the indexes all have the right number of rows */ - cnt = pObjTab ? 1 : 0; - 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 = sqlite3VdbeAddOp3(v, OP_Eq, 8+cnt, 0, 8+iTab); - VdbeCoverageNeverNull(v); - sqlite3VdbeLoadString(v, 4, pIdx->zName); - sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3); - integrityCheckResultRow(v); - sqlite3VdbeJumpHere(v, addr); - } - cnt++; - } - } - /* Make sure all the indices are constructed correctly. */ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ @@ -140541,8 +135183,8 @@ SQLITE_PRIVATE void sqlite3Pragma( int r2; /* Previous key for WITHOUT ROWID tables */ int mxCol; /* Maximum non-virtual column number */ - if( pObjTab && pObjTab!=pTab ) continue; if( !IsOrdinaryTable(pTab) ) continue; + if( pObjTab && pObjTab!=pTab ) continue; if( isQuick || HasRowid(pTab) ){ pPk = 0; r2 = 0; @@ -140570,21 +135212,12 @@ SQLITE_PRIVATE void sqlite3Pragma( ** 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; jnCol; 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 = sqlite3PrimaryKeyIndex(pTab)->nColumn-1; - } + mxCol = pTab->nCol-1; + while( mxCol>=0 + && ((pTab->aCol[mxCol].colFlags & COLFLAG_VIRTUAL)!=0 + || pTab->iPKey==mxCol) ) mxCol--; if( mxCol>=0 ){ - sqlite3VdbeAddOp3(v, OP_Column, iDataCur, mxCol, 3); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, mxCol, 3); sqlite3VdbeTypeofColumn(v, 3); } @@ -140664,30 +135297,15 @@ SQLITE_PRIVATE void sqlite3Pragma( labelOk = sqlite3VdbeMakeLabel(pParse); if( pCol->notNull ){ /* (1) NOT NULL columns may not contain a NULL */ - int jmp3; int jmp2 = sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4); + sqlite3VdbeChangeP5(v, 0x0f); VdbeCoverage(v); - if( p1<0 ){ - sqlite3VdbeChangeP5(v, 0x0f); /* INT, REAL, TEXT, or BLOB */ - jmp3 = jmp2; - }else{ - 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. */ - sqlite3VdbeAddOp3(v, OP_Column, p1, p3, 3); - sqlite3ColumnDefault(v, pTab, j, 3); - jmp3 = sqlite3VdbeAddOp2(v, OP_NotNull, 3, labelOk); - VdbeCoverage(v); - } zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, pCol->zCnName); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); if( doTypeCheck ){ sqlite3VdbeGoto(v, labelError); sqlite3VdbeJumpHere(v, jmp2); - sqlite3VdbeJumpHere(v, jmp3); }else{ /* VDBE byte code will fall thru */ } @@ -140767,8 +135385,7 @@ SQLITE_PRIVATE void 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, label6; - int kk; + int jmp2, jmp3, jmp4, jmp5; int ckUniq = sqlite3VdbeMakeLabel(pParse); if( pPk==pIdx ) continue; r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3, @@ -140786,49 +135403,13 @@ SQLITE_PRIVATE void sqlite3Pragma( sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); jmp4 = integrityCheckResultRow(v); 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; - sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur+j, 3); - jmp7 = sqlite3VdbeAddOp3(v, OP_Eq, 3, 0, r1+pIdx->nColumn-1); - VdbeCoverageNeverNull(v); - sqlite3VdbeLoadString(v, 3, - "rowid not at end-of-record for row "); - sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); - sqlite3VdbeLoadString(v, 4, " of index "); - sqlite3VdbeGoto(v, jmp5-1); - 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; kknKeyCol; kk++){ - if( pIdx->azColl[kk]==sqlite3StrBINARY ) continue; - if( label6==0 ) label6 = sqlite3VdbeMakeLabel(pParse); - sqlite3VdbeAddOp3(v, OP_Column, iIdxCur+j, kk, 3); - sqlite3VdbeAddOp3(v, OP_Ne, 3, label6, r1+kk); VdbeCoverage(v); - } - if( label6 ){ - int jmp6 = sqlite3VdbeAddOp0(v, OP_Goto); - sqlite3VdbeResolveLabel(v, label6); - sqlite3VdbeLoadString(v, 3, "row "); - sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); - sqlite3VdbeLoadString(v, 4, " values differ from index "); - sqlite3VdbeGoto(v, jmp5-1); - 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 = sqlite3VdbeMakeLabel(pParse); int jmp6; + int kk; for(kk=0; kknKeyCol; kk++){ int iCol = pIdx->aiColumn[kk]; assert( iCol!=XN_ROWID && iColnCol ); @@ -140851,43 +135432,23 @@ SQLITE_PRIVATE void sqlite3Pragma( } sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v); sqlite3VdbeJumpHere(v, loopTop-1); - if( pPk ){ - assert( !isQuick ); - sqlite3ReleaseTempRange(pParse, r2, pPk->nKeyCol); + if( !isQuick ){ + sqlite3VdbeLoadString(v, 2, "wrong # of entries in index "); + for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ + if( pPk==pIdx ) continue; + sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3); + addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v); + sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); + sqlite3VdbeLoadString(v, 4, pIdx->zName); + sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3); + integrityCheckResultRow(v); + sqlite3VdbeJumpHere(v, addr); + } + if( pPk ){ + 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); - 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( sqlite3HashFind(&db->aModule, zMod)==0 ) continue; - } - 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; - sqlite3VdbeAddOp3(v, OP_VCheck, i, 3, isQuick); - pTab->nTabRef++; - sqlite3VdbeAppendP4(v, pTab, P4_TABLEREF); - a1 = sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v); - integrityCheckResultRow(v); - sqlite3VdbeJumpHere(v, a1); - continue; - } -#endif } { static const int iLn = VDBE_OFFSET_LINENO(2); @@ -141151,63 +135712,44 @@ SQLITE_PRIVATE void sqlite3Pragma( ** ** The optional argument is a bitmask of optimizations to perform: ** - ** 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. + ** 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. ** - ** 0x00002 Run ANALYZE on tables that might benefit. On by default. - ** See below for additional information. + ** 0x0002 Run ANALYZE on tables that might benefit. On by default. + ** See below for additional information. ** - ** 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. + ** 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. ** - ** 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. + ** 0x0008 (Not yet implemented) Create indexes that might have + ** been helpful to recent queries ** - ** 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. + ** 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. ** ** 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 0x00002 is set. - ** - ** (2) The table is an ordinary table, not a virtual table or view. + ** (1) MASK bit 0x02 is set. ** - ** (3) The table name does not begin with "sqlite_". + ** (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. ** - ** (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. + ** (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. ** ** The rules for when tables are analyzed are likely to change in - ** 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. + ** future releases. */ case PragTyp_OPTIMIZE: { int iDbLast; /* Loop termination point for the schema loop */ @@ -141216,13 +135758,9 @@ SQLITE_PRIVATE void 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 needed */ + LogEst szThreshold; /* Size threshold above which reanalysis is needd */ 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)sqlite3Atoi(zRight); @@ -141230,14 +135768,6 @@ SQLITE_PRIVATE void sqlite3Pragma( }else{ opMask = 0xfffe; } - if( (opMask & 0x10)==0 ){ - nLimit = 0; - }else if( db->nAnalysisLimit>0 - && db->nAnalysisLimitnTab++; for(iDbLast = zDb?iDb:db->nDb-1; iDb<=iDbLast; iDb++){ if( iDb==1 ) continue; @@ -141246,61 +135776,23 @@ SQLITE_PRIVATE void sqlite3Pragma( for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ pTab = (Table*)sqliteHashData(k); - /* This only works for ordinary tables */ - if( !IsOrdinaryTable(pTab) ) continue; - - /* Do not scan system tables */ - if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) ) continue; + /* 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; - /* 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; + /* Reanalyze if the table is 25 times larger than the last analysis */ + szThreshold = pTab->nRowLogEst + 46; assert( sqlite3LogEst(25)==46 ); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - nIndex++; if( !pIdx->hasStat1 ){ - szThreshold = -1; /* Always analyze if any index lacks statistics */ + szThreshold = 0; /* Always analyze if any index lacks statistics */ + break; } } - - /* 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 */ - 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. */ - sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead); - if( szThreshold>=0 ){ - const LogEst iRange = 33; /* 10x size change */ - sqlite3VdbeAddOp4Int(v, OP_IfSizeBetween, iTabCur, - sqlite3VdbeCurrentAddr(v)+2+(opMask&1), - szThreshold>=iRange ? szThreshold-iRange : -1, - szThreshold+iRange); - VdbeCoverage(v); - }else{ - sqlite3VdbeAddOp2(v, OP_Rewind, iTabCur, - sqlite3VdbeCurrentAddr(v)+2+(opMask&1)); + if( szThreshold ){ + sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead); + sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur, + sqlite3VdbeCurrentAddr(v)+2+(opMask&1), szThreshold); VdbeCoverage(v); } zSubSql = sqlite3MPrintf(db, "ANALYZE \"%w\".\"%w\"", @@ -141310,27 +135802,11 @@ SQLITE_PRIVATE void sqlite3Pragma( sqlite3VdbeAddOp4(v, OP_String8, 0, r1, 0, zSubSql, P4_DYNAMIC); sqlite3VdbeAddOp2(v, OP_ResultRow, r1, 1); }else{ - sqlite3VdbeAddOp4(v, OP_SqlExec, nLimit ? 0x02 : 00, nLimit, 0, - zSubSql, P4_DYNAMIC); + sqlite3VdbeAddOp4(v, OP_SqlExec, 0, 0, 0, zSubSql, P4_DYNAMIC); } } } 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 = sqlite3VdbeGetOp(v, 0); - iEnd = sqlite3VdbeCurrentAddr(v); - for(iAddr=0; iAddrnConstraint; i++, pConstraint++){ - if( pConstraint->iColumn < pTab->iHidden ) continue; + if( pConstraint->usable==0 ) continue; if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; - if( pConstraint->usable==0 ) return SQLITE_CONSTRAINT; + if( pConstraint->iColumn < pTab->iHidden ) continue; j = pConstraint->iColumn - pTab->iHidden; assert( j < 2 ); seen[j] = i+1; @@ -141609,13 +136085,12 @@ static int pragmaVtabBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ 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; - if( seen[1] ){ - j = seen[1]-1; - pIdxInfo->aConstraintUsage[j].argvIndex = 2; - pIdxInfo->aConstraintUsage[j].omit = 1; - } + j = seen[1]-1; + pIdxInfo->aConstraintUsage[j].argvIndex = 2; + pIdxInfo->aConstraintUsage[j].omit = 1; return SQLITE_OK; } @@ -141635,7 +136110,6 @@ static void pragmaVtabCursorClear(PragmaVtabCursor *pCsr){ int i; sqlite3_finalize(pCsr->pPragma); pCsr->pPragma = 0; - pCsr->iRowid = 0; for(i=0; iazArg); i++){ sqlite3_free(pCsr->azArg[i]); pCsr->azArg[i] = 0; @@ -141776,8 +136250,7 @@ static const sqlite3_module pragmaVtabModule = { 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - 0, /* xShadowName */ - 0 /* xIntegrity */ + 0 /* xShadowName */ }; /* @@ -142109,14 +136582,7 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl #else encoding = SQLITE_UTF8; #endif - if( db->nVdbeActive>0 && encoding!=ENC(db) - && (db->mDbFlags & DBFLAG_Vacuum)==0 - ){ - rc = SQLITE_LOCKED; - goto initone_error_out; - }else{ - sqlite3SetTextEncoding(db, encoding); - } + sqlite3SetTextEncoding(db, encoding); }else{ /* If opening an attached database, the encoding much match ENC(db) */ if( (meta[BTREE_TEXT_ENCODING-1] & 3)!=ENC(db) ){ @@ -142330,8 +136796,8 @@ static void schemaIsValid(Parse *pParse){ sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&cookie); assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( cookie!=db->aDb[iDb].pSchema->schema_cookie ){ - if( DbHasProperty(db, iDb, DB_SchemaLoaded) ) pParse->rc = SQLITE_SCHEMA; sqlite3ResetOneSchema(db, iDb); + pParse->rc = SQLITE_SCHEMA; } /* Close the transaction, if one was opened. */ @@ -142401,6 +136867,8 @@ SQLITE_PRIVATE void 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; } /* @@ -142409,7 +136877,7 @@ SQLITE_PRIVATE void sqlite3ParseObjectReset(Parse *pParse){ ** immediately. ** ** Use this mechanism for uncommon cleanups. There is a higher setup -** cost for this mechanism (an extra malloc), so it should not be used +** cost for this mechansim (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 ** sqlite3ParseObjectReset(), which reduces the total CPU cycle count. @@ -142436,13 +136904,7 @@ SQLITE_PRIVATE void *sqlite3ParserAddCleanup( void (*xCleanup)(sqlite3*,void*), /* The cleanup routine */ void *pPtr /* Pointer to object to be cleaned up */ ){ - ParseCleanup *pCleanup; - if( sqlite3FaultSim(300) ){ - pCleanup = 0; - sqlite3OomFault(pParse->db); - }else{ - pCleanup = sqlite3DbMallocRaw(pParse->db, sizeof(*pCleanup)); - } + ParseCleanup *pCleanup = sqlite3DbMallocRaw(pParse->db, sizeof(*pCleanup)); if( pCleanup ){ pCleanup->pNext = pParse->pCleanup; pParse->pCleanup = pCleanup; @@ -142507,18 +136969,9 @@ static int sqlite3Prepare( sParse.pOuterParse = db->pParse; db->pParse = &sParse; sParse.db = db; - if( pReprepare ){ - sParse.pReprepare = pReprepare; - sParse.explain = sqlite3_stmt_isexplain((sqlite3_stmt*)pReprepare); - }else{ - assert( sParse.pReprepare==0 ); - } + sParse.pReprepare = pReprepare; assert( ppStmt && *ppStmt==0 ); - if( db->mallocFailed ){ - sqlite3ErrorMsg(&sParse, "out of memory"); - db->errCode = rc = SQLITE_NOMEM; - goto end_prepare; - } + if( db->mallocFailed ) sqlite3ErrorMsg(&sParse, "out of memory"); assert( sqlite3_mutex_held(db->mutex) ); /* For a long-term use prepared statement avoid the use of @@ -142677,7 +137130,6 @@ static int sqlite3LockAndPrepare( assert( (rc&db->errMask)==rc ); db->busyHandler.nBusy = 0; sqlite3_mutex_leave(db->mutex); - assert( rc==SQLITE_OK || (*ppStmt)==0 ); return rc; } @@ -142956,10 +137408,6 @@ 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 */ @@ -143075,9 +137523,6 @@ SQLITE_PRIVATE Select *sqlite3SelectNew( SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){ if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1); } -SQLITE_PRIVATE void sqlite3SelectDeleteGeneric(sqlite3 *db, void *p){ - if( ALWAYS(p) ) clearSelect(db, (Select*)p, 1); -} /* ** Return a pointer to the right-most SELECT statement in a compound. @@ -143126,7 +137571,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 nonsensical join types. +** of other non-standard and in many cases non-sensical 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: @@ -143348,7 +137793,6 @@ 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; ix.pList->nExpr; i++){ @@ -143398,7 +137842,7 @@ static int 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 appropriate USING clause + /* If this is a NATURAL join, synthesize an approprate USING clause ** to specify which columns should be joined. */ if( pRight->fg.jointype & JT_NATURAL ){ @@ -143612,18 +138056,14 @@ 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_REFERENCES optimization, or due to the + ** the SQLITE_ENABLE_SORTER_REFERENCE optimization, or due to the ** SQLITE_ECEL_OMITREF optimization, or due to the - ** SortCtx.pDeferredRowLoad optimization. In any of these cases + ** SortCtx.pDeferredRowLoad optimiation. 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 = sqlite3VdbeCurrentAddr(v); -#endif - if( nPrefixReg ){ assert( nPrefixReg==nExpr+bSeq ); regBase = regData - nPrefixReg; @@ -143670,7 +138110,7 @@ static void pushOntoSorter( testcase( pKI->nAllField > pKI->nKeyField+2 ); pOp->p4.pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pSort->pOrderBy,nOBSat, pKI->nAllField-pKI->nKeyField-1); - pOp = 0; /* Ensure pOp not used after sqlite3VdbeAddOp3() */ + pOp = 0; /* Ensure pOp not used after sqltie3VdbeAddOp3() */ addrJmp = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v); pSort->labelBkOut = sqlite3VdbeMakeLabel(pParse); @@ -143724,9 +138164,6 @@ static void pushOntoSorter( sqlite3VdbeChangeP2(v, iSkip, pSort->labelOBLopt ? pSort->labelOBLopt : sqlite3VdbeCurrentAddr(v)); } -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS - pSort->addrPushEnd = sqlite3VdbeCurrentAddr(v)-1; -#endif } /* @@ -143764,7 +138201,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 ephemeral +** In this case rows are being delivered sorted order. The ephermal ** 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, @@ -144193,16 +138630,9 @@ static void selectInnerLoop( testcase( eDest==SRT_Fifo ); testcase( eDest==SRT_DistFifo ); 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 ){ - sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC); + if( pDest->zAffSdst ){ + sqlite3VdbeChangeP4(v, -1, pDest->zAffSdst, nResultCol); } -#endif #ifndef SQLITE_OMIT_CTE if( eDest==SRT_DistFifo ){ /* If the destination is DistFifo, then cursor (iParm+1) is open @@ -144560,23 +138990,6 @@ 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 - )); - } - sqlite3VdbeScanStatusRange(v, addrExplain,pSort->addrPush,pSort->addrPushEnd); - sqlite3VdbeScanStatusCounters(v, addrExplain, addrExplain, pSort->addrPush); - assert( addrBreak<0 ); if( pSort->labelBkOut ){ @@ -144611,6 +139024,7 @@ static void generateSortTail( regRow = sqlite3GetTempRange(pParse, nColumn); } } + nKey = pOrderBy->nExpr - pSort->nOBSat; if( pSort->sortFlags & SORTFLAG_UseSorter ){ int regSortOut = ++pParse->nMem; iSortTab = pParse->nTab++; @@ -144688,7 +139102,6 @@ static void generateSortTail( VdbeComment((v, "%s", aOutEx[i].zEName)); } } - sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1); switch( eDest ){ case SRT_Table: case SRT_EphemTab: { @@ -144750,7 +139163,6 @@ static void generateSortTail( }else{ sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v); } - sqlite3VdbeScanStatusRange(v, addrExplain, sqlite3VdbeCurrentAddr(v)-1, -1); if( pSort->regReturn ) sqlite3VdbeAddOp1(v, OP_Return, pSort->regReturn); sqlite3VdbeResolveLabel(v, addrBreak); } @@ -144850,7 +139262,11 @@ static const char *columnTypeImpl( ** data for the result-set column of the sub-select. */ if( iColpEList->nExpr - && (!ViewCanHaveRowid || iCol>=0) +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + && iCol>=0 +#else + && ALWAYS(iCol>=0) +#endif ){ /* If iCol is less than zero, then the expression requests the ** rowid of the sub-select or view. This expression is legal (see @@ -145008,10 +139424,17 @@ SQLITE_PRIVATE void 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; - TREETRACE(0x80,pParse,pSelect,("generating column names\n")); + SELECTTRACE(1,pParse,pSelect,("generating column names\n")); pTabList = pSelect->pSrc; pEList = pSelect->pEList; assert( v!=0 ); @@ -145111,7 +139534,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( *pnCol = nCol; *paCol = aCol; - for(i=0, pCol=aCol; inErr; i++, pCol++){ + for(i=0, pCol=aCol; imallocFailed; i++, pCol++){ struct ExprList_item *pX = &pEList->a[i]; struct ExprList_item *pCollide; /* Get an appropriate name for the column @@ -145161,10 +139584,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( if( zName[j]==':' ) nName = j; } zName = sqlite3MPrintf(db, "%.*z:%u", nName, zName, ++cnt); - sqlite3ProgressCheck(pParse); - if( cnt>3 ){ - sqlite3_randomness(sizeof(cnt), &cnt); - } + if( cnt>3 ) sqlite3_randomness(sizeof(cnt), &cnt); } pCol->zCnName = zName; pCol->hName = sqlite3StrIHash(zName); @@ -145177,109 +139597,71 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( } } sqlite3HashClear(&ht); - if( pParse->nErr ){ + if( db->mallocFailed ){ for(j=0; jrc; + return SQLITE_NOMEM_BKPT; } return SQLITE_OK; } /* -** 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: +** Add type and collation information to a column list based on +** a SELECT statement. ** -** * 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 +** 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. +** +** This routine requires that all identifiers in the SELECT +** statement be resolved. */ -SQLITE_PRIVATE void 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. */ +SQLITE_PRIVATE void 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 */ ){ sqlite3 *db = pParse->db; + NameContext sNC; Column *pCol; CollSeq *pColl; - int i,j; + int i; Expr *p; struct ExprList_item *a; - NameContext sNC; assert( pSelect!=0 ); 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 || IN_RENAME_OBJECT ) return; - while( pSelect->pPrior ) pSelect = pSelect->pPrior; - a = pSelect->pEList->a; + assert( pTab->nCol==pSelect->pEList->nExpr || db->mallocFailed ); + if( db->mallocFailed ) return; memset(&sNC, 0, sizeof(sNC)); sNC.pSrcList = pSelect->pSrc; + a = pSelect->pEList->a; for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ const char *zType; - i64 n; - int m = 0; - Select *pS2 = pSelect; + i64 n, m; 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 = sqlite3ExprAffinity(p); - while( pCol->affinity<=SQLITE_AFF_NONE && pS2->pNext!=0 ){ - m |= sqlite3ExprDataType(pS2->pEList->a[i].pExpr); - pS2 = pS2->pNext; - pCol->affinity = 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 |= 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!=sqlite3AffinityType(zType, 0) ){ - if( pCol->affinity==SQLITE_AFF_NUMERIC - || pCol->affinity==SQLITE_AFF_FLEXNUM - ){ - zType = "NUM"; - }else{ - zType = 0; - for(j=1; jaffinity ){ - zType = sqlite3StdType[j]; - break; - } - } - } - } if( zType ){ - const i64 k = sqlite3Strlen30(zType); + m = sqlite3Strlen30(zType); n = sqlite3Strlen30(pCol->zCnName); - pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+k+2); - pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL); + pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+m+2); if( pCol->zCnName ){ - memcpy(&pCol->zCnName[n+1], zType, k+1); + 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( pCol->affinity<=SQLITE_AFF_NONE ) pCol->affinity = aff; pColl = sqlite3ExprCollSeq(pParse, p); if( pColl ){ assert( pTab->pIndex==0 ); @@ -145313,7 +139695,7 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect, c pTab->zName = 0; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol); - sqlite3SubqueryColumnTypes(pParse, pTab, pSelect, aff); + sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect, aff); pTab->iPKey = -1; if( db->mallocFailed ){ sqlite3DeleteTable(db, pTab); @@ -145528,7 +139910,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 targeting the Queue table */ + SelectDest destQueue; /* SelectDest targetting the Queue table */ int i; /* Loop counter */ int rc; /* Result code */ ExprList *pOrderBy; /* The ORDER BY clause */ @@ -145838,7 +140220,7 @@ static int multiSelect( pPrior->iLimit = p->iLimit; pPrior->iOffset = p->iOffset; pPrior->pLimit = p->pLimit; - TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL left...\n")); + SELECTTRACE(1, pParse, p, ("multiSelect UNION ALL left...\n")); rc = sqlite3Select(pParse, pPrior, &dest); pPrior->pLimit = 0; if( rc ){ @@ -145856,7 +140238,7 @@ static int multiSelect( } } ExplainQueryPlan((pParse, 1, "UNION ALL")); - TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL right...\n")); + SELECTTRACE(1, pParse, p, ("multiSelect UNION ALL right...\n")); rc = sqlite3Select(pParse, p, &dest); testcase( rc!=SQLITE_OK ); pDelete = p->pPrior; @@ -145909,7 +140291,7 @@ static int multiSelect( */ assert( !pPrior->pOrderBy ); sqlite3SelectDestInit(&uniondest, priorOp, unionTab); - TREETRACE(0x200, pParse, p, ("multiSelect EXCEPT/UNION left...\n")); + SELECTTRACE(1, pParse, p, ("multiSelect EXCEPT/UNION left...\n")); rc = sqlite3Select(pParse, pPrior, &uniondest); if( rc ){ goto multi_select_end; @@ -145929,7 +140311,7 @@ static int multiSelect( uniondest.eDest = op; ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", sqlite3SelectOpName(p->op))); - TREETRACE(0x200, pParse, p, ("multiSelect EXCEPT/UNION right...\n")); + SELECTTRACE(1, pParse, p, ("multiSelect EXCEPT/UNION right...\n")); rc = sqlite3Select(pParse, p, &uniondest); testcase( rc!=SQLITE_OK ); assert( p->pOrderBy==0 ); @@ -145990,7 +140372,7 @@ static int multiSelect( /* Code the SELECTs to our left into temporary table "tab1". */ sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1); - TREETRACE(0x400, pParse, p, ("multiSelect INTERSECT left...\n")); + SELECTTRACE(1, pParse, p, ("multiSelect INTERSECT left...\n")); rc = sqlite3Select(pParse, pPrior, &intersectdest); if( rc ){ goto multi_select_end; @@ -146007,7 +140389,7 @@ static int multiSelect( intersectdest.iSDParm = tab2; ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", sqlite3SelectOpName(p->op))); - TREETRACE(0x400, pParse, p, ("multiSelect INTERSECT right...\n")); + SELECTTRACE(1, pParse, p, ("multiSelect INTERSECT right...\n")); rc = sqlite3Select(pParse, p, &intersectdest); testcase( rc!=SQLITE_OK ); pDelete = p->pPrior; @@ -146104,7 +140486,9 @@ multi_select_end: pDest->iSdst = dest.iSdst; pDest->nSdst = dest.nSdst; if( pDelete ){ - sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pDelete); + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3SelectDelete, + pDelete); } return rc; } @@ -146126,7 +140510,7 @@ SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p){ /* ** Code an output subroutine for a coroutine implementation of a -** SELECT statement. +** SELECT statment. ** ** The data to be output is contained in pIn->iSdst. There are ** pIn->nSdst columns to be output. pDest is where the output should @@ -146348,7 +140732,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" label. AltB, AeqB, +** until all data is exhausted then jump to the "end" labe. AltB, AeqB, ** and AgtB jump to either L2 or to one of EofA or EofB. */ #ifndef SQLITE_OMIT_COMPOUND_SELECT @@ -146385,7 +140769,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 retargeted */ + int addr1; /* Jump instructions that get retargetted */ int op; /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */ KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */ KeyInfo *pKeyMerge; /* Comparison information for merging rows */ @@ -146655,7 +141039,8 @@ static int multiSelectOrderBy( /* Make arrangements to free the 2nd and subsequent arms of the compound ** after the parse has finished */ if( pSplit->pPrior ){ - sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pSplit->pPrior); + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3SelectDelete, pSplit->pPrior); } pSplit->pPrior = pPrior; pPrior->pNext = pSplit; @@ -146753,21 +141138,16 @@ static Expr *substExpr( #endif { Expr *pNew; - int iColumn; - Expr *pCopy; + int iColumn = pExpr->iColumn; + Expr *pCopy = pSubst->pEList->a[iColumn].pExpr; Expr ifNullRow; - iColumn = pExpr->iColumn; - assert( iColumn>=0 ); assert( pSubst->pEList!=0 && iColumnpEList->nExpr ); assert( pExpr->pRight==0 ); - pCopy = pSubst->pEList->a[iColumn].pExpr; if( sqlite3ExprIsVector(pCopy) ){ sqlite3VectorErrorMsg(pSubst->pParse, pCopy); }else{ sqlite3 *db = pSubst->pParse->db; - if( pSubst->isOuterJoin - && (pCopy->op!=TK_COLUMN || pCopy->iTable!=pSubst->iNewTable) - ){ + if( pSubst->isOuterJoin && pCopy->op!=TK_COLUMN ){ memset(&ifNullRow, 0, sizeof(ifNullRow)); ifNullRow.op = TK_IF_NULL_ROW; ifNullRow.pLeft = pCopy; @@ -147013,34 +141393,6 @@ static ExprList *findLeftmostExprlist(Select *pSel){ 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; iinExpr; ii++){ - char aff; - Select *pSub1; - assert( pList->a[ii].pExpr!=0 ); - aff = 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( 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. @@ -147109,7 +141461,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 -** accidentally carried the comment forward until 2014-09-15. Original +** accidently carried the comment forward until 2014-09-15. Original ** constraint: "If the subquery is aggregate then the outer query ** may not use LIMIT." ** @@ -147201,8 +141553,7 @@ 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. (This is handled -** in the caller before ever reaching this routine.) +** (28) The subquery is not a MATERIALIZED CTE. ** ** ** In this routine, the "p" parameter is a pointer to the outer query. @@ -147312,9 +141663,9 @@ static int flattenSubquery( if( iFrom>0 && (pSubSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){ return 0; /* Restriction (27a) */ } - - /* Condition (28) is blocked by the caller */ - assert( !pSubitem->fg.isCte || pSubitem->u2.pCteUse->eM10d!=M10d_Yes ); + if( pSubitem->fg.isCte && pSubitem->u2.pCteUse->eM10d==M10d_Yes ){ + return 0; /* (28) */ + } /* 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 @@ -147364,7 +141715,19 @@ static int flattenSubquery( if( (p->selFlags & SF_Recursive) ) return 0; /* Restriction (17h) */ - if( compoundHasDifferentAffinities(pSub) ) return 0; + for(ii=0; iipEList->nExpr; ii++){ + char aff; + assert( pSub->pEList->a[ii].pExpr!=0 ); + aff = sqlite3ExprAffinity(pSub->pEList->a[ii].pExpr); + for(pSub1=pSub->pPrior; pSub1; pSub1=pSub1->pPrior){ + assert( pSub1->pEList!=0 ); + assert( pSub1->pEList->nExpr>ii ); + assert( pSub1->pEList->a[ii].pExpr!=0 ); + if( sqlite3ExprAffinity(pSub1->pEList->a[ii].pExpr)!=aff ){ + return 0; + } + } + } if( pSrc->nSrc>1 ){ if( pParse->nSelect>500 ) return 0; @@ -147375,7 +141738,7 @@ static int flattenSubquery( } /***** If we reach this point, flattening is permitted. *****/ - TREETRACE(0x4,pParse,p,("flatten %u.%p from term %d\n", + SELECTTRACE(1,pParse,p,("flatten %u.%p from term %d\n", pSub->selId, pSub, iFrom)); /* Authorize the subquery */ @@ -147384,7 +141747,7 @@ static int flattenSubquery( testcase( i==SQLITE_DENY ); pParse->zAuthContext = zSavedAuthContext; - /* Delete the transient structures associated with the subquery */ + /* Delete the transient structures associated with thesubquery */ pSub1 = pSubitem->pSelect; sqlite3DbFree(db, pSubitem->zDatabase); sqlite3DbFree(db, pSubitem->zName); @@ -147454,7 +141817,7 @@ static int flattenSubquery( if( pPrior ) pPrior->pNext = pNew; pNew->pNext = p; p->pPrior = pNew; - TREETRACE(0x4,pParse,p,("compound-subquery flattener" + SELECTTRACE(2,pParse,p,("compound-subquery flattener" " creates %u as peer\n",pNew->selId)); } assert( pSubitem->pSelect==0 ); @@ -147476,7 +141839,9 @@ static int flattenSubquery( Table *pTabToDel = pSubitem->pTab; if( pTabToDel->nTabRef==1 ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); - sqlite3ParserAddCleanup(pToplevel, sqlite3DeleteTableGeneric, pTabToDel); + sqlite3ParserAddCleanup(pToplevel, + (void(*)(sqlite3*,void*))sqlite3DeleteTable, + pTabToDel); testcase( pToplevel->earlyCleanup ); }else{ pTabToDel->nTabRef--; @@ -147564,7 +141929,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 transferring the ORDER BY clause. + ** zero them before transfering 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 @@ -147624,15 +141989,16 @@ static int flattenSubquery( } } - /* Finally, delete what is left of the subquery and return success. + /* Finially, delete what is left of the subquery and return + ** success. */ sqlite3AggInfoPersistWalkerInit(&w, pParse); sqlite3WalkSelect(&w,pSub1); sqlite3SelectDelete(db, pSub1); #if TREETRACE_ENABLED - if( sqlite3TreeTrace & 0x4 ){ - TREETRACE(0x4,pParse,p,("After flattening:\n")); + if( sqlite3TreeTrace & 0x100 ){ + SELECTTRACE(0x100,pParse,p,("After flattening:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif @@ -147659,7 +142025,7 @@ struct WhereConst { /* ** Add a new entry to the pConst object. Except, do not add duplicate -** pColumn entries. Also, do not add if doing so would not be appropriate. +** pColumn entires. 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 @@ -147673,7 +142039,7 @@ static void constInsert( ){ int i; assert( pColumn->op==TK_COLUMN ); - assert( sqlite3ExprIsConstant(pConst->pParse, pValue) ); + assert( sqlite3ExprIsConstant(pValue) ); if( ExprHasProperty(pColumn, EP_FixedCol) ) return; if( sqlite3ExprAffinity(pValue)!=0 ) return; @@ -147731,10 +142097,10 @@ static void findConstInWhere(WhereConst *pConst, Expr *pExpr){ pLeft = pExpr->pLeft; assert( pRight!=0 ); assert( pLeft!=0 ); - if( pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pConst->pParse, pLeft) ){ + if( pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pLeft) ){ constInsert(pConst,pRight,pLeft,pExpr); } - if( pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pConst->pParse, pRight) ){ + if( pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pRight) ){ constInsert(pConst,pLeft,pRight,pExpr); } } @@ -147845,7 +142211,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 always true because the comparison uses numeric affinity, but b=123 +** is alway 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 @@ -147929,7 +142295,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 clause. +** * that the window frame has a PARTITION BY clase. */ static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){ assert( pSubq->pWin->pPartition ); @@ -147955,18 +142321,6 @@ 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 @@ -148018,32 +142372,12 @@ 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 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. +** (8) The subquery may not be a compound that uses UNION, INTERSECT, +** or EXCEPT. (We could, perhaps, relax this restriction to allow +** this case if none of the comparisons operators between left and +** right arms of the compound use a collation other than BINARY. +** But it is a lot of work to check that case for an obscure and +** minor optimization, so we omit it for now.) ** ** Return 0 if no changes are made and non-zero if one or more WHERE clause ** terms are duplicated into the subquery. @@ -148052,56 +142386,28 @@ 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 */ - SrcList *pSrcList, /* The complete from clause of the outer query */ - int iSrc /* Which FROM clause term to try to push into */ + SrcItem *pSrc /* The subquery term of the outer FROM clause */ ){ 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; /* restrictions (2) and (11) */ - } - if( pSrc->fg.jointype & (JT_LTORJ|JT_RIGHT) ){ - return 0; /* restrictions (10) */ - } + if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ) return 0; + if( pSrc->fg.jointype & (JT_LTORJ|JT_RIGHT) ) return 0; +#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( op!=TK_ALL && op!=TK_SELECT ) return 0; /* restriction (8) */ 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; iinExpr; ii++){ - CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[ii].pExpr); - if( !sqlite3IsBinary(pColl) ){ - return 0; /* Restriction (8) */ - } - } - } } }else{ -#ifndef SQLITE_OMIT_WINDOWFUNC if( pSubq->pWin && pSubq->pWin->pPartition==0 ) return 0; -#endif } +#endif #ifdef SQLITE_DEBUG /* Only the first term of a compound can have a WITH clause. But make @@ -148120,28 +142426,11 @@ static int pushDownWhereTerms( return 0; /* restriction (3) */ } while( pWhere->op==TK_AND ){ - nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, pSrcList, iSrc); + nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, pSrc); pWhere = pWhere->pLeft; } -#if 0 /* These checks now done by 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; jjw.iJoin==pSrcList->a[jj].iCursor ){ - /* If we reach this point, both (9a) and (9b) are satisfied. - ** The following loop checks (9c): - */ - for(jj++; jja[jj].fg.jointype & JT_RIGHT)!=0 ){ - return 0; /* restriction (9) */ - } - } - } - } - } +#if 0 /* Legacy code. Checks now done by sqlite3ExprIsTableConstraint() */ if( isLeftJoin && (ExprHasProperty(pWhere,EP_OuterON)==0 || pWhere->w.iJoin!=iCursor) @@ -148155,19 +142444,7 @@ static int pushDownWhereTerms( } #endif -#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( sqlite3ExprIsSingleTableConstraint(pWhere, pSrcList, iSrc, 1) ){ + if( sqlite3ExprIsTableConstraint(pWhere, pSrc) ){ nChng++; pSubq->selFlags |= SF_PushDown; while( pSubq ){ @@ -148201,78 +142478,6 @@ 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; jnExpr; 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; jpPrior) { - 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. @@ -148551,7 +142756,8 @@ static struct Cte *searchWith( SQLITE_PRIVATE With *sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){ if( pWith ){ if( bFree ){ - pWith = (With*)sqlite3ParserAddCleanup(pParse, sqlite3WithDeleteGeneric, + pWith = (With*)sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3WithDelete, pWith); if( pWith==0 ) return 0; } @@ -148663,6 +142869,9 @@ 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; @@ -148794,14 +143003,12 @@ SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){ while( pSel->pPrior ){ pSel = pSel->pPrior; } sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol); pTab->iPKey = -1; - pTab->eTabType = TABTYP_VIEW; pTab->nRowLogEst = 200; assert( 200==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 - /* Legacy compatibility mode */ - pTab->tabFlags |= TF_Ephemeral | sqlite3Config.mNoVisibleRowid; + pTab->tabFlags |= TF_Ephemeral; /* Legacy compatibility mode */ #endif return pParse->nErr ? SQLITE_ERROR : SQLITE_OK; } @@ -149038,20 +143245,12 @@ 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; inSrc; 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 */ @@ -149069,7 +143268,6 @@ 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 && sqlite3StrICmp(zTName, zTabName)!=0 ){ continue; @@ -149087,7 +143285,6 @@ static int selectExpander(Walker *pWalker, Select *p){ for(ii=0; iinId; ii++){ const char *zUName = pUsing->a[ii].zName; pRight = sqlite3Expr(db, TK_ID, zUName); - sqlite3ExprSetErrorOffset(pRight, iErrOfst); pNew = sqlite3ExprListAppend(pParse, pNew, pRight); if( pNew ){ struct ExprList_item *pX = &pNew->a[pNew->nExpr-1]; @@ -149100,49 +143297,33 @@ static int selectExpander(Walker *pWalker, Select *p){ }else{ pUsing = 0; } - - nAdd = pTab->nCol; - if( VisibleRowid(pTab) && (selFlags & SF_NestedFrom)!=0 ) nAdd++; - for(j=0; jnCol; j++){ + char *zName = pTab->aCol[j].zCnName; struct ExprList_item *pX; /* Newly added ExprList term */ - if( j==pTab->nCol ){ - zName = sqlite3RowidAlias(pTab); - if( zName==0 ) continue; - }else{ - zName = pTab->aCol[j].zCnName; - - /* 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 - && sqlite3MatchEName(&pNestedFrom->a[j], 0, zTName, 0, 0)==0 - ){ - continue; - } + assert( zName ); + if( zTName + && pNestedFrom + && sqlite3MatchEName(&pNestedFrom->a[j], 0, zTName, 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; - } + /* 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 ){ @@ -149176,7 +143357,6 @@ static int selectExpander(Walker *pWalker, Select *p){ }else{ pExpr = pRight; } - sqlite3ExprSetErrorOffset(pExpr, iErrOfst); pNew = sqlite3ExprListAppend(pParse, pNew, pExpr); if( pNew==0 ){ break; /* OOM */ @@ -149184,8 +143364,7 @@ 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 && (!ViewCanHaveRowid || jnExpr) ){ - assert( jnExpr ); + if( pNestedFrom ){ pX->zEName = sqlite3DbStrDup(db, pNestedFrom->a[j].zEName); testcase( pX->zEName==0 ); }else{ @@ -149193,11 +143372,11 @@ static int selectExpander(Walker *pWalker, Select *p){ zSchemaName, zTabName, zName); testcase( pX->zEName==0 ); } - pX->fg.eEName = (j==pTab->nCol ? ENAME_ROWID : ENAME_TAB); + pX->fg.eEName = ENAME_TAB; if( (pFrom->fg.isUsing && sqlite3IdListIndex(pFrom->u3.pUsing, zName)>=0) || (pUsing && sqlite3IdListIndex(pUsing, zName)>=0) - || (jnCol && (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)) + || (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0 ){ pX->fg.bNoExpand = 1; } @@ -149232,8 +143411,8 @@ static int selectExpander(Walker *pWalker, Select *p){ } } #if TREETRACE_ENABLED - if( sqlite3TreeTrace & 0x8 ){ - TREETRACE(0x8,pParse,p,("After result-set wildcard expansion:\n")); + if( sqlite3TreeTrace & 0x100 ){ + SELECTTRACE(0x100,pParse,p,("After result-set wildcard expansion:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif @@ -149284,14 +143463,14 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){ ** This is a Walker.xSelectCallback callback for the sqlite3SelectTypeInfo() ** interface. ** -** 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. +** For each FROM-clause subquery, add Column.zType and Column.zColl +** 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 and affinity 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 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; @@ -149299,10 +143478,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; inSrc; i++, pFrom++){ Table *pTab = pFrom->pTab; @@ -149311,7 +143490,9 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ /* A sub-query in the FROM clause of a SELECT */ Select *pSel = pFrom->pSelect; if( pSel ){ - sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE); + while( pSel->pPrior ) pSel = pSel->pPrior; + sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel, + SQLITE_AFF_NONE); } } } @@ -149366,186 +143547,6 @@ SQLITE_PRIVATE void sqlite3SelectPrep( sqlite3SelectAddTypeInfo(pParse, p); } -#if TREETRACE_ENABLED -/* -** Display all information about an AggInfo object -*/ -static void printAggInfo(AggInfo *pAggInfo){ - int ii; - sqlite3DebugPrintf("AggInfo %d/%p:\n", - pAggInfo->selId, pAggInfo); - for(ii=0; iinColumn; ii++){ - struct AggInfo_col *pCol = &pAggInfo->aCol[ii]; - 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"); - sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0); - } - for(ii=0; iinFunc; ii++){ - sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n", - ii, pAggInfo->iFirstReg+pAggInfo->nColumn+ii); - 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; inFunc; i++){ - Expr *pExpr = pAggInfo->aFunc[i].pFExpr; - assert( pExpr->op==TK_FUNCTION || pExpr->op==TK_AGG_FUNCTION ); - assert( ExprUseXList(pExpr) ); - sqlite3ExprAnalyzeAggList(pNC, pExpr->x.pList); - if( pExpr->pLeft ){ - assert( pExpr->pLeft->op==TK_ORDER ); - assert( ExprUseXList(pExpr->pLeft) ); - sqlite3ExprAnalyzeAggList(pNC, pExpr->pLeft->x.pList); - } -#ifndef SQLITE_OMIT_WINDOWFUNC - assert( !IsWindowFunc(pExpr) ); - if( ExprHasProperty(pExpr, EP_WinFunc) ){ - 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; jnColumn; j++){ - k = pAggInfo->aCol[j].iSorterColumn; - if( k>mx ) mx = k; - } - pAggInfo->nSortingColumn = mx+1; - } - analyzeAggFuncArgs(pAggInfo, pNC); -#if TREETRACE_ENABLED - if( sqlite3TreeTrace & 0x20 ){ - IndexedExpr *pIEpr; - TREETRACE(0x20, pParse, pSelect, - ("AggInfo (possibly) adjusted for Indexed Exprs\n")); - 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); - 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; inFunc; i++){ - 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. ** @@ -149559,13 +143560,24 @@ 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; - sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->iFirstReg, - pAggInfo->iFirstReg+nReg-1); +#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; inColumn; i++){ + assert( pAggInfo->aCol[i].iMem>=pAggInfo->mnReg + && pAggInfo->aCol[i].iMem<=pAggInfo->mxReg ); + } + for(i=0; inFunc; i++){ + assert( pAggInfo->aFunc[i].iMem>=pAggInfo->mnReg + && pAggInfo->aFunc[i].iMem<=pAggInfo->mxReg ); + } +#endif + sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->mnReg, pAggInfo->mxReg); for(pFunc=pAggInfo->aFunc, i=0; inFunc; i++, pFunc++){ if( pFunc->iDistinct>=0 ){ Expr *pE = pFunc->pFExpr; @@ -149582,36 +143594,6 @@ 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 = sqlite3KeyInfoFromExprList(pParse, pOBList, 0, nExtra); - if( !pFunc->bOBUnique && pParse->nErr==0 ){ - pKeyInfo->nKeyField++; - } - 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)); - } } } @@ -149627,71 +143609,20 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ ExprList *pList; assert( ExprUseXList(pF->pFExpr) ); 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 = 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 = sqlite3VdbeAddOp1(v, OP_Rewind, pF->iOBTab); VdbeCoverage(v); - for(j=nArg-1; j>=0; j--){ - sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, nKey+j, regAgg+j); - } - if( pF->bUseSubtype ){ - int regSubtype = sqlite3GetTempReg(pParse); - int iBaseCol = nKey + nArg + (pF->bOBPayload==0 && pF->bOBUnique==0); - for(j=nArg-1; j>=0; j--){ - sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, iBaseCol+j, regSubtype); - sqlite3VdbeAddOp2(v, OP_SetSubtype, regSubtype, regAgg+j); - } - sqlite3ReleaseTempReg(pParse, regSubtype); - } - sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i)); - sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); - sqlite3VdbeChangeP5(v, (u8)nArg); - sqlite3VdbeAddOp2(v, OP_Next, pF->iOBTab, iTop+1); VdbeCoverage(v); - sqlite3VdbeJumpHere(v, iTop); - sqlite3ReleaseTempRange(pParse, regAgg, nArg); - } - sqlite3VdbeAddOp2(v, OP_AggFinal, AggInfoFuncReg(pAggInfo,i), - pList ? pList->nExpr : 0); + sqlite3VdbeAddOp2(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); } } + /* -** Generate code that will update the accumulator memory cells for an -** aggregate based on the current cursor position. +** 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, @@ -149706,19 +143637,14 @@ 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; inFunc; 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; @@ -149742,55 +143668,9 @@ static void updateAccumulator( addrNext = sqlite3VdbeMakeLabel(pParse); sqlite3ExprIfFalse(pParse, pFilter, addrNext, SQLITE_JUMPIFNULL); } - 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 = sqlite3GetTempRange(pParse, regAggSz); - regDistinct = regAgg; - sqlite3ExprCodeExprList(pParse, pOBList, regAgg, 0, SQLITE_ECEL_DUP); - jj = pOBList->nExpr; - if( !pF->bOBUnique ){ - sqlite3VdbeAddOp2(v, OP_Sequence, pF->iOBTab, regAgg+jj); - jj++; - } - if( pF->bOBPayload ){ - regDistinct = regAgg+jj; - sqlite3ExprCodeExprList(pParse, pList, regDistinct, 0, SQLITE_ECEL_DUP); - jj += nArg; - } - if( pF->bUseSubtype ){ - int kk; - int regBase = pF->bOBPayload ? regDistinct : regAgg; - for(kk=0; kknExpr; regAgg = sqlite3GetTempRange(pParse, nArg); - regDistinct = regAgg; sqlite3ExprCodeExprList(pParse, pList, regAgg, 0, SQLITE_ECEL_DUP); }else{ nArg = 0; @@ -149801,37 +143681,26 @@ static void updateAccumulator( addrNext = sqlite3VdbeMakeLabel(pParse); } pF->iDistinct = codeDistinct(pParse, eDistinctType, - pF->iDistinct, addrNext, pList, regDistinct); - } - if( pF->iOBTab>=0 ){ - /* Insert a new record into the ORDER BY table */ - sqlite3VdbeAddOp3(v, OP_MakeRecord, regAgg, regAggSz-1, - regAgg+regAggSz-1); - sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pF->iOBTab, regAgg+regAggSz-1, - regAgg, regAggSz-1); - 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 && jpExpr); - } - if( !pColl ){ - pColl = pParse->db->pDfltColl; - } - if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem; - sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, - (char *)pColl, P4_COLLSEQ); + 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 && jpExpr); } - sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i)); - sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); - sqlite3VdbeChangeP5(v, (u8)nArg); - sqlite3ReleaseTempRange(pParse, regAgg, nArg); + if( !pColl ){ + pColl = pParse->db->pDfltColl; + } + if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem; + sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ); } + sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, pF->iMem); + sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); + sqlite3VdbeChangeP5(v, (u8)nArg); + sqlite3ReleaseTempRange(pParse, regAgg, nArg); if( addrNext ){ sqlite3VdbeResolveLabel(v, addrNext); } @@ -149843,7 +143712,7 @@ static void updateAccumulator( addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v); } for(i=0, pC=pAggInfo->aCol; inAccumulator; i++, pC++){ - sqlite3ExprCode(pParse, pC->pCExpr, AggInfoColumnReg(pAggInfo,i)); + sqlite3ExprCode(pParse, pC->pCExpr, pC->iMem); } pAggInfo->directMode = 0; @@ -149939,31 +143808,26 @@ static void havingToWhere(Parse *pParse, Select *p){ sqlite3WalkExpr(&sWalker, p->pHaving); #if TREETRACE_ENABLED if( sWalker.eCode && (sqlite3TreeTrace & 0x100)!=0 ){ - TREETRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n")); + SELECTTRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif } /* -** 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. +** Check to see if the pThis entry of pTabList is a self-join of a prior view. +** If it is, then return the SrcItem for the prior view. If it is not, +** 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 */ - int iFirst, int iEnd /* Range of FROM-clause entries to search. */ + SrcItem *pThis /* Search for prior reference to this subquery */ ){ SrcItem *pItem; assert( pThis->pSelect!=0 ); if( pThis->pSelect->selFlags & SF_PushDown ) return 0; - while( iFirsta; pItema[iFirst++]; if( pItem->pSelect==0 ) continue; if( pItem->fg.viaCoroutine ) continue; if( pItem->zName==0 ) continue; @@ -149990,13 +143854,13 @@ static SrcItem *isSelfJoinView( /* ** Deallocate a single AggInfo object */ -static void agginfoFree(sqlite3 *db, void *pArg){ - AggInfo *p = (AggInfo*)pArg; +static void agginfoFree(sqlite3 *db, AggInfo *p){ sqlite3DbFree(db, p->aCol); sqlite3DbFree(db, p->aFunc); sqlite3DbFreeNN(db, p); } +#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION /* ** Attempt to transform a query of the form ** @@ -150024,9 +143888,7 @@ 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) ); @@ -150034,18 +143896,15 @@ 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 */ - if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */ + if( pSub->pPrior==0 ) return 0; /* Must be a compound ry */ 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 */ - assert( pSub->pHaving==0 ); /* Due to the previous */ - pSub = pSub->pPrior; /* Repeat over compound */ + pSub = pSub->pPrior; /* Repeat over compound */ }while( pSub ); /* If we reach this point then it is OK to perform the transformation */ @@ -150065,7 +143924,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ pSub->selFlags |= SF_Aggregate; pSub->selFlags &= ~SF_Compound; pSub->nSelectRow = 0; - sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pSub->pEList); + sqlite3ExprListDelete(db, pSub->pEList); pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount; pSub->pEList = sqlite3ExprListAppend(pParse, 0, pTerm); pTerm = sqlite3PExpr(pParse, TK_SELECT, 0, 0); @@ -150081,13 +143940,14 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ p->selFlags &= ~SF_Aggregate; #if TREETRACE_ENABLED - if( sqlite3TreeTrace & 0x200 ){ - TREETRACE(0x200,pParse,p,("After count-of-view optimization:\n")); + if( sqlite3TreeTrace & 0x400 ){ + SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n")); 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 @@ -150112,68 +143972,6 @@ static int sameSrcAlias(SrcItem *p0, SrcList *pSrc){ return 0; } -/* -** 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 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. ** @@ -150219,8 +144017,8 @@ SQLITE_PRIVATE int sqlite3Select( assert( db->mallocFailed==0 ); if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; #if TREETRACE_ENABLED - TREETRACE(0x1,pParse,p, ("begin processing:\n", pParse->addrExplain)); - if( sqlite3TreeTrace & 0x10000 ){ + SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain)); + if( sqlite3TreeTrace & 0x10100 ){ if( (sqlite3TreeTrace & 0x10001)==0x10000 ){ sqlite3TreeViewLine(0, "In sqlite3Select() at %s:%d", __FILE__, __LINE__); @@ -150240,13 +144038,14 @@ SQLITE_PRIVATE int sqlite3Select( /* All of these destinations are also able to ignore the ORDER BY clause */ if( p->pOrderBy ){ #if TREETRACE_ENABLED - TREETRACE(0x800,pParse,p, ("dropping superfluous ORDER BY:\n")); - if( sqlite3TreeTrace & 0x800 ){ + SELECTTRACE(1,pParse,p, ("dropping superfluous ORDER BY:\n")); + if( sqlite3TreeTrace & 0x100 ){ sqlite3TreeViewExprList(0, p->pOrderBy, 0, "ORDERBY"); } #endif - sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, - p->pOrderBy); + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3ExprListDelete, + p->pOrderBy); testcase( pParse->earlyCleanup ); p->pOrderBy = 0; } @@ -150260,8 +144059,8 @@ SQLITE_PRIVATE int sqlite3Select( assert( db->mallocFailed==0 ); assert( p->pEList!=0 ); #if TREETRACE_ENABLED - if( sqlite3TreeTrace & 0x10 ){ - TREETRACE(0x10,pParse,p, ("after name resolution:\n")); + if( sqlite3TreeTrace & 0x104 ){ + SELECTTRACE(0x104,pParse,p, ("after name resolution:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif @@ -150302,8 +144101,8 @@ SQLITE_PRIVATE int sqlite3Select( goto select_end; } #if TREETRACE_ENABLED - if( p->pWin && (sqlite3TreeTrace & 0x40)!=0 ){ - TREETRACE(0x40,pParse,p, ("after window rewrite:\n")); + if( p->pWin && (sqlite3TreeTrace & 0x108)!=0 ){ + SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif @@ -150327,58 +144126,22 @@ SQLITE_PRIVATE int sqlite3Select( ** to a real table */ assert( pTab!=0 ); - /* 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. + /* Convert LEFT JOIN into JOIN if there are terms of the right table + ** of the LEFT JOIN used in the WHERE clause. */ - if( (pItem->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 - && sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor, - pItem->fg.jointype & JT_LTORJ) + if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==JT_LEFT + && sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor) && OptimizationEnabled(db, SQLITE_SimplifyJoin) ){ - 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; jnSrc; 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; - } - } + 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); } - /* No further action if this term of the FROM clause is not a subquery */ + /* No futher action if this term of the FROM clause is no a subquery */ if( pSub==0 ) continue; /* Catch mismatch in the declared columns of a view and the number of @@ -150389,14 +144152,6 @@ SQLITE_PRIVATE int 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 @@ -150426,8 +144181,6 @@ SQLITE_PRIVATE int 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) */ @@ -150436,10 +144189,11 @@ SQLITE_PRIVATE int sqlite3Select( && (p->selFlags & SF_OrderByReqd)==0 /* Condition (3) and (4) */ && OptimizationEnabled(db, SQLITE_OmitOrderBy) ){ - TREETRACE(0x800,pParse,p, + SELECTTRACE(0x100,pParse,p, ("omit superfluous ORDER BY on %r FROM-clause subquery\n",i+1)); - sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, - pSub->pOrderBy); + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3ExprListDelete, + pSub->pOrderBy); pSub->pOrderBy = 0; } @@ -150490,8 +144244,8 @@ SQLITE_PRIVATE int sqlite3Select( if( p->pPrior ){ rc = multiSelect(pParse, p, pDest); #if TREETRACE_ENABLED - TREETRACE(0x400,pParse,p,("end compound-select processing\n")); - if( (sqlite3TreeTrace & 0x400)!=0 && ExplainQueryPlanParent(pParse)==0 ){ + SELECTTRACE(0x1,pParse,p,("end compound-select processing\n")); + if( (sqlite3TreeTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){ sqlite3TreeViewSelect(0, p, 0); } #endif @@ -150511,21 +144265,24 @@ SQLITE_PRIVATE int sqlite3Select( && propagateConstants(pParse, p) ){ #if TREETRACE_ENABLED - if( sqlite3TreeTrace & 0x2000 ){ - TREETRACE(0x2000,pParse,p,("After constant propagation:\n")); + if( sqlite3TreeTrace & 0x100 ){ + SELECTTRACE(0x100,pParse,p,("After constant propagation:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif }else{ - TREETRACE(0x2000,pParse,p,("Constant propagation not helpful\n")); + SELECTTRACE(0x100,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 @@ -150564,7 +144321,7 @@ SQLITE_PRIVATE int sqlite3Select( /* Generate code for all sub-queries in the FROM clause */ pSub = pItem->pSelect; - if( pSub==0 || pItem->addrFillSub!=0 ) continue; + if( pSub==0 ) continue; /* The code for a subquery should only be generated once. */ assert( pItem->addrFillSub==0 ); @@ -150584,42 +144341,39 @@ SQLITE_PRIVATE int 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, pTabList, i) + && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem) ){ #if TREETRACE_ENABLED - if( sqlite3TreeTrace & 0x4000 ){ - TREETRACE(0x4000,pParse,p, + if( sqlite3TreeTrace & 0x100 ){ + SELECTTRACE(0x100,pParse,p, ("After WHERE-clause push-down into subquery %d:\n", pSub->selId)); sqlite3TreeViewSelect(0, p, 0); } #endif assert( pItem->pSelect && (pItem->pSelect->selFlags & SF_PushDown)!=0 ); }else{ - 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( sqlite3TreeTrace & 0x4000 ){ - TREETRACE(0x4000,pParse,p, - ("Change unused result columns to NULL for subquery %d:\n", - pSub->selId)); - sqlite3TreeViewSelect(0, p, 0); - } -#endif + SELECTTRACE(0x100,pParse,p,("Push-down not possible\n")); } 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( fromClauseTermCanBeCoroutine(pParse, pTabList, i, p->selFlags) ){ + 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) */ + ){ /* Implement a co-routine that will return a single row of the result ** set on each invocation. */ @@ -150641,7 +144395,7 @@ SQLITE_PRIVATE int 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 ephemeral table that + ** the make the pItem->iCursor be a copy of the ephemerial table that ** holds the result of the materialization. */ CteUse *pCteUse = pItem->u2.pCteUse; sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e); @@ -150650,7 +144404,7 @@ SQLITE_PRIVATE int sqlite3Select( VdbeComment((v, "%!S", pItem)); } pSub->nSelectRow = pCteUse->nRowEst; - }else if( (pPrior = isSelfJoinView(pTabList, pItem, 0, i))!=0 ){ + }else if( (pPrior = isSelfJoinView(pTabList, pItem))!=0 ){ /* This view has already been materialized by a prior entry in ** this same FROM clause. Reuse it. */ if( pPrior->addrFillSub ){ @@ -150664,9 +144418,6 @@ SQLITE_PRIVATE int 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 = sqlite3VdbeAddOp0(v, OP_Goto); @@ -150682,14 +144433,15 @@ SQLITE_PRIVATE int sqlite3Select( VdbeNoopComment((v, "materialize %!S", pItem)); } sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); - - ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem)); + ExplainQueryPlan((pParse, 1, "MATERIALIZE %!S", pItem)); + dest.zAffSdst = sqlite3TableAffinityStr(db, pItem->pTab); sqlite3Select(pParse, pSub, &dest); + sqlite3DbFree(db, dest.zAffSdst); + dest.zAffSdst = 0; pItem->pTab->nRowLogEst = pSub->nSelectRow; if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1); VdbeComment((v, "end %!S", pItem)); - sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1); sqlite3VdbeJumpHere(v, topAddr); sqlite3ClearTempRegCache(pParse); if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){ @@ -150715,8 +144467,8 @@ SQLITE_PRIVATE int sqlite3Select( sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0; #if TREETRACE_ENABLED - if( sqlite3TreeTrace & 0x8000 ){ - TREETRACE(0x8000,pParse,p,("After all FROM-clause analysis:\n")); + if( sqlite3TreeTrace & 0x400 ){ + SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif @@ -150752,8 +144504,8 @@ SQLITE_PRIVATE int sqlite3Select( sDistinct.isTnct = 2; #if TREETRACE_ENABLED - if( sqlite3TreeTrace & 0x20000 ){ - TREETRACE(0x20000,pParse,p,("Transform DISTINCT into GROUP BY:\n")); + if( sqlite3TreeTrace & 0x400 ){ + SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif @@ -150839,7 +144591,7 @@ SQLITE_PRIVATE int sqlite3Select( /* Begin the database scan. */ - TREETRACE(0x2,pParse,p,("WhereBegin\n")); + SELECTTRACE(1,pParse,p,("WhereBegin\n")); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy, p->pEList, p, wctrlFlags, p->nSelectRow); if( pWInfo==0 ) goto select_end; @@ -150856,7 +144608,7 @@ SQLITE_PRIVATE int sqlite3Select( sSort.pOrderBy = 0; } } - TREETRACE(0x2,pParse,p,("WhereBegin returns\n")); + SELECTTRACE(1,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 @@ -150895,7 +144647,7 @@ SQLITE_PRIVATE int sqlite3Select( /* End the database scan loop. */ - TREETRACE(0x2,pParse,p,("WhereEnd\n")); + SELECTTRACE(1,pParse,p,("WhereEnd\n")); sqlite3WhereEnd(pWInfo); } }else{ @@ -150968,21 +144720,20 @@ SQLITE_PRIVATE int sqlite3Select( */ pAggInfo = sqlite3DbMallocZero(db, sizeof(*pAggInfo) ); if( pAggInfo ){ - sqlite3ParserAddCleanup(pParse, agginfoFree, pAggInfo); + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))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; sqlite3ExprAnalyzeAggList(&sNC, pEList); @@ -151003,17 +144754,45 @@ SQLITE_PRIVATE int sqlite3Select( }else{ minMaxFlag = WHERE_ORDERBY_NORMAL; } - analyzeAggFuncArgs(pAggInfo, &sNC); + for(i=0; inFunc; i++){ + Expr *pExpr = pAggInfo->aFunc[i].pFExpr; + assert( ExprUseXList(pExpr) ); + sNC.ncFlags |= NC_InAggFunc; + sqlite3ExprAnalyzeAggList(&sNC, pExpr->x.pList); +#ifndef SQLITE_OMIT_WINDOWFUNC + assert( !IsWindowFunc(pExpr) ); + if( ExprHasProperty(pExpr, EP_WinFunc) ){ + sqlite3ExprAnalyzeAggregates(&sNC, pExpr->y.pWin->pFilter); + } +#endif + sNC.ncFlags &= ~NC_InAggFunc; + } + pAggInfo->mxReg = pParse->nMem; if( db->mallocFailed ) goto select_end; #if TREETRACE_ENABLED - if( sqlite3TreeTrace & 0x20 ){ - TREETRACE(0x20,pParse,p,("After aggregate analysis %p:\n", pAggInfo)); + if( sqlite3TreeTrace & 0x400 ){ + int ii; + SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo)); sqlite3TreeViewSelect(0, p, 0); if( minMaxFlag ){ sqlite3DebugPrintf("MIN/MAX Optimization (0x%02x) adds:\n", minMaxFlag); sqlite3TreeViewExprList(0, pMinMaxOrderBy, 0, "ORDERBY"); } - printAggInfo(pAggInfo); + for(ii=0; iinColumn; ii++){ + struct AggInfo_col *pCol = &pAggInfo->aCol[ii]; + sqlite3DebugPrintf( + "agg-column[%d] pTab=%s iTable=%d iColumn=%d iMem=%d" + " iSorterColumn=%d\n", + ii, pCol->pTab ? pCol->pTab->zName : "NULL", + pCol->iTable, pCol->iColumn, pCol->iMem, + pCol->iSorterColumn); + sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0); + } + for(ii=0; iinFunc; ii++){ + sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n", + ii, pAggInfo->aFunc[ii].iMem); + sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pFExpr, 0); + } } #endif @@ -151023,7 +144802,7 @@ SQLITE_PRIVATE int sqlite3Select( */ if( pGroupBy ){ KeyInfo *pKeyInfo; /* Keying information for the group by clause */ - int addr1; /* A-vs-B comparison jump */ + int addr1; /* A-vs-B comparision jump */ int addrOutputRow; /* Start of subroutine that outputs a result row */ int regOutputRow; /* Return address register for output subroutine */ int addrSetAbort; /* Set the abort flag and return */ @@ -151082,7 +144861,7 @@ SQLITE_PRIVATE int sqlite3Select( ** in the right order to begin with. */ sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); - TREETRACE(0x2,pParse,p,("WhereBegin\n")); + SELECTTRACE(1,pParse,p,("WhereBegin\n")); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, pDistinct, p, (sDistinct.isTnct==2 ? WHERE_DISTINCTBY : WHERE_GROUPBY) | (orderByGrp ? WHERE_SORTBYGROUP : 0) | distFlag, 0 @@ -151091,12 +144870,8 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3ExprListDelete(db, pDistinct); goto select_end; } - if( pParse->pIdxEpr ){ - optimizeAggregateUseOfIndexedExpr(pParse, p, pAggInfo, &sNC); - } - assignAggregateRegisters(pParse, pAggInfo); eDist = sqlite3WhereIsDistinct(pWInfo); - TREETRACE(0x2,pParse,p,("WhereBegin returns\n")); + SELECTTRACE(1,pParse,p,("WhereBegin returns\n")); if( 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 @@ -151114,13 +144889,9 @@ SQLITE_PRIVATE int sqlite3Select( int nCol; int nGroupBy; -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS - int addrExp; /* Address of OP_Explain instruction */ -#endif - ExplainQueryPlan2(addrExp, (pParse, 0, "USE TEMP B-TREE FOR %s", + explainTempTable(pParse, (sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ? - "DISTINCT" : "GROUP BY" - )); + "DISTINCT" : "GROUP BY"); groupBySort = 1; nGroupBy = pGroupBy->nExpr; @@ -151145,40 +144916,18 @@ SQLITE_PRIVATE int sqlite3Select( } pAggInfo->directMode = 0; regRecord = sqlite3GetTempReg(pParse); - sqlite3VdbeScanStatusCounters(v, addrExp, 0, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord); sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord); - sqlite3VdbeScanStatusRange(v, addrExp, sqlite3VdbeCurrentAddr(v)-2, -1); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3ReleaseTempRange(pParse, regBase, nCol); - TREETRACE(0x2,pParse,p,("WhereEnd\n")); + SELECTTRACE(1,pParse,p,("WhereEnd\n")); sqlite3WhereEnd(pWInfo); pAggInfo->sortingIdxPTab = sortPTab = pParse->nTab++; sortOut = sqlite3GetTempReg(pParse); - sqlite3VdbeScanStatusCounters(v, addrExp, sqlite3VdbeCurrentAddr(v), 0); sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol); sqlite3VdbeAddOp2(v, OP_SorterSort, pAggInfo->sortingIdx, addrEnd); VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v); pAggInfo->useSortingIdx = 1; - sqlite3VdbeScanStatusRange(v, addrExp, -1, sortPTab); - 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( sqlite3TreeTrace & 0x20 ){ - TREETRACE(0x20, pParse, p, - ("AggInfo function expressions converted to reference index\n")); - sqlite3TreeViewSelect(0, p, 0); - printAggInfo(pAggInfo); - } -#endif } /* If the index or temporary table used by the GROUP BY sort @@ -151249,7 +144998,7 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3VdbeAddOp2(v, OP_SorterNext, pAggInfo->sortingIdx,addrTopOfLoop); VdbeCoverage(v); }else{ - TREETRACE(0x2,pParse,p,("WhereEnd\n")); + SELECTTRACE(1,pParse,p,("WhereEnd\n")); sqlite3WhereEnd(pWInfo); sqlite3VdbeChangeToNoop(v, addrSortingIdx); } @@ -151359,8 +145108,7 @@ SQLITE_PRIVATE int sqlite3Select( if( pKeyInfo ){ sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO); } - assignAggregateRegisters(pParse, pAggInfo); - sqlite3VdbeAddOp2(v, OP_Count, iCsr, AggInfoFuncReg(pAggInfo,0)); + sqlite3VdbeAddOp2(v, OP_Count, iCsr, pAggInfo->aFunc[0].iMem); sqlite3VdbeAddOp1(v, OP_Close, iCsr); explainSimpleCount(pParse, pTab, pBest); }else{ @@ -151396,7 +145144,6 @@ SQLITE_PRIVATE int 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 @@ -151413,13 +145160,13 @@ SQLITE_PRIVATE int sqlite3Select( assert( minMaxFlag==WHERE_ORDERBY_NORMAL || pMinMaxOrderBy!=0 ); assert( pMinMaxOrderBy==0 || pMinMaxOrderBy->nExpr==1 ); - TREETRACE(0x2,pParse,p,("WhereBegin\n")); + SELECTTRACE(1,pParse,p,("WhereBegin\n")); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy, pDistinct, p, minMaxFlag|distFlag, 0); if( pWInfo==0 ){ goto select_end; } - TREETRACE(0x2,pParse,p,("WhereBegin returns\n")); + SELECTTRACE(1,pParse,p,("WhereBegin returns\n")); eDist = sqlite3WhereIsDistinct(pWInfo); updateAccumulator(pParse, regAcc, pAggInfo, eDist); if( eDist!=WHERE_DISTINCT_NOOP ){ @@ -151433,7 +145180,7 @@ SQLITE_PRIVATE int sqlite3Select( if( minMaxFlag ){ sqlite3WhereMinMaxOptEarlyOut(v, pWInfo); } - TREETRACE(0x2,pParse,p,("WhereEnd\n")); + SELECTTRACE(1,pParse,p,("WhereEnd\n")); sqlite3WhereEnd(pWInfo); finalizeAggFunctions(pParse, pAggInfo); } @@ -151455,6 +145202,8 @@ SQLITE_PRIVATE int sqlite3Select( ** and send them to the callback one by one. */ if( sSort.pOrderBy ){ + explainTempTable(pParse, + sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY"); assert( p->pEList==pEList ); generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest); } @@ -151476,15 +145225,9 @@ select_end: sqlite3ExprListDelete(db, pMinMaxOrderBy); #ifdef SQLITE_DEBUG if( pAggInfo && !db->mallocFailed ){ -#if TREETRACE_ENABLED - if( sqlite3TreeTrace & 0x20 ){ - TREETRACE(0x20,pParse,p,("Finished with AggInfo\n")); - printAggInfo(pAggInfo); - } -#endif for(i=0; inColumn; i++){ Expr *pExpr = pAggInfo->aCol[i].pCExpr; - if( pExpr==0 ) continue; + assert( pExpr!=0 ); assert( pExpr->pAggInfo==pAggInfo ); assert( pExpr->iAgg==i ); } @@ -151498,8 +145241,8 @@ select_end: #endif #if TREETRACE_ENABLED - TREETRACE(0x1,pParse,p,("end processing\n")); - if( (sqlite3TreeTrace & 0x40000)!=0 && ExplainQueryPlanParent(pParse)==0 ){ + SELECTTRACE(0x1,pParse,p,("end processing\n")); + if( (sqlite3TreeTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){ sqlite3TreeViewSelect(0, p, 0); } #endif @@ -151895,10 +145638,6 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables"); goto trigger_orphan_error; } - if( (pTab->tabFlags & TF_Shadow)!=0 && sqlite3ReadOnlyShadowTables(db) ){ - 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 */ @@ -151918,7 +145657,6 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( }else{ assert( !db->init.busy ); sqlite3CodeVerifySchema(pParse, iDb); - VVA_ONLY( pParse->ifNotExists = 1; ) } goto trigger_cleanup; } @@ -152663,72 +146401,6 @@ static ExprList *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 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 sqlite3ReturningSubqueryCorrelated(Walker *pWalker, Select *pSelect){ - int i; - SrcList *pSrc; - assert( pSelect!=0 ); - pSrc = pSelect->pSrc; - assert( pSrc!=0 ); - for(i=0; inSrc; 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 sqlite3ProcessReturningSubqueries( - ExprList *pEList, - Table *pTab -){ - Walker w; - memset(&w, 0, sizeof(w)); - w.xExprCallback = sqlite3ExprWalkNoop; - w.xSelectCallback = sqlite3ReturningSubqueryCorrelated; - w.u.pTab = pTab; - sqlite3WalkExprList(&w, pEList); - if( w.eCode ){ - w.xExprCallback = sqlite3ReturningSubqueryVarSelect; - w.xSelectCallback = sqlite3SelectWalkNoop; - sqlite3WalkExprList(&w, pEList); - } -} - /* ** Generate code for the RETURNING trigger. Unlike other triggers ** that invoke a subprogram in the bytecode, the code for RETURNING @@ -152748,24 +146420,16 @@ static void codeReturningTrigger( SrcList sFrom; assert( v!=0 ); - if( !pParse->bReturning ){ - /* This RETURNING trigger must be for a different statement as - ** this statement lacks a RETURNING clause. */ - return; - } + assert( pParse->bReturning ); assert( db->pParse==pParse ); pReturning = pParse->u1.pReturning; - if( pTrigger != &(pReturning->retTrig) ){ - /* This RETURNING trigger is for a different statement */ - return; - } + assert( pTrigger == &(pReturning->retTrig) ); memset(&sSelect, 0, sizeof(sSelect)); memset(&sFrom, 0, sizeof(sFrom)); sSelect.pEList = 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; sqlite3SelectPrep(pParse, &sSelect, 0); if( pParse->nErr==0 ){ @@ -152774,7 +146438,7 @@ static void codeReturningTrigger( } sqlite3ExprListDelete(db, sSelect.pEList); pNew = sqlite3ExpandReturning(pParse, pReturning->pReturnEL, pTab); - if( pParse->nErr==0 ){ + if( !db->mallocFailed ){ NameContext sNC; memset(&sNC, 0, sizeof(sNC)); if( pReturning->nRetCol==0 ){ @@ -152792,7 +146456,6 @@ static void codeReturningTrigger( int i; int nCol = pNew->nExpr; int reg = pParse->nMem+1; - sqlite3ProcessReturningSubqueries(pNew, pTab); pParse->nMem += nCol+2; pReturning->iRetReg = reg; for(i=0; ipNext){ if( p->op==op && (tr_tm&p->tr_tm) @@ -153497,7 +147157,7 @@ static void updateFromSelect( assert( pTabList->nSrc>1 ); if( pSrc ){ - assert( pSrc->a[0].fg.notCte ); + pSrc->a[0].fg.notCte = 1; pSrc->a[0].iCursor = -1; pSrc->a[0].pTab->nTabRef--; pSrc->a[0].pTab = 0; @@ -153536,8 +147196,7 @@ static void updateFromSelect( } } pSelect = sqlite3SelectNew(pParse, pList, - pSrc, pWhere2, pGrp, 0, pOrderBy2, - SF_UFSrcCheck|SF_IncludeHidden|SF_UpdateFrom, pLimit2 + pSrc, pWhere2, pGrp, 0, pOrderBy2, SF_UFSrcCheck|SF_IncludeHidden, pLimit2 ); if( pSelect ) pSelect->selFlags |= SF_OrderByReqd; sqlite3SelectDestInit(&dest, eDest, iEph); @@ -153681,7 +147340,7 @@ SQLITE_PRIVATE void sqlite3Update( if( sqlite3ViewGetColumnNames(pParse, pTab) ){ goto update_cleanup; } - if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){ + if( sqlite3IsReadOnly(pParse, pTab, tmask) ){ goto update_cleanup; } @@ -154000,22 +147659,12 @@ SQLITE_PRIVATE void sqlite3Update( /* Begin the database scan. ** ** Do not consider a single-pass strategy for a multi-row update if - ** 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 - */ + ** 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. */ flags = WHERE_ONEPASS_DESIRED; - if( !pParse->nested - && !pTrigger - && !hasFK - && !chngKey - && !bReplace - && (pWhere==0 || !ExprHasProperty(pWhere, EP_Subquery)) - ){ + if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){ flags |= WHERE_ONEPASS_MULTIROW; } pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,0,0,flags,iIdxCur); @@ -154086,8 +147735,6 @@ SQLITE_PRIVATE void sqlite3Update( if( !isView ){ int addrOnce = 0; - int iNotUsed1 = 0; - int iNotUsed2 = 0; /* Open every index that needs updating. */ if( eOnePass!=ONEPASS_OFF ){ @@ -154099,7 +147746,7 @@ SQLITE_PRIVATE void sqlite3Update( addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur, - aToOpen, &iNotUsed1, &iNotUsed2); + aToOpen, 0, 0); if( addrOnce ){ sqlite3VdbeJumpHereOrPopInst(v, addrOnce); } @@ -154194,9 +147841,6 @@ SQLITE_PRIVATE void sqlite3Update( } } if( chngRowid==0 && pPk==0 ){ -#ifdef SQLITE_ALLOW_ROWID_IN_VIEW - if( isView ) sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid); -#endif sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid); } } @@ -154393,10 +148037,8 @@ SQLITE_PRIVATE void sqlite3Update( sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); } - if( pTrigger ){ - sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, - TRIGGER_AFTER, pTab, regOldRowid, onError, labelContinue); - } + 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. @@ -154491,7 +148133,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 ephemeral table rowid */ + int regRowid; /* Register for ephem table rowid */ int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */ int aDummy[2]; /* Unused arg for sqlite3WhereOkOnePass() */ int eOnePass; /* True to use onepass strategy */ @@ -154535,9 +148177,7 @@ static void updateVirtualTable( sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0) ); }else{ - Expr *pRowExpr = exprRowColumn(pParse, i); - if( pRowExpr ) pRowExpr->op2 = OPFLAG_NOCHNG; - pList = sqlite3ExprListAppend(pParse, pList, pRowExpr); + pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i)); } } @@ -154614,7 +148254,7 @@ static void updateVirtualTable( sqlite3WhereEnd(pWInfo); } - /* Begin scanning through the ephemeral table. */ + /* Begin scannning through the ephemeral table. */ addr = sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v); /* Extract arguments from the current row of the ephemeral table and @@ -154734,8 +148374,7 @@ SQLITE_PRIVATE Upsert *sqlite3UpsertNew( SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget( Parse *pParse, /* The parsing context */ SrcList *pTabList, /* Table into which we are inserting */ - Upsert *pUpsert, /* The ON CONFLICT clauses */ - Upsert *pAll /* Complete list of all ON CONFLICT clauses */ + Upsert *pUpsert /* The ON CONFLICT clauses */ ){ Table *pTab; /* That table into which we are inserting */ int rc; /* Result code */ @@ -154823,7 +148462,7 @@ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget( pExpr = &sCol[0]; } for(jj=0; jja[jj].pExpr,pExpr,iCursor)<2 ){ + if( sqlite3ExprCompare(pParse,pTarget->a[jj].pExpr,pExpr,iCursor)<2 ){ break; /* Column ii of the index matches column jj of target */ } } @@ -154838,14 +148477,6 @@ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget( continue; } pUpsert->pUpsertIdx = pIdx; - if( 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 ){ @@ -154872,13 +148503,9 @@ SQLITE_PRIVATE int sqlite3UpsertNextIsIPK(Upsert *pUpsert){ Upsert *pNext; if( NEVER(pUpsert==0) ) return 0; pNext = pUpsert->pNextUpsert; - 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; - } + if( pNext==0 ) return 1; + if( pNext->pUpsertTarget==0 ) return 1; + if( pNext->pUpsertIdx==0 ) return 1; return 0; } @@ -155184,7 +148811,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( ** (possibly synchronous) transaction opened on the main database before ** sqlite3BtreeCopyFile() is called. ** - ** An optimization would be to use a non-journaled pager. + ** An optimisation 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 @@ -155603,10 +149230,10 @@ SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *pVTab){ pVTab->nRef--; if( pVTab->nRef==0 ){ sqlite3_vtab *p = pVTab->pVtab; + sqlite3VtabModuleUnref(pVTab->db, pVTab->pMod); if( p ){ p->pModule->xDisconnect(p); } - sqlite3VtabModuleUnref(pVTab->db, pVTab->pMod); sqlite3DbFree(db, pVTab); } } @@ -155707,6 +149334,7 @@ SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3 *db){ if( p ){ db->pDisconnect = 0; + sqlite3ExpirePreparedStatements(db, 0); do { VTable *pNext = p->pNext; sqlite3VtabUnlock(p); @@ -155872,7 +149500,7 @@ SQLITE_PRIVATE void 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 that was created for this vtab + ** entry in the sqlite_schema table tht was created for this vtab ** by sqlite3StartTable(). */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); @@ -156001,11 +149629,7 @@ 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 ); - sqlite3DeleteTable(db, pTab); db->pVtabCtx = sCtx.pPrior; if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); assert( sCtx.pTab==pTab ); @@ -156027,7 +149651,7 @@ static int vtabCallConstructor( pVTable->nRef = 1; if( sCtx.bDeclared==0 ){ const char *zFormat = "vtable constructor did not declare schema: %s"; - *pzErr = sqlite3MPrintf(db, zFormat, zModuleName); + *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName); sqlite3VtabUnlock(pVTable); rc = SQLITE_ERROR; }else{ @@ -156205,38 +149829,19 @@ SQLITE_API int sqlite3_declare_vtab(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( !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 - ** sqlite3_declare_vtab() is being misused. - */ - z = (const unsigned char*)zCreateTable; - for(i=0; aKeyword[i]; i++){ - int tokenType = 0; - do{ z += sqlite3GetToken(z, &tokenType); }while( tokenType==TK_SPACE ); - if( tokenType!=aKeyword[i] ){ - sqlite3ErrorWithMsg(db, SQLITE_ERROR, "syntax error"); - return SQLITE_ERROR; - } - } - sqlite3_mutex_enter(db->mutex); pCtx = db->pVtabCtx; if( !pCtx || pCtx->bDeclared ){ - sqlite3Error(db, SQLITE_MISUSE_BKPT); + sqlite3Error(db, SQLITE_MISUSE); sqlite3_mutex_leave(db->mutex); return SQLITE_MISUSE_BKPT; } - pTab = pCtx->pTab; assert( IsVirtual(pTab) ); @@ -156250,10 +149855,11 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ initBusy = db->init.busy; db->init.busy = 0; sParse.nQueryLoop = 1; - if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable) ){ - assert( sParse.pNewTable!=0 ); - assert( !db->mallocFailed ); - assert( IsOrdinaryTable(sParse.pNewTable) ); + if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable) + && ALWAYS(sParse.pNewTable!=0) + && ALWAYS(!db->mallocFailed) + && IsOrdinaryTable(sParse.pNewTable) + ){ assert( sParse.zErrMsg==0 ); if( !pTab->aCol ){ Table *pNew = sParse.pNewTable; @@ -156513,10 +150119,7 @@ SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ 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; } sqlite3VtabUnlock(pVTab); } @@ -156636,7 +150239,7 @@ SQLITE_PRIVATE void 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 existence. Eponymous virtual table +** statement in order to come into existance. Eponymous virtual table ** instances always exist. They cannot be DROP-ed. ** ** Any virtual table module for which xConnect and xCreate are the same @@ -156745,10 +150348,6 @@ SQLITE_API int sqlite3_vtab_config(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; @@ -156827,7 +150426,7 @@ typedef struct WhereRightJoin WhereRightJoin; /* ** This object is a header on a block of allocated memory that will be -** automatically freed when its WInfo object is destructed. +** automatically freed when its WInfo oject is destructed. */ struct WhereMemBlock { WhereMemBlock *pNext; /* Next block in the chain */ @@ -156888,7 +150487,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 entries in the key */ + int nPrefix; /* Number of prior entires 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 */ @@ -157138,7 +150737,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 clause */ + WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */ #if defined(SQLITE_SMALL_STACK) WhereTerm aStatic[1]; /* Initial static space for a[] */ #else @@ -157292,7 +150891,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet*,int); #ifdef WHERETRACE_ENABLED SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC); SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm); -SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC); +SQLITE_PRIVATE void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC); #endif SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm( WhereClause *pWC, /* The WHERE clause to be searched */ @@ -157423,8 +151022,7 @@ SQLITE_PRIVATE void 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 */ - /* 0x02000000 -- available for reuse */ -#define WHERE_EXPRIDX 0x04000000 /* Uses an index-on-expressions */ +#define WHERE_VIEWSCAN 0x02000000 /* A full-scan of a VIEW or subquery */ #endif /* !defined(SQLITE_WHEREINT_H) */ @@ -157522,9 +151120,9 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){ /* ** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN -** 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. +** command, or if either SQLITE_DEBUG or SQLITE_ENABLE_STMT_SCANSTATUS was +** defined at compile-time. If it is not a no-op, a single OP_Explain opcode +** is added to the output to describe the table scan strategy in pLevel. ** ** If an OP_Explain opcode is added to the VM, its address is returned. ** Otherwise, if no OP_Explain is coded, zero is returned. @@ -157536,8 +151134,8 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ int ret = 0; -#if !defined(SQLITE_DEBUG) - if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) ) +#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS) + if( sqlite3ParseToplevel(pParse)->explain==2 ) #endif { SrcItem *pItem = &pTabList->a[pLevel->iFrom]; @@ -157681,8 +151279,6 @@ SQLITE_PRIVATE int sqlite3WhereExplainBloomFilter( zMsg = sqlite3StrAccumFinish(&str); ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v), pParse->addrExplain, 0, zMsg,P4_DYNAMIC); - - sqlite3VdbeScanStatus(v, sqlite3VdbeCurrentAddr(v)-1, 0, 0, 0, 0); return ret; } #endif /* SQLITE_OMIT_EXPLAIN */ @@ -157703,37 +151299,16 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus( WhereLevel *pLvl, /* Level to add scanstatus() entry for */ int addrExplain /* Address of OP_Explain (or 0) */ ){ - if( IS_STMT_SCANSTATUS( 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; - } - sqlite3VdbeScanStatus( - v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj - ); - - if( viaCoroutine==0 ){ - if( (wsFlags & (WHERE_MULTI_OR|WHERE_AUTO_INDEX))==0 ){ - sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iTabCur); - } - if( wsFlags & WHERE_INDEXED ){ - sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur); - } - }else{ - int addr = pSrclist->a[pLvl->iFrom].addrFillSub; - VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1); - assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine ); - assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr ); - sqlite3VdbeScanStatusRange(v, addrExplain, addr, pOp->p2-1); - } + const char *zObj = 0; + WhereLoop *pLoop = pLvl->pWLoop; + if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){ + zObj = pLoop->u.btree.pIndex->zName; + }else{ + zObj = pSrclist->a[pLvl->iFrom].zName; } + sqlite3VdbeScanStatus( + v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj + ); } #endif @@ -157793,7 +151368,7 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ pTerm->wtFlags |= TERM_CODED; } #ifdef WHERETRACE_ENABLED - if( (sqlite3WhereTrace & 0x4001)==0x4001 ){ + if( sqlite3WhereTrace & 0x20000 ){ sqlite3DebugPrintf("DISABLE-"); sqlite3WhereTermPrint(pTerm, (int)(pTerm - (pTerm->pWC->a))); } @@ -157908,75 +151483,68 @@ static Expr *removeUnindexableInClauseTerms( Expr *pX /* The IN expression to be reduced */ ){ sqlite3 *db = pParse->db; - Select *pSelect; /* Pointer to the SELECT on the RHS */ Expr *pNew; pNew = sqlite3ExprDup(db, pX, 0); if( db->mallocFailed==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; inLTerm; 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 = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr); - pOrigRhs->a[iField].pExpr = 0; - if( pOrigLhs ){ - assert( pOrigLhs->a[iField].pExpr!=0 ); - pLhs = sqlite3ExprListAppend(pParse,pLhs,pOrigLhs->a[iField].pExpr); - pOrigLhs->a[iField].pExpr = 0; - } - } - } - sqlite3ExprListDelete(db, pOrigRhs); - if( pOrigLhs ){ - 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; - 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; inExpr; i++){ - pOrderBy->a[i].u.x.iOrderByCol = 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; inLTerm; 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 = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr); + pOrigRhs->a[iField].pExpr = 0; + assert( pOrigLhs->a[iField].pExpr!=0 ); + pLhs = sqlite3ExprListAppend(pParse, pLhs, pOrigLhs->a[iField].pExpr); + pOrigLhs->a[iField].pExpr = 0; + } + } + sqlite3ExprListDelete(db, pOrigRhs); + 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; + 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; inExpr; i++){ + pOrderBy->a[i].u.x.iOrderByCol = 0; } + } #if 0 - printf("For indexing, change the IN expr:\n"); - sqlite3TreeViewExpr(0, pX, 0); - printf("Into:\n"); - sqlite3TreeViewExpr(0, pNew, 0); + printf("For indexing, change the IN expr:\n"); + sqlite3TreeViewExpr(0, pX, 0); + printf("Into:\n"); + sqlite3TreeViewExpr(0, pNew, 0); #endif - } } return pNew; } @@ -158229,7 +151797,7 @@ static int codeAllEqualityTerms( /* Figure out how many memory cells we will need then allocate them. */ regBase = pParse->nMem + 1; - nReg = nEq + nExtraReg; + nReg = pLoop->u.btree.nEq + nExtraReg; pParse->nMem += nReg; zAff = sqlite3DbStrDup(pParse->db,sqlite3IndexAffinityStr(pParse->db,pIdx)); @@ -158276,6 +151844,9 @@ static int codeAllEqualityTerms( sqlite3VdbeAddOp2(v, OP_Copy, r1, regBase+j); } } + } + for(j=nSkip; jaLTerm[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 @@ -158418,19 +151989,18 @@ 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 identified +** Also, if the node is a TK_COLUMN that does access the table idenified ** by pCCurHint.iTabCur, and an index is being used (which we will ** know because CCurHint.pIdx!=0) then transform the TK_COLUMN into ** an access of the index rather than the original table. */ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ int rc = WRC_Continue; - int reg; struct CCurHint *pHint = pWalker->u.pCCurHint; if( pExpr->op==TK_COLUMN ){ if( pExpr->iTable!=pHint->iTabCur ){ - reg = ++pWalker->pParse->nMem; /* Register for column value */ - reg = sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg); + int reg = ++pWalker->pParse->nMem; /* Register for column value */ + sqlite3ExprCode(pWalker->pParse, pExpr, reg); pExpr->op = TK_REGISTER; pExpr->iTable = reg; }else if( pHint->pIdx!=0 ){ @@ -158438,15 +152008,15 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ pExpr->iColumn = sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn); assert( pExpr->iColumn>=0 ); } - }else if( pExpr->pAggInfo ){ + }else if( pExpr->op==TK_AGG_FUNCTION ){ + /* An aggregate function in the WHERE clause of a query means this must + ** be a correlated sub-query, and expression pExpr is an aggregate from + ** the parent context. Do not walk the function arguments in this case. + ** + ** todo: It should be possible to replace this node with a TK_REGISTER + ** expression, as the result of the expression must be stored in a + ** register at this point. The same holds for TK_AGG_COLUMN nodes. */ rc = WRC_Prune; - reg = ++pWalker->pParse->nMem; /* Register for column value */ - reg = 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; } @@ -158548,7 +152118,7 @@ static void codeCursorHint( } if( pExpr!=0 ){ sWalker.xExprCallback = codeCursorHintFixExpr; - if( pParse->nErr==0 ) sqlite3WalkExpr(&sWalker, pExpr); + sqlite3WalkExpr(&sWalker, pExpr); sqlite3VdbeAddOp4(v, OP_CursorHint, (sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0, (const char*)pExpr, P4_EXPR); @@ -158748,27 +152318,6 @@ 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; iiu.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. @@ -158806,15 +152355,13 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); bRev = (pWInfo->revMask>>iLevel)&1; VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName)); -#if WHERETRACE_ENABLED /* 0x4001 */ - if( sqlite3WhereTrace & 0x1 ){ +#if WHERETRACE_ENABLED /* 0x20800 */ + if( sqlite3WhereTrace & 0x800 ){ sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n", iLevel, pWInfo->nLevel, (u64)notReady, pLevel->iFrom); - if( sqlite3WhereTrace & 0x1000 ){ - sqlite3WhereLoopPrint(pLoop, pWC); - } + sqlite3WhereLoopPrint(pLoop, pWC); } - if( (sqlite3WhereTrace & 0x4001)==0x4001 ){ + if( sqlite3WhereTrace & 0x20000 ){ if( iLevel==0 ){ sqlite3DebugPrintf("WHERE clause being coded:\n"); sqlite3TreeViewExpr(0, pWInfo->pWhere, 0); @@ -158847,7 +152394,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( if( pLevel->iFrom>0 && (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){ pLevel->iLeftJoin = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin); - VdbeComment((v, "init LEFT JOIN match flag")); + VdbeComment((v, "init LEFT JOIN no-match flag")); } /* Compute a safe address to jump to if we discover that the table for @@ -159057,7 +152604,7 @@ SQLITE_PRIVATE Bitmask 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 correct. */ + assert( TK_GE==TK_GT+3 ); /* ... is correcct. */ assert( (pStart->wtFlags & TERM_VNULL)==0 ); testcase( pStart->wtFlags & TERM_VIRTUAL ); @@ -159363,7 +152910,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** guess. */ addrSeekScan = sqlite3VdbeAddOp1(v, OP_SeekScan, (pIdx->aiRowLogEst[0]+9)/10); - if( pRangeStart || pRangeEnd ){ + if( pRangeStart ){ sqlite3VdbeChangeP5(v, 1); sqlite3VdbeChangeP2(v, addrSeekScan, sqlite3VdbeCurrentAddr(v)+1); addrSeekScan = 0; @@ -159404,7 +152951,16 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( assert( pLevel->p2==0 ); if( pRangeEnd ){ Expr *pRight = pRangeEnd->pExpr->pRight; - assert( addrSeekScan==0 ); + 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 = sqlite3VdbeCurrentAddr(v); + } codeExprOrVector(pParse, pRight, regBase+nEq, nTop); whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd); if( (pRangeEnd->wtFlags & TERM_VNULL)==0 @@ -159438,7 +152994,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( if( zEndAff ) sqlite3DbNNFreeNN(db, zEndAff); /* Top of the loop body */ - pLevel->p2 = sqlite3VdbeCurrentAddr(v); + if( pLevel->p2==0 ) pLevel->p2 = sqlite3VdbeCurrentAddr(v); /* Check if the index cursor is past the end of the range. */ if( nConstraint ){ @@ -159516,9 +153072,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } /* Record the instruction used to terminate the loop. */ - if( (pLoop->wsFlags & WHERE_ONEROW) - || (pLevel->u.in.nIn && regBignull==0 && whereLoopIsOneRow(pLoop)) - ){ + if( pLoop->wsFlags & WHERE_ONEROW ){ pLevel->op = OP_Noop; }else if( bRev ){ pLevel->op = OP_Prev; @@ -159731,7 +153285,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } /* Loop through table entries that match term pOrTerm. */ ExplainQueryPlan((pParse, 1, "INDEX %d", ii+1)); - WHERETRACE(0xffffffff, ("Subplan for OR-clause:\n")); + WHERETRACE(0xffff, ("Subplan for OR-clause:\n")); pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, 0, WHERE_OR_SUBCLAUSE, iCovCur); assert( pSubWInfo || pParse->nErr ); @@ -159908,12 +153462,6 @@ SQLITE_PRIVATE Bitmask 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{ @@ -159974,12 +153522,12 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } #endif } -#ifdef WHERETRACE_ENABLED /* 0xffffffff */ +#ifdef WHERETRACE_ENABLED /* 0xffff */ if( sqlite3WhereTrace ){ VdbeNoopComment((v, "WhereTerm[%d] (%p) priority=%d", pWC->nTerm-j, pTerm, iLoop)); } - if( sqlite3WhereTrace & 0x4000 ){ + if( sqlite3WhereTrace & 0x800 ){ sqlite3DebugPrintf("Coding auxiliary constraint:\n"); sqlite3WhereTermPrint(pTerm, pWC->nTerm-j); } @@ -160008,8 +153556,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( if( pTerm->leftCursor!=iCur ) continue; if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT) ) continue; pE = pTerm->pExpr; -#ifdef WHERETRACE_ENABLED /* 0x4001 */ - if( (sqlite3WhereTrace & 0x4001)==0x4001 ){ +#ifdef WHERETRACE_ENABLED /* 0x800 */ + if( sqlite3WhereTrace & 0x800 ){ sqlite3DebugPrintf("Coding transitive constraint:\n"); sqlite3WhereTermPrint(pTerm, pWC->nTerm-j); } @@ -160124,13 +153672,13 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } } -#if WHERETRACE_ENABLED /* 0x4001 */ - if( sqlite3WhereTrace & 0x4000 ){ +#if WHERETRACE_ENABLED /* 0x20800 */ + if( sqlite3WhereTrace & 0x20000 ){ sqlite3DebugPrintf("All WHERE-clause terms after coding level %d:\n", iLevel); sqlite3WhereClausePrint(pWC); } - if( sqlite3WhereTrace & 0x1 ){ + if( sqlite3WhereTrace & 0x800 ){ sqlite3DebugPrintf("End Coding level %d: notReady=%llx\n", iLevel, (u64)pLevel->notReady); } @@ -160164,16 +153712,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( pRJ->regReturn); for(k=0; ka[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 ){ - sqlite3VdbeAddOp3( - v, OP_Null, 0, pRight->regResult, - pRight->regResult + pRight->pSelect->pEList->nExpr-1 - ); - } sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur); iIdxCur = pWInfo->a[k].iIdxCur; if( iIdxCur ){ @@ -160254,7 +153793,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( ** the WHERE clause of SQL statements. ** ** This file was originally part of where.c but was split out to improve -** readability and editability. This file contains utility routines for +** readability and editabiliity. This file contains utility routines for ** analyzing Expr objects in the WHERE clause. */ /* #include "sqliteInt.h" */ @@ -160470,7 +154009,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>1 || (cnt>0 && z[0]!=wc[3])) && 255!=(u8)z[cnt-1] ){ + if( cnt!=0 && 255!=(u8)z[cnt-1] && (cnt>1 || z[0]!=wc[3]) ){ Expr *pPrefix; /* A "complete" match if the pattern ends with "*" or "%" */ @@ -161043,7 +154582,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 followed by an inverted copy (t2.b==t1.a). Skip this term + ** or follwed 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 ); @@ -161215,40 +154754,36 @@ 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 */ - int j /* Start looking with the j-th pFrom entry */ + Expr *pExpr /* An operand of a comparison operator */ ){ Index *pIdx; int i; int iCur; - 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; inKeyCol; i++){ - if( pIdx->aiColumn[i]!=XN_EXPR ) continue; - assert( pIdx->bHasExpr ); - if( sqlite3ExprCompareSkip(pExpr,pIdx->aColExpr->a[i].pExpr,iCur)==0 - && !sqlite3ExprIsConstant(0,pIdx->aColExpr->a[i].pExpr) - ){ - aiCurCol[0] = iCur; - aiCurCol[1] = XN_EXPR; - return 1; - } + 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; inKeyCol; i++){ + if( pIdx->aiColumn[i]!=XN_EXPR ) continue; + assert( pIdx->bHasExpr ); + if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){ + 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. */ @@ -161258,6 +154793,7 @@ 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 ){ @@ -161265,16 +154801,9 @@ static int exprMightBeIndexed( aiCurCol[1] = pExpr->iColumn; return 1; } - - for(i=0; inSrc; 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; + 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); } @@ -161305,8 +154834,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; /* Prerequisites of the pExpr->pLeft */ - Bitmask prereqAll; /* Prerequisites of pExpr */ + Bitmask prereqLeft; /* Prerequesites of the pExpr->pLeft */ + Bitmask prereqAll; /* Prerequesites 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 */ @@ -161400,7 +154929,7 @@ static void exprAnalyze( pLeft = pLeft->x.pList->a[pTerm->u.x.iField-1].pExpr; } - if( exprMightBeIndexed(pSrc, aiCurCol, pLeft, op) ){ + if( exprMightBeIndexed(pSrc, prereqLeft, aiCurCol, pLeft, op) ){ pTerm->leftCursor = aiCurCol[0]; assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); pTerm->u.x.leftColumn = aiCurCol[1]; @@ -161408,7 +154937,7 @@ static void exprAnalyze( } if( op==TK_IS ) pTerm->wtFlags |= TERM_IS; if( pRight - && exprMightBeIndexed(pSrc, aiCurCol, pRight, op) + && exprMightBeIndexed(pSrc, pTerm->prereqRight, aiCurCol, pRight, op) && !ExprHasProperty(pRight, EP_FixedCol) ){ WhereTerm *pNew; @@ -161452,7 +154981,7 @@ static void exprAnalyze( && 0==sqlite3ExprCanBeNull(pLeft) ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); - pExpr->op = TK_TRUEFALSE; /* See tag-20230504-1 */ + pExpr->op = TK_TRUEFALSE; pExpr->u.zToken = "false"; ExprSetProperty(pExpr, EP_IsFalse); pTerm->prereqAll = 0; @@ -161619,6 +155148,7 @@ static void exprAnalyze( transferJoinMarkings(pNewExpr1, pExpr); idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags); testcase( idxNew1==0 ); + exprAnalyze(pSrc, pWC, idxNew1); pNewExpr2 = sqlite3ExprDup(db, pLeft, 0); pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName), @@ -161626,7 +155156,6 @@ 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 ){ @@ -161683,7 +155212,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->selFlags & SF_Values)) + && pExpr->x.pSelect->pPrior==0 #ifndef SQLITE_OMIT_WINDOWFUNC && pExpr->x.pSelect->pWin==0 #endif @@ -161871,15 +155400,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Selec 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. */ @@ -161894,14 +155415,12 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Selec /* All conditions are met. Add the terms to the where-clause object. */ assert( p->pLimit->op==TK_LIMIT ); - if( p->iOffset!=0 && (p->selFlags & SF_Compound)==0 ){ + whereAddLimitExpr(pWC, p->iLimit, p->pLimit->pLeft, + iCsr, SQLITE_INDEX_CONSTRAINT_LIMIT); + if( p->iOffset>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); - } } } @@ -162100,12 +155619,9 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs( pRhs = sqlite3PExpr(pParse, TK_UPLUS, sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0); pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs); - if( pItem->fg.jointype & (JT_LEFT|JT_RIGHT) ){ - testcase( pItem->fg.jointype & JT_LEFT ); /* testtag-20230227a */ - testcase( pItem->fg.jointype & JT_RIGHT ); /* testtag-20230227b */ + if( pItem->fg.jointype & (JT_LEFT|JT_LTORJ) ){ joinType = EP_OuterON; }else{ - testcase( pItem->fg.jointype & JT_LTORJ ); /* testtag-20230227c */ joinType = EP_InnerON; } sqlite3SetJoinExpr(pTerm, pItem->iCursor, joinType); @@ -162419,42 +155935,6 @@ static Expr *whereRightSubexprIsColumn(Expr *p){ return 0; } -/* -** 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( 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( sqlite3IndexAffinityOk(pX, idxaff) ){ - CollSeq *pRet = sqlite3ExprCompareCollSeq(pParse, pX); - return pRet ? pRet->zName : sqlite3StrBINARY; - } - return 0; -} - /* ** Advance to the next WhereTerm that matches according to the criteria ** established when the pScan object was initialized by whereScanInit(). @@ -162505,24 +155985,16 @@ 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 ){ - const char *zCollName; + CollSeq *pColl; Parse *pParse = pWC->pWInfo->pParse; pX = pTerm->pExpr; - - if( (pTerm->eOperator & WO_IN) ){ - zCollName = indexInAffinityOk(pParse, pTerm, pScan->idxaff); - if( !zCollName ) continue; - }else{ - CollSeq *pColl; - if( !sqlite3IndexAffinityOk(pX, pScan->idxaff) ){ - continue; - } - assert(pX->pLeft); - pColl = sqlite3ExprCompareCollSeq(pParse, pX); - zCollName = pColl ? pColl->zName : sqlite3StrBINARY; + if( !sqlite3IndexAffinityOk(pX, pScan->idxaff) ){ + continue; } - - if( sqlite3StrICmp(zCollName, pScan->zCollName) ){ + assert(pX->pLeft); + pColl = sqlite3ExprCompareCollSeq(pParse, pX); + if( pColl==0 ) pColl = pParse->db->pDfltColl; + if( sqlite3StrICmp(pColl->zName, pScan->zCollName) ){ continue; } } @@ -162839,22 +156311,12 @@ static void translateColumnToCopy( for(; iStartp1!=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 @@ -162874,13 +156336,9 @@ static void translateColumnToCopy( ** are no-ops. */ #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(WHERETRACE_ENABLED) -static void whereTraceIndexInfoInputs( - sqlite3_index_info *p, /* The IndexInfo object */ - Table *pTab /* The TABLE that is the virtual table */ -){ +static void whereTraceIndexInfoInputs(sqlite3_index_info *p){ int i; - if( (sqlite3WhereTrace & 0x10)==0 ) return; - sqlite3DebugPrintf("sqlite3_index_info inputs for %s:\n", pTab->zName); + if( !sqlite3WhereTrace ) return; for(i=0; inConstraint; i++){ sqlite3DebugPrintf( " constraint[%d]: col=%d termid=%d op=%d usabled=%d collseq=%s\n", @@ -162898,13 +156356,9 @@ static void whereTraceIndexInfoInputs( p->aOrderBy[i].desc); } } -static void whereTraceIndexInfoOutputs( - sqlite3_index_info *p, /* The IndexInfo object */ - Table *pTab /* The TABLE that is the virtual table */ -){ +static void whereTraceIndexInfoOutputs(sqlite3_index_info *p){ int i; - if( (sqlite3WhereTrace & 0x10)==0 ) return; - sqlite3DebugPrintf("sqlite3_index_info outputs for %s:\n", pTab->zName); + if( !sqlite3WhereTrace ) return; for(i=0; inConstraint; i++){ sqlite3DebugPrintf(" usage[%d]: argvIdx=%d omit=%d\n", i, @@ -162918,8 +156372,8 @@ static void whereTraceIndexInfoOutputs( sqlite3DebugPrintf(" estimatedRows=%lld\n", p->estimatedRows); } #else -#define whereTraceIndexInfoInputs(A,B) -#define whereTraceIndexInfoOutputs(A,B) +#define whereTraceIndexInfoInputs(A) +#define whereTraceIndexInfoOutputs(A) #endif /* @@ -162991,57 +156445,6 @@ 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 () [WHERE ] -** -** This is only required if 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; - sqlite3_str *pStr = sqlite3_str_new(pParse->db); - 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; - sqlite3_str_appendf(pStr, "%s%s", zSep, zName); - zSep = ", "; - } - zText = sqlite3_str_finish(pStr); - if( zText==0 ){ - sqlite3OomFault(pParse->db); - }else{ - *pAddrExplain = sqlite3VdbeExplain( - pParse, 0, "%s)%s", zText, (bPartial ? " WHERE " : "") - ); - 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 @@ -163049,7 +156452,8 @@ static void explainAutomaticIndex( */ static SQLITE_NOINLINE void constructAutomaticIndex( Parse *pParse, /* The parsing context */ - WhereClause *pWC, /* The WHERE clause */ + const WhereClause *pWC, /* The WHERE clause */ + const SrcItem *pSrc, /* The FROM clause term to get the next index */ const Bitmask notReady, /* Mask of cursors that are not available */ WhereLevel *pLevel /* Write new index here */ ){ @@ -163070,17 +156474,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 warning has been issued */ - u8 useBloomFilter = 0; /* True to also add a Bloom filter */ + u8 sentWarning = 0; /* True if a warnning has been issued */ Expr *pPartial = 0; /* Partial Index Expression */ int iContinue = 0; /* Jump here to skip excluded rows */ - SrcList *pTabList; /* The complete FROM clause */ - SrcItem *pSrc; /* The FROM clause term to get the next index */ + SrcItem *pTabItem; /* FROM clause term being indexed */ 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. */ @@ -163091,8 +156490,6 @@ 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; @@ -163103,7 +156500,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 - && sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, pLevel->iFrom, 0) + && sqlite3ExprIsTableConstraint(pExpr, pSrc) ){ pPartial = sqlite3ExprAnd(pParse, pPartial, sqlite3ExprDup(pParse->db, pExpr, 0)); @@ -163144,11 +156541,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex( ** original table changes and the index and table cannot both be used ** if they go out of sync. */ - if( IsView(pTable) ){ - extraCols = ALLBITS & ~idxCols; - }else{ - extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1)); - } + extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1)); mxBitCol = MIN(BMS-1,pTable->nCol); testcase( pTable->nCol==BMS-1 ); testcase( pTable->nCol==BMS-2 ); @@ -163184,16 +156577,6 @@ static SQLITE_NOINLINE void constructAutomaticIndex( assert( pColl!=0 || pParse->nErr>0 ); /* TH3 collate01.800 */ pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY; n++; - if( ALWAYS(pX->pLeft!=0) - && 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; - } } } } @@ -163220,27 +156603,25 @@ static SQLITE_NOINLINE void constructAutomaticIndex( pIdx->azColl[n] = sqlite3StrBINARY; /* Create the automatic index */ - explainAutomaticIndex(pParse, pIdx, pPartial!=0, &addrExp); assert( pLevel->iIdxCur>=0 ); pLevel->iIdxCur = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "for %s", pTable->zName)); - if( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) && useBloomFilter ){ - sqlite3WhereExplainBloomFilter(pParse, pWC->pWInfo, pLevel); + if( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ){ pLevel->regFilter = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Blob, 10000, pLevel->regFilter); } /* Fill the automatic index with content */ - assert( pSrc == &pWC->pWInfo->pTabList->a[pLevel->iFrom] ); - if( pSrc->fg.viaCoroutine ){ - int regYield = pSrc->regReturn; + pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom]; + if( pTabItem->fg.viaCoroutine ){ + int regYield = pTabItem->regReturn; addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0); - sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSrc->addrFillSub); + sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield); VdbeCoverage(v); - VdbeComment((v, "next row of %s", pSrc->pTab->zName)); + VdbeComment((v, "next row of %s", pTabItem->pTab->zName)); }else{ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v); } @@ -163257,18 +156638,17 @@ static SQLITE_NOINLINE void constructAutomaticIndex( sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, regBase, pLoop->u.btree.nEq); } - sqlite3VdbeScanStatusCounters(v, addrExp, addrExp, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue); - if( pSrc->fg.viaCoroutine ){ + if( pTabItem->fg.viaCoroutine ){ sqlite3VdbeChangeP2(v, addrCounter, regBase+n); testcase( pParse->db->mallocFailed ); assert( pLevel->iIdxCur>0 ); translateColumnToCopy(pParse, addrTop, pLevel->iTabCur, - pSrc->regResult, pLevel->iIdxCur); + pTabItem->regResult, pLevel->iIdxCur); sqlite3VdbeGoto(v, addrTop); - pSrc->fg.viaCoroutine = 0; + pTabItem->fg.viaCoroutine = 0; }else{ sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v); sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX); @@ -163278,7 +156658,6 @@ static SQLITE_NOINLINE void constructAutomaticIndex( /* Jump here when skipping the initialization */ sqlite3VdbeJumpHere(v, addrInit); - sqlite3VdbeScanStatusRange(v, addrExp, addrExp, -1); end_auto_index_create: sqlite3ExprDelete(pParse->db, pPartial); @@ -163320,26 +156699,16 @@ static SQLITE_NOINLINE void 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 = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); do{ - const SrcList *pTabList; const SrcItem *pItem; const Table *pTab; u64 sz; - int iSrc; sqlite3WhereExplainBloomFilter(pParse, pWInfo, pLevel); addrCont = sqlite3VdbeMakeLabel(pParse); iCur = pLevel->iTabCur; @@ -163353,9 +156722,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( ** testing complicated. By basing the blob size on the value in the ** sqlite_stat1 table, testing is much easier. */ - pTabList = pWInfo->pTabList; - iSrc = pLevel->iFrom; - pItem = &pTabList->a[iSrc]; + pItem = &pWInfo->pTabList->a[pLevel->iFrom]; assert( pItem!=0 ); pTab = pItem->pTab; assert( pTab!=0 ); @@ -163372,7 +156739,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( for(pTerm=pWInfo->sWC.a; pTermpExpr; if( (pTerm->wtFlags & TERM_VIRTUAL)==0 - && sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, iSrc, 0) + && sqlite3ExprIsTableConstraint(pExpr, pItem) ){ sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); } @@ -163388,8 +156755,9 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( int r1 = sqlite3GetTempRange(pParse, n); int jj; for(jj=0; jjaiColumn[jj]; assert( pIdx->pTable==pItem->pTab ); - sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj); + sqlite3ExprCodeGetColumnOfTable(v, pIdx->pTable, iCur, iCol,r1+jj); } sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n); sqlite3ReleaseTempRange(pParse, r1, n); @@ -163420,8 +156788,6 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( } }while( iLevel < pWInfo->nLevel ); sqlite3VdbeJumpHere(v, addrOnce); - pParse->pIdxEpr = saved_pIdxEpr; - pParse->pIdxPartExpr = saved_pIdxPartExpr; } @@ -163498,7 +156864,7 @@ static sqlite3_index_info *allocateIndexInfo( Expr *pE2; /* Skip over constant terms in the ORDER BY clause */ - if( sqlite3ExprIsConstant(0, pExpr) ){ + if( sqlite3ExprIsConstant(pExpr) ){ continue; } @@ -163533,7 +156899,7 @@ static sqlite3_index_info *allocateIndexInfo( } if( i==n ){ nOrderBy = n; - if( (pWInfo->wctrlFlags & WHERE_DISTINCTBY) && !pSrc->fg.rowidUsed ){ + if( (pWInfo->wctrlFlags & WHERE_DISTINCTBY) ){ eDistinct = 2 + ((pWInfo->wctrlFlags & WHERE_SORTBYGROUP)!=0); }else if( pWInfo->wctrlFlags & WHERE_GROUPBY ){ eDistinct = 1; @@ -163610,7 +156976,7 @@ static sqlite3_index_info *allocateIndexInfo( pIdxInfo->nConstraint = j; for(i=j=0; ia[i].pExpr; - if( sqlite3ExprIsConstant(0, pExpr) ) continue; + if( sqlite3ExprIsConstant(pExpr) ) continue; assert( pExpr->op==TK_COLUMN || (pExpr->op==TK_COLLATE && pExpr->pLeft->op==TK_COLUMN && pExpr->iColumn==pExpr->pLeft->iColumn) ); @@ -163662,11 +157028,11 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab; int rc; - whereTraceIndexInfoInputs(p, pTab); + whereTraceIndexInfoInputs(p); pParse->db->nSchemaLock++; rc = pVtab->pModule->xBestIndex(pVtab, p); pParse->db->nSchemaLock--; - whereTraceIndexInfoOutputs(p, pTab); + whereTraceIndexInfoOutputs(p); if( rc!=SQLITE_OK && rc!=SQLITE_CONSTRAINT ){ if( rc==SQLITE_NOMEM ){ @@ -163677,9 +157043,6 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg); } } - if( pTab->u.vtab.p->bAllSchemas ){ - sqlite3VtabUsesAllSchemas(pParse); - } sqlite3_free(pVtab->zErrMsg); pVtab->zErrMsg = 0; return rc; @@ -163724,7 +157087,6 @@ 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 @@ -163769,12 +157131,7 @@ static int whereKeyStats( ** it is extended to two fields. The duplicates that this creates do not ** cause any problems. */ - if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){ - nField = pIdx->nKeyCol; - }else{ - nField = pIdx->nColumn; - } - nField = MIN(pRec->nField, nField); + nField = MIN(pRec->nField, pIdx->nSample); iCol = 0; iSample = pIdx->nSample * nField; do{ @@ -163840,12 +157197,12 @@ static int whereKeyStats( if( iCol>0 ){ pRec->nField = iCol; assert( sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)<=0 - || pParse->db->mallocFailed || CORRUPT_DB ); + || pParse->db->mallocFailed ); } if( i>0 ){ pRec->nField = nField; assert( sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0 - || pParse->db->mallocFailed || CORRUPT_DB ); + || pParse->db->mallocFailed ); } } } @@ -163937,7 +157294,7 @@ SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCo ** 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 performed multiple +** on the stat4 data for the index. this scan will be peformed multiple ** times (once for each (a,b) combination that matches a=?) is dealt with ** by the caller. ** @@ -164018,7 +157375,7 @@ static int whereRangeSkipScanEst( int nAdjust = (sqlite3LogEst(p->nSample) - sqlite3LogEst(nDiff)); pLoop->nOut -= nAdjust; *pbDone = 1; - WHERETRACE(0x20, ("range skip-scan regions: %u..%u adjust=%d est=%d\n", + WHERETRACE(0x10, ("range skip-scan regions: %u..%u adjust=%d est=%d\n", nLower, nUpper, nAdjust*-1, pLoop->nOut)); } @@ -164189,15 +157546,14 @@ 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==sqlite3LogEst(4) ); + if( iLwrIdx==iUprIdx ) nNew -= 20; assert( 20==sqlite3LogEst(4) ); }else{ nNew = 10; assert( 10==sqlite3LogEst(2) ); } if( nNewwtFlags & TERM_VNULL)==0 || pParse->nErr>0 ); + assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 ); nNew = whereRangeAdjust(pLower, nOut); nNew = whereRangeAdjust(pUpper, nNew); @@ -164230,7 +157586,7 @@ static int whereRangeScanEst( if( nNewnOut>nOut ){ - WHERETRACE(0x20,("Range scan lowers nOut from %d to %d\n", + WHERETRACE(0x10,("Range scan lowers nOut from %d to %d\n", pLoop->nOut, nOut)); } #endif @@ -164295,7 +157651,7 @@ static int whereEqualScanEst( pBuilder->nRecValid = nEq; whereKeyStats(pParse, p, pRec, 0, a); - WHERETRACE(0x20,("equality scan regions %s(%d): %d\n", + WHERETRACE(0x10,("equality scan regions %s(%d): %d\n", p->zName, nEq-1, (int)a[1])); *pnRow = a[1]; @@ -164343,9 +157699,9 @@ static int whereInScanEst( } if( rc==SQLITE_OK ){ - if( nRowEst > (tRowcnt)nRow0 ) nRowEst = nRow0; + if( nRowEst > nRow0 ) nRowEst = nRow0; *pnRow = nRowEst; - WHERETRACE(0x20,("IN row estimate: est=%d\n", nRowEst)); + WHERETRACE(0x10,("IN row estimate: est=%d\n", nRowEst)); } assert( pBuilder->nRecValid==nRecValid ); return rc; @@ -164414,34 +157770,17 @@ SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){ #ifdef WHERETRACE_ENABLED /* ** Print a WhereLoop object for debugging purposes -** -** 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 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; - sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, - p->iTab, nb, p->maskSelf, nb, p->prereq & mAll); - sqlite3DebugPrintf(" %12s", - pItem->zAlias ? pItem->zAlias : pTab->zName); - }else{ - sqlite3DebugPrintf("%c%2d.%03llx.%03llx %c%d", - p->cId, p->iTab, p->maskSelf, p->prereq & 0xfff, p->cId, p->iTab); - } +*/ +SQLITE_PRIVATE void 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; + sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, + p->iTab, nb, p->maskSelf, nb, p->prereq & mAll); + sqlite3DebugPrintf(" %12s", + pItem->zAlias ? pItem->zAlias : pTab->zName); if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ const char *zName; if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){ @@ -164471,22 +157810,13 @@ SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause sqlite3DebugPrintf(" f %06x N %d", p->wsFlags, p->nLTerm); } sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); - if( p->nLTerm && (sqlite3WhereTrace & 0x4000)!=0 ){ + if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){ int i; for(i=0; inLTerm; i++){ sqlite3WhereTermPrint(p->aLTerm[i], i); } } } -SQLITE_PRIVATE void sqlite3ShowWhereLoop(const WhereLoop *p){ - if( p ) sqlite3WhereLoopPrint(p, 0); -} -SQLITE_PRIVATE void sqlite3ShowWhereLoopList(const WhereLoop *p){ - while( p ){ - sqlite3ShowWhereLoop(p); - p = p->pNextLoop; - } -} #endif /* @@ -164599,60 +157929,46 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ } /* -** 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. +** Return TRUE if all of the following are true: ** -** In other words, return true if the cost relationwship between X and Y -** is inverted and needs to be adjusted. +** (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 ** -** Case 1: -** -** (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 -** -** 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 +** 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. */ 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; /* (2b) */ + return 0; /* X is not a subset of Y */ } - if( pY->nSkip > pX->nSkip ) return 0; /* (2d) */ + if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0; + if( pY->nSkip > pX->nSkip ) return 0; 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; /* (2c) */ + if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */ } if( (pX->wsFlags&WHERE_IDX_ONLY)!=0 && (pY->wsFlags&WHERE_IDX_ONLY)==0 ){ - return 0; /* (2e) */ + return 0; /* Constraint (5) */ } - return 1; /* Case 2 is true */ + return 1; /* All conditions meet */ } /* @@ -164733,7 +158049,7 @@ static WhereLoop **whereLoopFindLesser( ** rSetup. Call this SETUP-INVARIANT */ assert( p->rSetup>=pTemplate->rSetup ); - /* Any loop using an application-defined index (or PRIMARY KEY or + /* Any loop using an appliation-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 @@ -164760,7 +158076,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 dependencies than p, and + ** (1) pTemplate has no more dependences than p, and ** (2) pTemplate has an equal or lower cost than p. */ if( (p->prereq & pTemplate->prereq)==pTemplate->prereq /* (1) */ @@ -164878,7 +158194,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 supplanted by pTemplate */ + ** p[] that are also supplated by pTemplate */ WhereLoop **ppTail = &p->pNextLoop; WhereLoop *pToDel; while( *ppTail ){ @@ -164958,7 +158274,6 @@ static void whereLoopOutputAdjust( if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break; } if( j<0 ){ - 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 @@ -165078,7 +158393,7 @@ static int whereRangeVectorLen( } /* -** Adjust the cost C by the costMult factor T. This only occurs if +** Adjust the cost C by the costMult facter T. This only occurs if ** compiled with -DSQLITE_ENABLE_COSTMULT */ #ifdef SQLITE_ENABLE_COSTMULT @@ -165105,7 +158420,7 @@ static int whereLoopAddBtreeIndex( Index *pProbe, /* An index on pSrc */ LogEst nInMul /* log(Number of iterations due to IN) */ ){ - WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyze context */ + WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyse context */ Parse *pParse = pWInfo->pParse; /* Parsing context */ sqlite3 *db = pParse->db; /* Database connection malloc context */ WhereLoop *pNew; /* Template WhereLoop under construction */ @@ -165126,10 +158441,7 @@ static int whereLoopAddBtreeIndex( WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */ pNew = pBuilder->pNew; - assert( db->mallocFailed==0 || pParse->nErr>0 ); - if( pParse->nErr ){ - return pParse->rc; - } + if( db->mallocFailed ) return SQLITE_NOMEM_BKPT; 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)); @@ -165142,12 +158454,7 @@ 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 || 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); - } - } + if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); assert( pNew->u.btree.nEqnColumn ); assert( pNew->u.btree.nEqnKeyCol @@ -165381,7 +158688,7 @@ static int whereLoopAddBtreeIndex( && pNew->nOut+10 > pProbe->aiRowLogEst[0] ){ #if WHERETRACE_ENABLED /* 0x01 */ - if( sqlite3WhereTrace & 0x20 ){ + if( sqlite3WhereTrace & 0x01 ){ sqlite3DebugPrintf( "STAT4 determines term has low selectivity:\n"); sqlite3WhereTermPrint(pTerm, 999); @@ -165413,33 +158720,14 @@ static int whereLoopAddBtreeIndex( } } - /* 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. - */ + /* 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 ); - 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 = 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 ){ + rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow; + pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx); + if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){ pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16); } ApplyCostMultiplier(pNew->rRun, pProbe->pTable->costMult); @@ -165461,9 +158749,6 @@ static int whereLoopAddBtreeIndex( && (pNew->u.btree.nEqnKeyCol || pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY) ){ - if( pNew->u.btree.nEq>3 ){ - sqlite3ProgressCheck(pParse); - } whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn); } pNew->nOut = saved_nOut; @@ -165544,9 +158829,7 @@ static int indexMightHelpWithOrderBy( for(ii=0; iinExpr; ii++){ Expr *pExpr = sqlite3ExprSkipCollateAndLikely(pOB->a[ii].pExpr); if( NEVER(pExpr==0) ) continue; - if( (pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN) - && pExpr->iTable==iCursor - ){ + if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){ if( pExpr->iColumn<0 ) return 1; for(jj=0; jjnKeyCol; jj++){ if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1; @@ -165597,39 +158880,16 @@ static int whereUsablePartialIndex( return 0; } -/* -** 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; inColumn; i++){ - if( pIdx->aiColumn[i]==XN_EXPR - && 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. +** Information passed in is pWalk->u.pCovIdxCk. Call is 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 @@ -165641,199 +158901,73 @@ struct CoveringIndexCheck { ** ** 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; iiColumn ) 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; + 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 */ + if( pExpr->op!=TK_COLUMN && pExpr->op!=TK_AGG_COLUMN ) return WRC_Continue; + if( pExpr->iColumn<(BMS-1) ) return WRC_Continue; + if( pExpr->iTable!=pWalk->u.pCovIdxCk->iTabCur ) return WRC_Continue; + pIdx = pWalk->u.pCovIdxCk->pIdx; + aiColumn = pIdx->aiColumn; + nColumn = pIdx->nColumn; + for(i=0; iiColumn ) return WRC_Continue; + } + pWalk->eCode = 1; + return WRC_Abort; } /* ** 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 +** pWInfo->pSelect (columns from 0 through 62). But there are columns +** in pWInfo->pSelect beyond 62. This routine tries to answer the question +** of whether pIdx covers *all* columns in the query. ** -** 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. +** Return 0 if pIdx is a covering index. Return non-zero if pIdx is +** not a covering index or if we are unable to determine if pIdx is a +** covering index. ** -** 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. +** This routine is an optimization. It is always safe to return non-zero. +** But returning zero when non-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; + int i; 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; + return 1; } - if( pIdx->bHasExpr==0 ){ - for(i=0; inColumn; 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; - } + for(i=0; inColumn; 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 1; } ck.pIdx = pIdx; ck.iTabCur = iTabCur; - ck.bExpr = 0; - ck.bUnidx = 0; memset(&w, 0, sizeof(w)); w.xExprCallback = whereIsCoveringIndexWalkCallback; w.xSelectCallback = sqlite3SelectWalkNoop; w.u.pCovIdxCk = &ck; + w.eCode = 0; 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 sqlite3ParserAddCleanup() callback that is invoked to -** free the Parse->pIdxEpr list when the Parse object is destroyed. -*/ -static void whereIndexedExprCleanup(sqlite3 *db, void *pObject){ - IndexedExpr **pp = (IndexedExpr**)pObject; - while( *pp!=0 ){ - IndexedExpr *p = *pp; - *pp = p->pIENext; - sqlite3ExprDelete(db, p->pExpr); - 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=; -** SELECT a, b, c FROM t1 WHERE a= AND b=?; -** -** The "a" in the select-list may be replaced by , iff: -** -** (a) is a constant expression, and -** (b) The (a=) 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( !sqlite3ExprIsConstant(0, pRight) ) return; - if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pParse, pPart)) ) return; - if( pLeft->iColumn<0 ) return; - aff = pIdx->pTable->aCol[pLeft->iColumn].affinity; - if( aff>=SQLITE_AFF_TEXT ){ - if( pItem ){ - sqlite3 *db = pParse->db; - IndexedExpr *p = (IndexedExpr*)sqlite3DbMallocRaw(db, sizeof(*p)); - if( p ){ - int bNullRow = (pItem->fg.jointype&(JT_LEFT|JT_LTORJ))!=0; - p->pExpr = 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; - sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pArg); - } - } - }else if( pLeft->iColumn<(BMS-1) ){ - *pMask &= ~((Bitmask)1 << pLeft->iColumn); - } - } - } + return w.eCode; } - /* ** 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 @@ -165872,7 +159006,7 @@ static void wherePartIdxExpr( */ static int whereLoopAddBtree( WhereLoopBuilder *pBuilder, /* WHERE clause information */ - Bitmask mPrereq /* Extra prerequisites for using this table */ + Bitmask mPrereq /* Extra prerequesites for using this table */ ){ WhereInfo *pWInfo; /* WHERE analysis context */ Index *pProbe; /* An index we are evaluating */ @@ -165916,7 +159050,7 @@ static int whereLoopAddBtree( sPk.aiRowLogEst = aiRowEstPk; sPk.onError = OE_Replace; sPk.pTable = pTab; - sPk.szIdxRow = 3; /* TUNING: Interior rows of IPK table are very small */ + sPk.szIdxRow = pTab->szTabRow; sPk.idxType = SQLITE_IDXTYPE_IPK; aiRowEstPk[0] = pTab->nRowLogEst; aiRowEstPk[1] = 0; @@ -165967,8 +159101,7 @@ static int whereLoopAddBtree( if( !IsView(pTab) && (pTab->tabFlags & TF_Ephemeral)==0 ){ pNew->rSetup += 28; }else{ - pNew->rSetup -= 25; /* Greatly reduced setup cost for auto indexes - ** on ephemeral materializations of views */ + pNew->rSetup -= 10; } ApplyCostMultiplier(pNew->rSetup, pTab->costMult); if( pNew->rSetup<0 ) pNew->rSetup = 0; @@ -166037,6 +159170,9 @@ 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); rc = whereLoopInsert(pBuilder, pNew); @@ -166045,45 +159181,14 @@ static int whereLoopAddBtree( }else{ Bitmask m; if( pProbe->isCovering ){ - m = 0; pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED; + m = 0; }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); - 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 || 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; + if( m==TOPBIT ){ + m = whereIsCoveringIndex(pWInfo, pProbe, pSrc->iCursor); } + pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED; } /* Full scan via index */ @@ -166154,7 +159259,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_MaybeReanalyze; + pTab->tabFlags |= TF_StatsUsed; } #ifdef SQLITE_ENABLE_STAT4 sqlite3Stat4ProbeFree(pBuilder->pRec); @@ -166176,21 +159281,6 @@ static int isLimitTerm(WhereTerm *pTerm){ && pTerm->eMatchOp<=SQLITE_INDEX_CONSTRAINT_OFFSET; } -/* -** 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 sqlite3_index_constraint_usage *aUsage, - int nCons -){ - int ii; - for(ii=0; iipNew->iTab. This @@ -166271,7 +159361,7 @@ static int whereLoopAddVirtualOne( ** that the particular combination of parameters provided is unusable. ** Make no entries in the loop table. */ - WHERETRACE(0xffffffff, (" ^^^^--- non-viable plan rejected!\n")); + WHERETRACE(0xffff, (" ^^^^--- non-viable plan rejected!\n")); return SQLITE_OK; } return rc; @@ -166331,20 +159421,13 @@ 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) ); - assert( !isLimitTerm(pTerm) || i>=nConstraint-2 ); - assert( !isLimitTerm(pTerm) || i==nConstraint-1 || isLimitTerm(pTerm+1) ); - - if( isLimitTerm(pTerm) && (*pbIn || !allConstraintsUsed(pUsage, i)) ){ + if( isLimitTerm(pTerm) && *pbIn ){ /* 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. 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. */ + ** 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 ){ sqlite3_free(pIdxInfo->idxStr); pIdxInfo->idxStr = 0; @@ -166389,7 +159472,7 @@ static int whereLoopAddVirtualOne( sqlite3_free(pNew->u.vtab.idxStr); pNew->u.vtab.needFree = 0; } - WHERETRACE(0xffffffff, (" bIn=%d prereqIn=%04llx prereqOut=%04llx\n", + WHERETRACE(0xffff, (" bIn=%d prereqIn=%04llx prereqOut=%04llx\n", *pbIn, (sqlite3_uint64)mPrereq, (sqlite3_uint64)(pNew->prereq & ~mPrereq))); @@ -166405,7 +159488,7 @@ static int whereLoopAddVirtualOne( ** ** Return a pointer to the collation name: ** -** 1. If there is an explicit COLLATE operator on the constraint, return it. +** 1. If there is an explicit COLLATE operator on the constaint, return it. ** ** 2. Else, if the column has an alternative collation, return that. ** @@ -166460,7 +159543,7 @@ SQLITE_API int sqlite3_vtab_rhs_value( sqlite3_value *pVal = 0; int rc = SQLITE_OK; if( iCons<0 || iCons>=pIdxInfo->nConstraint ){ - rc = SQLITE_MISUSE_BKPT; /* EV: R-30545-25046 */ + rc = SQLITE_MISUSE; /* EV: R-30545-25046 */ }else{ if( pH->aRhs[iCons]==0 ){ WhereTerm *pTerm = &pH->pWC->a[pIdxInfo->aConstraint[iCons].iTermOffset]; @@ -166490,27 +159573,32 @@ SQLITE_API int sqlite3_vtab_distinct(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 +** xBestIndex to potentiall 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 sqlite3VtabUsesAllSchemas(Parse *pParse){ +SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(sqlite3_index_info *pIdxInfo){ + HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; + Parse *pParse = pHidden->pParse; int nDb = pParse->db->nDb; int i; for(i=0; iwriteMask) ){ + if( pParse->writeMask ){ for(i=0; ipTab->zName)); - WHERETRACE(0x800, (" VirtualOne: all usable\n")); + WHERETRACE(0x40, (" VirtualOne: all usable\n")); rc = whereLoopAddVirtualOne( pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry ); @@ -166601,7 +159689,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(0x800, (" VirtualOne: all usable w/o IN\n")); + WHERETRACE(0x40, (" VirtualOne: all usable w/o IN\n")); rc = whereLoopAddVirtualOne( pBuilder, mPrereq, ALLBITS, WO_IN, p, mNoOmit, &bIn, 0); assert( bIn==0 ); @@ -166627,7 +159715,7 @@ static int whereLoopAddVirtual( mPrev = mNext; if( mNext==ALLBITS ) break; if( mNext==mBest || mNext==mBestNoIn ) continue; - WHERETRACE(0x800, (" VirtualOne: mPrev=%04llx mNext=%04llx\n", + WHERETRACE(0x40, (" VirtualOne: mPrev=%04llx mNext=%04llx\n", (sqlite3_uint64)mPrev, (sqlite3_uint64)mNext)); rc = whereLoopAddVirtualOne( pBuilder, mPrereq, mNext|mPrereq, 0, p, mNoOmit, &bIn, 0); @@ -166641,7 +159729,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(0x800, (" VirtualOne: all disabled\n")); + WHERETRACE(0x40, (" VirtualOne: all disabled\n")); rc = whereLoopAddVirtualOne( pBuilder, mPrereq, mPrereq, 0, p, mNoOmit, &bIn, 0); if( bIn==0 ) seenZeroNoIN = 1; @@ -166651,7 +159739,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(0x800, (" VirtualOne: all disabled and w/o IN\n")); + WHERETRACE(0x40, (" VirtualOne: all disabled and w/o IN\n")); rc = whereLoopAddVirtualOne( pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn, 0); } @@ -166707,7 +159795,7 @@ static int whereLoopAddOr( sSubBuild = *pBuilder; sSubBuild.pOrSet = &sCur; - WHERETRACE(0x400, ("Begin processing OR-clause %p\n", pTerm)); + WHERETRACE(0x200, ("Begin processing OR-clause %p\n", pTerm)); for(pOrTerm=pOrWC->a; pOrTermeOperator & WO_AND)!=0 ){ sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc; @@ -166724,9 +159812,9 @@ static int whereLoopAddOr( } sCur.n = 0; #ifdef WHERETRACE_ENABLED - WHERETRACE(0x400, ("OR-term %d of %p has %d subterms:\n", + WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n", (int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm)); - if( sqlite3WhereTrace & 0x20000 ){ + if( sqlite3WhereTrace & 0x400 ){ sqlite3WhereClausePrint(sSubBuild.pWC); } #endif @@ -166741,6 +159829,8 @@ 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 ){ @@ -166786,7 +159876,7 @@ static int whereLoopAddOr( pNew->prereq = sSum.a[i].prereq; rc = whereLoopInsert(pBuilder, pNew); } - WHERETRACE(0x400, ("End processing OR-clause %p\n", pTerm)); + WHERETRACE(0x200, ("End processing OR-clause %p\n", pTerm)); } } return rc; @@ -167134,8 +160224,8 @@ static i8 wherePathSatisfiesOrderBy( if( pOBExpr->iTable!=iCur ) continue; if( pOBExpr->iColumn!=iColumn ) continue; }else{ - Expr *pIxExpr = pIndex->aColExpr->a[j].pExpr; - if( sqlite3ExprCompareSkip(pOBExpr, pIxExpr, iCur) ){ + Expr *pIdxExpr = pIndex->aColExpr->a[j].pExpr; + if( sqlite3ExprCompareSkip(pOBExpr, pIdxExpr, iCur) ){ continue; } } @@ -167201,7 +160291,7 @@ static i8 wherePathSatisfiesOrderBy( if( MASKBIT(i) & obSat ) continue; p = pOrderBy->a[i].pExpr; mTerm = sqlite3WhereExprUsage(&pWInfo->sMaskSet,p); - if( mTerm==0 && !sqlite3ExprIsConstant(0,p) ) continue; + if( mTerm==0 && !sqlite3ExprIsConstant(p) ) continue; if( (mTerm&~orderDistinctMask)==0 ){ obSat |= MASKBIT(i); } @@ -167267,56 +160357,37 @@ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){ ** order. */ static LogEst whereSortingCost( - 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 */ + WhereInfo *pWInfo, + LogEst nRow, + int nOrderBy, + int nSorted ){ - /* Estimated cost of a full external sort, where N is + /* TUNING: Estimated cost of a full external sort, where N is ** the number of rows to sort is: ** - ** cost = (K * N * log(N)). + ** cost = (3.0 * 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 = (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. + ** cost = (3.0 * N * log(N)) * (Y/X) ** - ** 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. + ** The (Y/X) term is implemented using stack variable rScale + ** below. */ - LogEst rSortCost, nCol; - assert( pWInfo->pSelect!=0 ); - assert( pWInfo->pSelect->pEList!=0 ); - /* TUNING: sorting cost proportional to the number of output columns: */ - nCol = sqlite3LogEst((pWInfo->pSelect->pEList->nExpr+59)/30); - rSortCost = nRow + nCol; - if( nSorted>0 ){ - /* Scale the result by (Y/X) */ - rSortCost += sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66; - } + LogEst rScale, rSortCost; + assert( nOrderBy>0 && 66==sqlite3LogEst(100) ); + rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66; + rSortCost = nRow + rScale + 16; /* 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 ){ - 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->iLimitiLimit; - } + if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 && pWInfo->iLimitiLimit; }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 */ @@ -167366,8 +160437,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ ** 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, nQueryLoop=%d)\n", - nRowEst, pParse->nQueryLoop)); + 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 @@ -167469,11 +160539,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ pWInfo, nRowEst, nOrderBy, isOrdered ); } - /* TUNING: Add a small extra penalty (3) to sorting as an - ** extra encouragement to the query planner to select a plan + /* TUNING: Add a small extra penalty (5) to sorting as an + ** extra encouragment to the query planner to select a plan ** where the rows emerge in the correct order without any sorting ** required. */ - rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 3; + rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 5; WHERETRACE(0x002, ("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n", @@ -167484,6 +160554,13 @@ 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. ** @@ -167670,9 +160747,6 @@ 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 ){ @@ -167715,6 +160789,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ } } + pWInfo->nRowOut = pFrom->nRow; /* Free temporary memory and return success */ @@ -167722,83 +160797,6 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ 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; inLevel; 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( sqlite3WhereTrace & 0x80 ){ - if( once==0 ){ - sqlite3DebugPrintf("Loops disabled by interstage heuristic:\n"); - once = 1; - } - 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 @@ -167893,7 +160891,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ pLoop->cId = '0'; #endif #ifdef WHERETRACE_ENABLED - if( sqlite3WhereTrace & 0x02 ){ + if( sqlite3WhereTrace ){ sqlite3DebugPrintf("whereShortCut() used to compute solution\n"); } #endif @@ -167960,17 +160958,6 @@ 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: ** @@ -167996,7 +160983,6 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin( ){ int i; Bitmask tabUsed; - int hasRightJoin; /* Preconditions checked by the caller */ assert( pWInfo->nLevel>=2 ); @@ -168011,7 +160997,6 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin( if( pWInfo->pOrderBy ){ tabUsed |= 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; @@ -168034,15 +161019,9 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin( break; } } - if( hasRightJoin - && ExprHasProperty(pTerm->pExpr, EP_InnerON) - && pTerm->pExpr->w.iJoin==pItem->iCursor - ){ - break; /* restriction (5) */ - } } if( pTerm drop loop %c not used\n", pLoop->cId)); + WHERETRACE(0xffff, ("-> drop loop %c not used\n", pLoop->cId)); notReady &= ~pLoop->maskSelf; for(pTerm=pWInfo->sWC.a; pTermprereqAll & pLoop->maskSelf)!=0 ){ @@ -168081,27 +161060,28 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful( const WhereInfo *pWInfo ){ int i; - LogEst nSearch = 0; + LogEst nSearch; assert( pWInfo->nLevel>=2 ); assert( OptimizationEnabled(pWInfo->pParse->db, SQLITE_BloomFilter) ); - for(i=0; inLevel; i++){ + nSearch = pWInfo->a[0].pWLoop->nOut; + for(i=1; inLevel; i++){ 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; - if( (pTab->tabFlags & TF_HasStat1)==0 ) break; - pTab->tabFlags |= TF_MaybeReanalyze; - if( i>=1 - && (pLoop->wsFlags & reqFlags)==reqFlags + if( (pLoop->wsFlags & reqFlags)==reqFlags /* vvvvvv--- Always the case if WHERE_COLUMN_EQ is defined */ && ALWAYS((pLoop->wsFlags & (WHERE_IPK|WHERE_INDEXED))!=0) ){ - if( nSearch > pTab->nRowLogEst ){ + SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab]; + Table *pTab = pItem->pTab; + pTab->tabFlags |= TF_StatsUsed; + if( nSearch > pTab->nRowLogEst + && (pTab->tabFlags & TF_HasStat1)!=0 + ){ testcase( pItem->fg.jointype & JT_LEFT ); pLoop->wsFlags |= WHERE_BLOOMFILTER; pLoop->wsFlags &= ~WHERE_IDX_ONLY; - WHERETRACE(0xffffffff, ( + WHERETRACE(0xffff, ( "-> use Bloom-filter on loop %c because there are ~%.1e " "lookups into %s which has only ~%.1e rows\n", pLoop->cId, (double)sqlite3LogEstToInt(nSearch), pTab->zName, @@ -168113,55 +161093,17 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful( } /* -** Expression Node callback for 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 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. +** This is an sqlite3ParserAddCleanup() callback that is invoked to +** free the Parse->pIdxExpr list when the Parse object is destroyed. */ -static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){ - int n; - FuncDef *pDef; - 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 = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); - if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){ - pWalker->eCode = 1; - return WRC_Prune; +static void whereIndexedExprCleanup(sqlite3 *db, void *pObject){ + Parse *pParse = (Parse*)pObject; + while( pParse->pIdxExpr!=0 ){ + IndexedExpr *p = pParse->pIdxExpr; + pParse->pIdxExpr = p->pIENext; + sqlite3ExprDelete(db, p->pExpr); + sqlite3DbFreeNN(db, p); } - 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 sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){ - Walker w; - memset(&w, 0, sizeof(w)); - w.pParse = pParse; - w.xExprCallback = exprNodeCanReturnSubtype; - sqlite3WalkExpr(&w, pExpr); - return w.eCode; } /* @@ -168170,13 +161112,13 @@ static int sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){ ** 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 +** This routine adds IndexedExpr entries to the Parse->pIdxExpr 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 */ + Parse *pParse, /* Add IndexedExpr entries to pParse->pIdxExpr */ 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 */ @@ -168189,66 +161131,34 @@ static SQLITE_NOINLINE void whereAddIndexedExpr( for(i=0; inColumn; 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 = sqlite3ColumnExpr(pTab, &pTab->aCol[j]); + bMaybeNullRow = 0; }else{ continue; } - if( sqlite3ExprIsConstant(0,pExpr) ) continue; - if( pExpr->op==TK_FUNCTION && 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; - } + if( sqlite3ExprIsConstant(pExpr) ) continue; p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr)); if( p==0 ) break; - p->pIENext = pParse->pIdxEpr; -#ifdef WHERETRACE_ENABLED - if( sqlite3WhereTrace & 0x200 ){ - sqlite3DebugPrintf("New pParse->pIdxEpr term {%d,%d}\n", iIdxCur, i); - if( sqlite3WhereTrace & 0x5000 ) sqlite3ShowExpr(pExpr); - } -#endif + p->pIENext = pParse->pIdxExpr; p->pExpr = 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( sqlite3IndexAffinityStr(pParse->db, pIdx) ){ - p->aff = pIdx->zColAff[i]; - } + p->bMaybeNullRow = bMaybeNullRow; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS p->zIdxName = pIdx->zName; #endif - pParse->pIdxEpr = p; + pParse->pIdxExpr = p; if( p->pIENext==0 ){ - void *pArg = (void*)&pParse->pIdxEpr; - 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; iipTabList->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); + sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pParse); } } } @@ -168311,7 +161221,7 @@ static SQLITE_NOINLINE void whereReverseScanOrder(WhereInfo *pWInfo){ ** ** OUTER JOINS ** -** An outer join of tables t1 and t2 is conceptually coded as follows: +** An outer join of tables t1 and t2 is conceptally coded as follows: ** ** foreach row1 in t1 do ** flag = 0 @@ -168381,11 +161291,7 @@ SQLITE_PRIVATE WhereInfo *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; - wctrlFlags &= ~WHERE_WANT_DISTINCT; - wctrlFlags |= WHERE_KEEP_ALL_JOINS; /* Disable omit-noop-join opt */ - } + if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0; /* The number of tables in the FROM clause is limited by the number of ** bits in a Bitmask @@ -168410,10 +161316,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( ** field (type Bitmask) it must be aligned on an 8-byte boundary on ** some architectures. Hence the ROUND8() below. */ - nByteWInfo = ROUND8P(sizeof(WhereInfo)); - if( nTabList>1 ){ - nByteWInfo = ROUND8P(nByteWInfo + (nTabList-1)*sizeof(WhereLevel)); - } + nByteWInfo = ROUND8P(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel)); pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop)); if( db->mallocFailed ){ sqlite3DbFree(db, pWInfo); @@ -168467,17 +161370,13 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } - if( ALWAYS(pWInfo->pSelect) - && (pWInfo->pSelect->selFlags & SF_MultiValue)==0 - ){ - ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW")); - } + 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<nErr ) goto whereBeginError; - /* 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: + /* 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. ** - ** (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 - ** - ** 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. + ** FROM ... WHERE random()>0; -- eval random() once per row + ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall */ for(ii=0; iinBase; ii++){ - WhereTerm *pT = &sWLB.pWC->a[ii]; /* A term of the WHERE clause */ - Expr *pX; /* The expression of pT */ + WhereTerm *pT = &sWLB.pWC->a[ii]; if( pT->wtFlags & TERM_VIRTUAL ) continue; - 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 ) - ){ - sqlite3ExprIfFalse(pParse, pX, pWInfo->iBreak, SQLITE_JUMPIFNULL); + if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){ + sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL); pT->wtFlags |= TERM_CODED; } } @@ -168572,13 +161448,13 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( /* Construct the WhereLoop objects */ #if defined(WHERETRACE_ENABLED) - if( sqlite3WhereTrace & 0xffffffff ){ + if( sqlite3WhereTrace & 0xffff ){ sqlite3DebugPrintf("*** Optimizer Start *** (wctrlFlags: 0x%x",wctrlFlags); if( wctrlFlags & WHERE_USE_LIMIT ){ sqlite3DebugPrintf(", limit: %d", iAuxArg); } sqlite3DebugPrintf(")\n"); - if( sqlite3WhereTrace & 0x8000 ){ + if( sqlite3WhereTrace & 0x100 ){ Select sSelect; memset(&sSelect, 0, sizeof(sSelect)); sSelect.selFlags = SF_WhereBegin; @@ -168588,10 +161464,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( sSelect.pEList = pResultSet; sqlite3TreeViewSelect(0, &sSelect, 0); } - if( sqlite3WhereTrace & 0x4000 ){ /* Display all WHERE clause terms */ - sqlite3DebugPrintf("---- WHERE clause at start of analysis:\n"); - sqlite3WhereClausePrint(sWLB.pWC); - } + } + if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */ + sqlite3DebugPrintf("---- WHERE clause at start of analysis:\n"); + sqlite3WhereClausePrint(sWLB.pWC); } #endif @@ -168607,7 +161483,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( ** loops will be built using the revised truthProb values. */ if( sWLB.bldFlags2 & SQLITE_BLDF2_2NDPASS ){ WHERETRACE_ALL_LOOPS(pWInfo, sWLB.pWC); - WHERETRACE(0xffffffff, + WHERETRACE(0xffff, ("**** Redo all loop computations due to" " TERM_HIGHTRUTH changes ****\n")); while( pWInfo->pLoops ){ @@ -168624,24 +161500,12 @@ SQLITE_PRIVATE WhereInfo *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 ){ - whereReverseScanOrder(pWInfo); + pWInfo->revMask = ALLBITS; } if( pParse->nErr ){ goto whereBeginError; @@ -168685,10 +161549,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( ** in-line sqlite3WhereCodeOneLoopStart() for performance reasons. */ notReady = ~(Bitmask)0; - 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) */ + if( pWInfo->nLevel>=2 + && pResultSet!=0 /* these two combine to guarantee */ + && 0==(wctrlFlags & WHERE_AGG_DISTINCT) /* condition (1) above */ + && OptimizationEnabled(db, SQLITE_OmitNoopJoin) ){ notReady = whereOmitNoopJoin(pWInfo, notReady); nTabList = pWInfo->nLevel; @@ -168705,11 +161569,11 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( } #if defined(WHERETRACE_ENABLED) - if( sqlite3WhereTrace & 0x4000 ){ /* Display all terms of the WHERE clause */ + if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */ sqlite3DebugPrintf("---- WHERE clause at end of analysis:\n"); sqlite3WhereClausePrint(sWLB.pWC); } - WHERETRACE(0xffffffff,("*** Optimizer Finished ***\n")); + WHERETRACE(0xffff,("*** Optimizer Finished ***\n")); #endif pWInfo->pParse->nQueryLoop += pWInfo->nRowOut; @@ -168741,7 +161605,6 @@ SQLITE_PRIVATE WhereInfo *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) ){ @@ -168805,7 +161668,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( assert( n<=pTab->nCol ); } #ifdef SQLITE_ENABLE_CURSOR_HINTS - if( pLoop->u.btree.pIndex!=0 && (pTab->tabFlags & TF_WithoutRowid)==0 ){ + if( pLoop->u.btree.pIndex!=0 ){ sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ|bFordelete); }else #endif @@ -168850,11 +161713,6 @@ SQLITE_PRIVATE WhereInfo *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 ); @@ -168947,11 +161805,11 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( 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, notReady, pLevel); + constructAutomaticIndex(pParse, &pWInfo->sWC, + &pTabList->a[pLevel->iFrom], notReady, pLevel); #endif }else{ sqlite3ConstructBloomFilter(pWInfo, ii, pLevel, notReady); @@ -168980,11 +161838,6 @@ whereBeginError: pParse->nQueryLoop = pWInfo->savedNQueryLoop; whereInfoFree(db, pWInfo); } -#ifdef WHERETRACE_ENABLED - /* Prevent harmless compiler warnings about debugging routines - ** being declared but never used */ - sqlite3ShowWhereLoopList(0); -#endif /* WHERETRACE_ENABLED */ return 0; } @@ -169008,6 +161861,26 @@ 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 = 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 ** sqlite3WhereBegin() for additional information. @@ -169154,15 +162027,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v); assert( (ws & WHERE_IDX_ONLY)==0 || (ws & WHERE_INDEXED)!=0 ); if( (ws & WHERE_IDX_ONLY)==0 ){ - 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; - sqlite3VdbeAddOp3(v, OP_Null, 0, n, n+m-1); - } + assert( pLevel->iTabCur==pTabList->a[pLevel->iFrom].iCursor ); sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur); } if( (ws & WHERE_INDEXED) @@ -169212,7 +162077,6 @@ SQLITE_PRIVATE void 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; @@ -169243,16 +162107,9 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ last = pWInfo->iEndWhere; } if( pIdx->bHasExpr ){ - IndexedExpr *p = pParse->pIdxEpr; + IndexedExpr *p = pParse->pIdxExpr; while( p ){ if( p->iIdxCur==pLevel->iIdxCur ){ -#ifdef WHERETRACE_ENABLED - if( sqlite3WhereTrace & 0x200 ){ - sqlite3DebugPrintf("Disable pParse->pIdxEpr term {%d,%d}\n", - p->iIdxCur, p->iIdxCol); - if( sqlite3WhereTrace & 0x5000 ) sqlite3ShowExpr(p->pExpr); - } -#endif p->iDataCur = -1; p->iIdxCur = -1; } @@ -169262,8 +162119,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ k = pLevel->addrBody + 1; #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeAddopTrace ){ - printf("TRANSLATE cursor %d->%d in opcode range %d..%d\n", - pLevel->iTabCur, pLevel->iIdxCur, k, last-1); + printf("TRANSLATE opcodes in range %d..%d\n", k, last-1); } /* Proof that the "+1" on the k value above is safe */ pOp = sqlite3VdbeGetOp(v, k - 1); @@ -169307,10 +162163,16 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ ** reference. Verify that this is harmless - that the ** table being referenced really is open. */ - if( pLoop->wsFlags & WHERE_IDX_ONLY ){ - sqlite3ErrorMsg(pParse, "internal query planner error"); - pParse->rc = SQLITE_INTERNAL; - } +#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 } }else if( pOp->opcode==OP_Rowid ){ pOp->p1 = pLevel->iIdxCur; @@ -169464,7 +162326,7 @@ SQLITE_PRIVATE void 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 functions) allows them to +** can be used as either aggregates or window funtions) 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. @@ -169994,7 +162856,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 referred to a named window (as in "max(x) OVER win"), +** * If the OVER clause refered 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. @@ -170132,7 +162994,6 @@ 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; @@ -170385,7 +163246,7 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ assert( ExprUseXList(pWin->pOwner) ); assert( pWin->pWFunc!=0 ); pArgs = pWin->pOwner->x.pList; - if( pWin->pWFunc->funcFlags & SQLITE_SUBTYPE ){ + if( pWin->pWFunc->funcFlags & SQLITE_FUNC_SUBTYPE ){ selectWindowRewriteEList(pParse, pMWin, pSrc, pArgs, pTab, &pSublist); pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); pWin->bExprArgs = 1; @@ -170417,7 +163278,7 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ pSub = sqlite3SelectNew( pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0 ); - TREETRACE(0x40,pParse,pSub, + SELECTTRACE(1,pParse,pSub, ("New window-function subquery in FROM clause of (%u/%p)\n", p->selId, p)); p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); @@ -170427,7 +163288,6 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ if( p->pSrc ){ Table *pTab2; p->pSrc->a[0].pSelect = pSub; - p->pSrc->a[0].fg.isCorrelated = 1; sqlite3SrcListAssignCursors(pParse, p->pSrc); pSub->selFlags |= SF_Expanded|SF_OrderByReqd; pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE); @@ -170511,7 +163371,7 @@ SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p){ ** variable values in the expression tree. */ static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){ - if( 0==sqlite3ExprIsConstant(0,pExpr) ){ + if( 0==sqlite3ExprIsConstant(pExpr) ){ if( IN_RENAME_OBJECT ) sqlite3RenameExprUnmap(pParse, pExpr); sqlite3ExprDelete(pParse->db, pExpr); pExpr = sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0); @@ -170615,7 +163475,7 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble( } /* -** Window *pWin has just been created from a WINDOW clause. Token pBase +** Window *pWin has just been created from a WINDOW clause. Tokne 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 @@ -170659,9 +163519,8 @@ SQLITE_PRIVATE void 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|EP_FullSize); + ExprSetProperty(p, EP_WinFunc); pWin->pOwner = p; if( (p->flags & EP_Distinct) && pWin->eFrmType!=TK_FILTER ){ sqlite3ErrorMsg(pParse, @@ -170922,7 +163781,7 @@ struct WindowCsrAndReg { ** ** (ORDER BY a, b GROUPS BETWEEN 2 PRECEDING AND 2 FOLLOWING) ** -** The windows functions implementation caches the input rows in a temp +** The windows functions implmentation 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 @@ -171931,7 +164790,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 equivalent to "0 PRECEDING/FOLLOWING". +** CURRENT ROW by assuming that it is equivilent 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: @@ -172210,7 +165069,7 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep( } /* Allocate registers for the array of values from the sub-query, the - ** same values in record form, and the rowid used to insert said record + ** samve values in record form, and the rowid used to insert said record ** into the ephemeral table. */ regNew = pParse->nMem+1; pParse->nMem += nInput; @@ -172294,7 +165153,8 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep( VdbeCoverageNeverNullIf(v, op==OP_Ge); /* NeverNull because bound */ VdbeCoverageNeverNullIf(v, op==OP_Le); /* values previously checked */ windowAggFinal(&s, 0); - sqlite3VdbeAddOp1(v, OP_Rewind, s.current.csr); + sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1); + VdbeCoverageNeverTaken(v); windowReturnOneRow(&s); sqlite3VdbeAddOp1(v, OP_ResetSorter, s.current.csr); sqlite3VdbeAddOp2(v, OP_Goto, 0, lblWhereEnd); @@ -172306,10 +165166,13 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep( } if( pMWin->eStart!=TK_UNBOUNDED ){ - sqlite3VdbeAddOp1(v, OP_Rewind, s.start.csr); + sqlite3VdbeAddOp2(v, OP_Rewind, s.start.csr, 1); + VdbeCoverageNeverTaken(v); } - sqlite3VdbeAddOp1(v, OP_Rewind, s.current.csr); - sqlite3VdbeAddOp1(v, OP_Rewind, s.end.csr); + sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1); + VdbeCoverageNeverTaken(v); + sqlite3VdbeAddOp2(v, OP_Rewind, s.end.csr, 1); + VdbeCoverageNeverTaken(v); if( regPeer && pOrderBy ){ sqlite3VdbeAddOp3(v, OP_Copy, regNewPeer, regPeer, pOrderBy->nExpr-1); sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.start.reg, pOrderBy->nExpr-1); @@ -172451,8 +165314,7 @@ SQLITE_PRIVATE void 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 ** @@ -172469,7 +165331,7 @@ SQLITE_PRIVATE void 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 grammar. You might be reading +** implementation of a parser for the given grammer. You might be reading ** this comment as part of the translated C-code. Edits should be made ** to the original parse.y sources. */ @@ -172581,9 +165443,9 @@ static void updateDeleteLimitError( break; } } - if( (p->selFlags & (SF_MultiValue|SF_Values))==0 - && (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 - && cnt>mxSelect + if( (p->selFlags & SF_MultiValue)==0 && + (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 && + cnt>mxSelect ){ sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); } @@ -172603,14 +165465,6 @@ static void updateDeleteLimitError( return pSelect; } - /* Memory allocator for parser stack resizing. This is a thin wrapper around - ** sqlite3_realloc() that includes a call to sqlite3FaultSim() to facilitate - ** testing. - */ - static void *parserStackRealloc(void *pOld, sqlite3_uint64 newSize){ - return sqlite3FaultSim(700) ? 0 : sqlite3_realloc(pOld, newSize); - } - /* Construct a new Expr object from a single token */ static Expr *tokenExpr(Parse *pParse, int op, Token t){ @@ -172860,8 +165714,8 @@ static void updateDeleteLimitError( #define TK_TRUEFALSE 170 #define TK_ISNOT 171 #define TK_FUNCTION 172 -#define TK_UPLUS 173 -#define TK_UMINUS 174 +#define TK_UMINUS 173 +#define TK_UPLUS 174 #define TK_TRUTH 175 #define TK_REGISTER 176 #define TK_VECTOR 177 @@ -172870,9 +165724,8 @@ static void updateDeleteLimitError( #define TK_ASTERISK 180 #define TK_SPAN 181 #define TK_ERROR 182 -#define TK_QNUMBER 183 -#define TK_SPACE 184 -#define TK_ILLEGAL 185 +#define TK_SPACE 183 +#define TK_ILLEGAL 184 #endif /**************** End token definitions ***************************************/ @@ -172913,9 +165766,6 @@ static void updateDeleteLimitError( ** sqlite3ParserARG_STORE Code to store %extra_argument into yypParser ** sqlite3ParserARG_FETCH Code to extract %extra_argument from yypParser ** sqlite3ParserCTX_* As 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. @@ -172929,39 +165779,37 @@ 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 322 +#define YYNOCODE 319 #define YYACTIONTYPE unsigned short int #define YYWILDCARD 101 #define sqlite3ParserTOKENTYPE Token typedef union { int yyinit; sqlite3ParserTOKENTYPE yy0; - 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; + 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; } YYMINORTYPE; #ifndef YYSTACKDEPTH #define YYSTACKDEPTH 100 @@ -172971,29 +165819,24 @@ typedef union { #define sqlite3ParserARG_PARAM #define sqlite3ParserARG_FETCH #define sqlite3ParserARG_STORE -#define YYREALLOC parserStackRealloc -#define YYFREE sqlite3_free -#define YYDYNSTACK 1 #define sqlite3ParserCTX_SDECL Parse *pParse; #define sqlite3ParserCTX_PDECL ,Parse *pParse #define sqlite3ParserCTX_PARAM ,pParse #define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse; #define sqlite3ParserCTX_STORE yypParser->pParse=pParse; #define YYFALLBACK 1 -#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 +#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 /************* End control #defines *******************************************/ #define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0]))) @@ -173009,22 +165852,6 @@ 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 @@ -173076,630 +165903,618 @@ typedef union { ** yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ -#define YY_ACTTAB_COUNT (2142) +#define YY_ACTTAB_COUNT (2098) static const YYACTIONTYPE yy_action[] = { - /* 0 */ 576, 128, 125, 232, 1622, 549, 576, 1290, 1281, 576, - /* 10 */ 328, 576, 1300, 212, 576, 128, 125, 232, 578, 412, - /* 20 */ 578, 391, 1542, 51, 51, 523, 405, 1293, 529, 51, - /* 30 */ 51, 983, 51, 51, 81, 81, 1107, 61, 61, 984, - /* 40 */ 1107, 1292, 380, 135, 136, 90, 1228, 1228, 1063, 1066, - /* 50 */ 1053, 1053, 133, 133, 134, 134, 134, 134, 1577, 412, - /* 60 */ 287, 287, 7, 287, 287, 422, 1050, 1050, 1064, 1067, - /* 70 */ 289, 556, 492, 573, 524, 561, 573, 497, 561, 482, - /* 80 */ 530, 262, 229, 135, 136, 90, 1228, 1228, 1063, 1066, - /* 90 */ 1053, 1053, 133, 133, 134, 134, 134, 134, 128, 125, - /* 100 */ 232, 1506, 132, 132, 132, 132, 131, 131, 130, 130, - /* 110 */ 130, 129, 126, 450, 1204, 1255, 1, 1, 582, 2, - /* 120 */ 1259, 1571, 420, 1582, 379, 320, 1174, 153, 1174, 1584, - /* 130 */ 412, 378, 1582, 543, 1341, 330, 111, 570, 570, 570, - /* 140 */ 293, 1054, 132, 132, 132, 132, 131, 131, 130, 130, - /* 150 */ 130, 129, 126, 450, 135, 136, 90, 1228, 1228, 1063, - /* 160 */ 1066, 1053, 1053, 133, 133, 134, 134, 134, 134, 287, - /* 170 */ 287, 1204, 1205, 1204, 255, 287, 287, 510, 507, 506, - /* 180 */ 137, 455, 573, 212, 561, 447, 446, 505, 573, 1616, - /* 190 */ 561, 134, 134, 134, 134, 127, 400, 243, 132, 132, - /* 200 */ 132, 132, 131, 131, 130, 130, 130, 129, 126, 450, - /* 210 */ 282, 471, 345, 132, 132, 132, 132, 131, 131, 130, - /* 220 */ 130, 130, 129, 126, 450, 574, 155, 936, 936, 454, - /* 230 */ 227, 521, 1236, 412, 1236, 134, 134, 134, 134, 132, - /* 240 */ 132, 132, 132, 131, 131, 130, 130, 130, 129, 126, - /* 250 */ 450, 130, 130, 130, 129, 126, 450, 135, 136, 90, - /* 260 */ 1228, 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, - /* 270 */ 134, 134, 128, 125, 232, 450, 576, 412, 397, 1249, - /* 280 */ 180, 92, 93, 132, 132, 132, 132, 131, 131, 130, - /* 290 */ 130, 130, 129, 126, 450, 381, 387, 1204, 383, 81, - /* 300 */ 81, 135, 136, 90, 1228, 1228, 1063, 1066, 1053, 1053, - /* 310 */ 133, 133, 134, 134, 134, 134, 132, 132, 132, 132, - /* 320 */ 131, 131, 130, 130, 130, 129, 126, 450, 131, 131, - /* 330 */ 130, 130, 130, 129, 126, 450, 556, 1204, 302, 319, - /* 340 */ 567, 121, 568, 480, 4, 555, 1149, 1657, 1628, 1657, - /* 350 */ 45, 128, 125, 232, 1204, 1205, 1204, 1250, 571, 1169, - /* 360 */ 132, 132, 132, 132, 131, 131, 130, 130, 130, 129, - /* 370 */ 126, 450, 1169, 287, 287, 1169, 1019, 576, 422, 1019, - /* 380 */ 412, 451, 1602, 582, 2, 1259, 573, 44, 561, 95, - /* 390 */ 320, 110, 153, 565, 1204, 1205, 1204, 522, 522, 1341, - /* 400 */ 81, 81, 7, 44, 135, 136, 90, 1228, 1228, 1063, - /* 410 */ 1066, 1053, 1053, 133, 133, 134, 134, 134, 134, 295, - /* 420 */ 1149, 1658, 1040, 1658, 1204, 1147, 319, 567, 119, 119, - /* 430 */ 343, 466, 331, 343, 287, 287, 120, 556, 451, 577, - /* 440 */ 451, 1169, 1169, 1028, 319, 567, 438, 573, 210, 561, - /* 450 */ 1339, 1451, 546, 531, 1169, 1169, 1598, 1169, 1169, 416, - /* 460 */ 319, 567, 243, 132, 132, 132, 132, 131, 131, 130, - /* 470 */ 130, 130, 129, 126, 450, 1028, 1028, 1030, 1031, 35, - /* 480 */ 44, 1204, 1205, 1204, 472, 287, 287, 1328, 412, 1307, - /* 490 */ 372, 1595, 359, 225, 454, 1204, 195, 1328, 573, 1147, - /* 500 */ 561, 1333, 1333, 274, 576, 1188, 576, 340, 46, 196, - /* 510 */ 537, 217, 135, 136, 90, 1228, 1228, 1063, 1066, 1053, - /* 520 */ 1053, 133, 133, 134, 134, 134, 134, 19, 19, 19, - /* 530 */ 19, 412, 581, 1204, 1259, 511, 1204, 319, 567, 320, - /* 540 */ 944, 153, 425, 491, 430, 943, 1204, 488, 1341, 1450, - /* 550 */ 532, 1277, 1204, 1205, 1204, 135, 136, 90, 1228, 1228, - /* 560 */ 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, 134, - /* 570 */ 575, 132, 132, 132, 132, 131, 131, 130, 130, 130, - /* 580 */ 129, 126, 450, 287, 287, 528, 287, 287, 372, 1595, - /* 590 */ 1204, 1205, 1204, 1204, 1205, 1204, 573, 486, 561, 573, - /* 600 */ 889, 561, 412, 1204, 1205, 1204, 886, 40, 22, 22, - /* 610 */ 220, 243, 525, 1449, 132, 132, 132, 132, 131, 131, - /* 620 */ 130, 130, 130, 129, 126, 450, 135, 136, 90, 1228, - /* 630 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, - /* 640 */ 134, 412, 180, 454, 1204, 879, 255, 287, 287, 510, - /* 650 */ 507, 506, 372, 1595, 1568, 1331, 1331, 576, 889, 505, - /* 660 */ 573, 44, 561, 559, 1207, 135, 136, 90, 1228, 1228, - /* 670 */ 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, 134, - /* 680 */ 81, 81, 422, 576, 377, 132, 132, 132, 132, 131, - /* 690 */ 131, 130, 130, 130, 129, 126, 450, 297, 287, 287, - /* 700 */ 460, 1204, 1205, 1204, 1204, 534, 19, 19, 448, 448, - /* 710 */ 448, 573, 412, 561, 230, 436, 1187, 535, 319, 567, - /* 720 */ 363, 432, 1207, 1435, 132, 132, 132, 132, 131, 131, - /* 730 */ 130, 130, 130, 129, 126, 450, 135, 136, 90, 1228, - /* 740 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, - /* 750 */ 134, 412, 211, 949, 1169, 1041, 1110, 1110, 494, 547, - /* 760 */ 547, 1204, 1205, 1204, 7, 539, 1570, 1169, 376, 576, - /* 770 */ 1169, 5, 1204, 486, 3, 135, 136, 90, 1228, 1228, - /* 780 */ 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, 134, - /* 790 */ 576, 513, 19, 19, 427, 132, 132, 132, 132, 131, - /* 800 */ 131, 130, 130, 130, 129, 126, 450, 305, 1204, 433, - /* 810 */ 225, 1204, 385, 19, 19, 273, 290, 371, 516, 366, - /* 820 */ 515, 260, 412, 538, 1568, 549, 1024, 362, 437, 1204, - /* 830 */ 1205, 1204, 902, 1552, 132, 132, 132, 132, 131, 131, - /* 840 */ 130, 130, 130, 129, 126, 450, 135, 136, 90, 1228, - /* 850 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, - /* 860 */ 134, 412, 1435, 514, 1281, 1204, 1205, 1204, 1204, 1205, - /* 870 */ 1204, 903, 48, 342, 1568, 1568, 1279, 1627, 1568, 911, - /* 880 */ 576, 129, 126, 450, 110, 135, 136, 90, 1228, 1228, - /* 890 */ 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, 134, - /* 900 */ 265, 576, 459, 19, 19, 132, 132, 132, 132, 131, - /* 910 */ 131, 130, 130, 130, 129, 126, 450, 1345, 204, 576, - /* 920 */ 459, 458, 50, 47, 19, 19, 49, 434, 1105, 573, - /* 930 */ 497, 561, 412, 428, 108, 1224, 1569, 1554, 376, 205, - /* 940 */ 550, 550, 81, 81, 132, 132, 132, 132, 131, 131, - /* 950 */ 130, 130, 130, 129, 126, 450, 135, 136, 90, 1228, - /* 960 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, - /* 970 */ 134, 480, 576, 1204, 576, 1541, 412, 1435, 969, 315, - /* 980 */ 1659, 398, 284, 497, 969, 893, 1569, 1569, 376, 376, - /* 990 */ 1569, 461, 376, 1224, 459, 80, 80, 81, 81, 497, - /* 1000 */ 374, 114, 90, 1228, 1228, 1063, 1066, 1053, 1053, 133, - /* 1010 */ 133, 134, 134, 134, 134, 132, 132, 132, 132, 131, - /* 1020 */ 131, 130, 130, 130, 129, 126, 450, 1204, 1505, 576, - /* 1030 */ 1204, 1205, 1204, 1366, 316, 486, 281, 281, 497, 431, - /* 1040 */ 557, 288, 288, 402, 1340, 471, 345, 298, 429, 573, - /* 1050 */ 576, 561, 81, 81, 573, 374, 561, 971, 386, 132, - /* 1060 */ 132, 132, 132, 131, 131, 130, 130, 130, 129, 126, - /* 1070 */ 450, 231, 117, 81, 81, 287, 287, 231, 287, 287, - /* 1080 */ 576, 1511, 576, 1336, 1204, 1205, 1204, 139, 573, 556, - /* 1090 */ 561, 573, 412, 561, 441, 456, 969, 213, 558, 1511, - /* 1100 */ 1513, 1550, 969, 143, 143, 145, 145, 1368, 314, 478, - /* 1110 */ 444, 970, 412, 850, 851, 852, 135, 136, 90, 1228, - /* 1120 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, - /* 1130 */ 134, 357, 412, 397, 1148, 304, 135, 136, 90, 1228, - /* 1140 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, - /* 1150 */ 134, 1575, 323, 6, 862, 7, 135, 124, 90, 1228, - /* 1160 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, - /* 1170 */ 134, 409, 408, 1511, 212, 132, 132, 132, 132, 131, - /* 1180 */ 131, 130, 130, 130, 129, 126, 450, 411, 118, 1204, - /* 1190 */ 116, 10, 352, 265, 355, 132, 132, 132, 132, 131, - /* 1200 */ 131, 130, 130, 130, 129, 126, 450, 576, 324, 306, - /* 1210 */ 576, 306, 1250, 469, 158, 132, 132, 132, 132, 131, - /* 1220 */ 131, 130, 130, 130, 129, 126, 450, 207, 1224, 1126, - /* 1230 */ 65, 65, 470, 66, 66, 412, 447, 446, 882, 531, - /* 1240 */ 335, 258, 257, 256, 1127, 1233, 1204, 1205, 1204, 327, - /* 1250 */ 1235, 874, 159, 576, 16, 480, 1085, 1040, 1234, 1128, - /* 1260 */ 136, 90, 1228, 1228, 1063, 1066, 1053, 1053, 133, 133, - /* 1270 */ 134, 134, 134, 134, 1029, 576, 81, 81, 1028, 1040, - /* 1280 */ 922, 576, 463, 1236, 576, 1236, 1224, 502, 107, 1435, - /* 1290 */ 923, 6, 576, 410, 1498, 882, 1029, 480, 21, 21, - /* 1300 */ 1028, 332, 1380, 334, 53, 53, 497, 81, 81, 874, - /* 1310 */ 1028, 1028, 1030, 445, 259, 19, 19, 533, 132, 132, - /* 1320 */ 132, 132, 131, 131, 130, 130, 130, 129, 126, 450, - /* 1330 */ 551, 301, 1028, 1028, 1030, 107, 532, 545, 121, 568, - /* 1340 */ 1188, 4, 1126, 1576, 449, 576, 462, 7, 1282, 418, - /* 1350 */ 462, 350, 1435, 576, 518, 571, 544, 1127, 121, 568, - /* 1360 */ 442, 4, 1188, 464, 533, 1180, 1223, 9, 67, 67, - /* 1370 */ 487, 576, 1128, 303, 410, 571, 54, 54, 451, 576, - /* 1380 */ 123, 944, 576, 417, 576, 333, 943, 1379, 576, 236, - /* 1390 */ 565, 576, 1574, 564, 68, 68, 7, 576, 451, 362, - /* 1400 */ 419, 182, 69, 69, 541, 70, 70, 71, 71, 540, - /* 1410 */ 565, 72, 72, 484, 55, 55, 473, 1180, 296, 1040, - /* 1420 */ 56, 56, 296, 493, 541, 119, 119, 410, 1573, 542, - /* 1430 */ 569, 418, 7, 120, 1244, 451, 577, 451, 465, 1040, - /* 1440 */ 1028, 576, 1557, 552, 476, 119, 119, 527, 259, 121, - /* 1450 */ 568, 240, 4, 120, 576, 451, 577, 451, 576, 477, - /* 1460 */ 1028, 576, 156, 576, 57, 57, 571, 576, 286, 229, - /* 1470 */ 410, 336, 1028, 1028, 1030, 1031, 35, 59, 59, 219, - /* 1480 */ 983, 60, 60, 220, 73, 73, 74, 74, 984, 451, - /* 1490 */ 75, 75, 1028, 1028, 1030, 1031, 35, 96, 216, 291, - /* 1500 */ 552, 565, 1188, 318, 395, 395, 394, 276, 392, 576, - /* 1510 */ 485, 859, 474, 1311, 410, 541, 576, 417, 1530, 1144, - /* 1520 */ 540, 399, 1188, 292, 237, 1153, 326, 38, 23, 576, - /* 1530 */ 1040, 576, 20, 20, 325, 299, 119, 119, 164, 76, - /* 1540 */ 76, 1529, 121, 568, 120, 4, 451, 577, 451, 203, - /* 1550 */ 576, 1028, 141, 141, 142, 142, 576, 322, 39, 571, - /* 1560 */ 341, 1021, 110, 264, 239, 901, 900, 423, 242, 908, - /* 1570 */ 909, 370, 173, 77, 77, 43, 479, 1310, 264, 62, - /* 1580 */ 62, 369, 451, 1028, 1028, 1030, 1031, 35, 1601, 1192, - /* 1590 */ 453, 1092, 238, 291, 565, 163, 1309, 110, 395, 395, - /* 1600 */ 394, 276, 392, 986, 987, 859, 481, 346, 264, 110, - /* 1610 */ 1032, 489, 576, 1188, 503, 1088, 261, 261, 237, 576, - /* 1620 */ 326, 121, 568, 1040, 4, 347, 1376, 413, 325, 119, - /* 1630 */ 119, 948, 319, 567, 351, 78, 78, 120, 571, 451, - /* 1640 */ 577, 451, 79, 79, 1028, 354, 356, 576, 360, 1092, - /* 1650 */ 110, 576, 974, 942, 264, 123, 457, 358, 239, 576, - /* 1660 */ 519, 451, 939, 1104, 123, 1104, 173, 576, 1032, 43, - /* 1670 */ 63, 63, 1324, 565, 168, 168, 1028, 1028, 1030, 1031, - /* 1680 */ 35, 576, 169, 169, 1308, 872, 238, 157, 1589, 576, - /* 1690 */ 86, 86, 365, 89, 568, 375, 4, 1103, 941, 1103, - /* 1700 */ 123, 576, 1040, 1389, 64, 64, 1188, 1434, 119, 119, - /* 1710 */ 571, 576, 82, 82, 563, 576, 120, 165, 451, 577, - /* 1720 */ 451, 413, 1362, 1028, 144, 144, 319, 567, 576, 1374, - /* 1730 */ 562, 498, 279, 451, 83, 83, 1439, 576, 166, 166, - /* 1740 */ 576, 1289, 554, 576, 1280, 565, 576, 12, 576, 1268, - /* 1750 */ 457, 146, 146, 1267, 576, 1028, 1028, 1030, 1031, 35, - /* 1760 */ 140, 140, 1269, 167, 167, 1609, 160, 160, 1359, 150, - /* 1770 */ 150, 149, 149, 311, 1040, 576, 312, 147, 147, 313, - /* 1780 */ 119, 119, 222, 235, 576, 1188, 396, 576, 120, 576, - /* 1790 */ 451, 577, 451, 1192, 453, 1028, 508, 291, 148, 148, - /* 1800 */ 1421, 1612, 395, 395, 394, 276, 392, 85, 85, 859, - /* 1810 */ 87, 87, 84, 84, 553, 576, 294, 576, 1426, 338, - /* 1820 */ 339, 1425, 237, 300, 326, 1416, 1409, 1028, 1028, 1030, - /* 1830 */ 1031, 35, 325, 344, 403, 483, 226, 1307, 52, 52, - /* 1840 */ 58, 58, 368, 1371, 1502, 566, 1501, 121, 568, 221, - /* 1850 */ 4, 208, 268, 209, 390, 1244, 1549, 1188, 1372, 1370, - /* 1860 */ 1369, 1547, 239, 184, 571, 233, 421, 1241, 95, 218, - /* 1870 */ 173, 1507, 193, 43, 91, 94, 178, 186, 467, 188, - /* 1880 */ 468, 1422, 13, 189, 190, 191, 501, 451, 245, 108, - /* 1890 */ 238, 401, 1428, 1427, 1430, 475, 404, 1496, 197, 565, - /* 1900 */ 14, 490, 249, 101, 1518, 496, 349, 280, 251, 201, - /* 1910 */ 353, 499, 252, 406, 1270, 253, 517, 1327, 1326, 435, - /* 1920 */ 1325, 1318, 103, 893, 1296, 413, 227, 407, 1040, 1626, - /* 1930 */ 319, 567, 1625, 1297, 119, 119, 439, 367, 1317, 1295, - /* 1940 */ 1624, 526, 120, 440, 451, 577, 451, 1594, 309, 1028, - /* 1950 */ 310, 373, 266, 267, 457, 1580, 1579, 443, 138, 1394, - /* 1960 */ 552, 1393, 11, 1483, 384, 115, 317, 1350, 109, 536, - /* 1970 */ 42, 579, 382, 214, 1349, 388, 1198, 389, 275, 277, - /* 1980 */ 278, 1028, 1028, 1030, 1031, 35, 580, 1265, 414, 1260, - /* 1990 */ 170, 415, 183, 1534, 1535, 1533, 171, 154, 307, 1532, - /* 2000 */ 846, 223, 224, 88, 452, 215, 172, 321, 234, 1102, - /* 2010 */ 152, 1188, 1100, 329, 185, 174, 1223, 925, 187, 241, - /* 2020 */ 337, 244, 1116, 192, 175, 176, 424, 426, 97, 194, - /* 2030 */ 98, 99, 100, 177, 1119, 1115, 246, 247, 161, 24, - /* 2040 */ 248, 348, 1238, 264, 1108, 250, 495, 199, 198, 15, - /* 2050 */ 861, 500, 369, 254, 504, 509, 512, 200, 102, 25, - /* 2060 */ 179, 361, 26, 364, 104, 891, 308, 162, 105, 904, - /* 2070 */ 520, 106, 1185, 1069, 1155, 17, 228, 27, 1154, 283, - /* 2080 */ 285, 263, 978, 202, 972, 123, 28, 1175, 29, 30, - /* 2090 */ 1179, 1171, 31, 1173, 1160, 41, 32, 206, 548, 33, - /* 2100 */ 110, 1178, 1083, 8, 112, 1070, 113, 1068, 1072, 34, - /* 2110 */ 1073, 560, 1125, 269, 1124, 270, 36, 18, 1194, 1033, - /* 2120 */ 873, 151, 122, 37, 393, 271, 272, 572, 181, 1193, - /* 2130 */ 1256, 1256, 1256, 935, 1256, 1256, 1256, 1256, 1256, 1256, - /* 2140 */ 1256, 1617, + /* 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, }; static const YYCODETYPE yy_lookahead[] = { - /* 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, + /* 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, 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, + /* 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, 108, 109, 110, 111, 112, 113, 43, 44, 45, + /* 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, 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, + /* 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, 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, + /* 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, 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, + /* 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 */ 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, + /* 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 */ 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, + /* 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, 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, + /* 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 */ 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, + /* 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, 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, + /* 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 */ 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, + /* 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, 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, + /* 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 */ 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, + /* 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, 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, + /* 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, 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, + /* 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, 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, + /* 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, 16, 19, 22, 23, 294, 43, 44, 45, 46, + /* 1130 */ 57, 238, 19, 59, 193, 59, 43, 44, 45, 46, /* 1140 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 1150 */ 57, 312, 194, 214, 21, 316, 43, 44, 45, 46, + /* 1150 */ 57, 22, 23, 193, 25, 193, 43, 44, 45, 46, /* 1160 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 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, + /* 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, 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, + /* 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 */ 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, 43, 235, 18, 238, - /* 1880 */ 201, 274, 272, 238, 238, 238, 18, 59, 200, 149, - /* 1890 */ 98, 247, 274, 274, 235, 247, 247, 247, 235, 71, - /* 1900 */ 272, 201, 200, 158, 292, 62, 291, 201, 200, 22, - /* 1910 */ 201, 222, 200, 222, 201, 200, 115, 219, 219, 64, - /* 1920 */ 219, 228, 22, 126, 221, 133, 165, 222, 100, 225, - /* 1930 */ 138, 139, 225, 219, 106, 107, 24, 219, 228, 219, - /* 1940 */ 219, 307, 114, 113, 116, 117, 118, 315, 284, 121, - /* 1950 */ 284, 222, 201, 91, 162, 320, 320, 82, 148, 267, - /* 1960 */ 145, 267, 22, 279, 201, 158, 281, 251, 147, 146, - /* 1970 */ 25, 203, 250, 249, 251, 248, 13, 247, 195, 195, - /* 1980 */ 6, 153, 154, 155, 156, 157, 193, 193, 305, 193, - /* 1990 */ 208, 305, 302, 214, 214, 214, 208, 223, 223, 214, - /* 2000 */ 4, 215, 215, 214, 3, 22, 208, 163, 15, 23, - /* 2010 */ 16, 183, 23, 139, 151, 130, 25, 20, 142, 24, - /* 2020 */ 16, 144, 1, 142, 130, 130, 61, 37, 53, 151, - /* 2030 */ 53, 53, 53, 130, 116, 1, 34, 141, 5, 22, - /* 2040 */ 115, 161, 75, 25, 68, 141, 41, 115, 68, 24, - /* 2050 */ 20, 19, 131, 125, 67, 67, 96, 22, 22, 22, - /* 2060 */ 37, 23, 22, 24, 22, 59, 67, 23, 149, 28, - /* 2070 */ 22, 25, 23, 23, 23, 22, 141, 34, 97, 23, - /* 2080 */ 23, 34, 116, 22, 143, 25, 34, 75, 34, 34, - /* 2090 */ 75, 88, 34, 86, 23, 22, 34, 25, 24, 34, - /* 2100 */ 25, 93, 23, 44, 142, 23, 142, 23, 23, 22, - /* 2110 */ 11, 25, 23, 25, 23, 22, 22, 22, 1, 23, - /* 2120 */ 23, 23, 22, 22, 15, 141, 141, 25, 25, 1, - /* 2130 */ 322, 322, 322, 135, 322, 322, 322, 322, 322, 322, - /* 2140 */ 322, 141, 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, 322, 322, 322, 322, + /* 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, }; -#define YY_SHIFT_COUNT (582) +#define YY_SHIFT_COUNT (575) #define YY_SHIFT_MIN (0) -#define YY_SHIFT_MAX (2128) +#define YY_SHIFT_MAX (2074) static const unsigned short int yy_shift_ofst[] = { - /* 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, 2142, 2142, - /* 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, 2142, 2142, 2142, 2142, 2142, - /* 220 */ 2142, 2142, 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, 1833, 1860, 1860, 1860, 1860, 1711, 1868, 1740, 1719, - /* 340 */ 1719, 1740, 1850, 1833, 1740, 1833, 1740, 1711, 1868, 1745, - /* 350 */ 1843, 1711, 1868, 1887, 1711, 1868, 1711, 1868, 1887, 1801, - /* 360 */ 1801, 1801, 1855, 1900, 1900, 1887, 1801, 1797, 1801, 1855, - /* 370 */ 1801, 1801, 1761, 1912, 1830, 1830, 1887, 1711, 1862, 1862, - /* 380 */ 1875, 1875, 1810, 1815, 1940, 1711, 1807, 1810, 1821, 1823, - /* 390 */ 1740, 1945, 1963, 1963, 1974, 1974, 1974, 2142, 2142, 2142, - /* 400 */ 2142, 2142, 2142, 2142, 2142, 2142, 2142, 2142, 2142, 2142, - /* 410 */ 2142, 2142, 20, 1224, 256, 1111, 1115, 1114, 1192, 1496, - /* 420 */ 1424, 1505, 1427, 355, 1383, 1537, 1506, 1538, 1553, 1583, - /* 430 */ 1584, 1591, 1625, 541, 1445, 1562, 1450, 1572, 1515, 1428, - /* 440 */ 1532, 1592, 1629, 1520, 1630, 1639, 1510, 1544, 1662, 1675, - /* 450 */ 1551, 48, 1996, 2001, 1983, 1844, 1993, 1994, 1986, 1989, - /* 460 */ 1874, 1863, 1885, 1991, 1991, 1995, 1876, 1997, 1877, 2004, - /* 470 */ 2021, 1881, 1894, 1991, 1895, 1965, 1990, 1991, 1878, 1975, - /* 480 */ 1977, 1978, 1979, 1903, 1918, 2002, 1896, 2034, 2033, 2017, - /* 490 */ 1925, 1880, 1976, 2018, 1980, 1967, 2005, 1904, 1932, 2025, - /* 500 */ 2030, 2032, 1921, 1928, 2035, 1987, 2036, 2037, 2038, 2040, - /* 510 */ 1988, 2006, 2039, 1960, 2041, 2042, 1999, 2023, 2044, 2043, - /* 520 */ 1919, 2048, 2049, 2050, 2046, 2051, 2053, 1981, 1935, 2056, - /* 530 */ 2057, 1966, 2047, 2061, 1941, 2060, 2052, 2054, 2055, 2058, - /* 540 */ 2003, 2012, 2007, 2059, 2015, 2008, 2062, 2071, 2073, 2074, - /* 550 */ 2072, 2075, 2065, 1962, 1964, 2079, 2060, 2082, 2084, 2085, - /* 560 */ 2087, 2086, 2089, 2088, 2091, 2093, 2099, 2094, 2095, 2096, - /* 570 */ 2097, 2100, 2101, 2102, 1998, 1984, 1985, 2000, 2103, 2098, - /* 580 */ 2109, 2117, 2128, + /* 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, }; -#define YY_REDUCE_COUNT (411) -#define YY_REDUCE_MIN (-275) -#define YY_REDUCE_MAX (1798) +#define YY_REDUCE_COUNT (408) +#define YY_REDUCE_MIN (-271) +#define YY_REDUCE_MAX (1740) static const short yy_reduce_ofst[] = { - /* 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, 1642, 1641, 1645, 1646, 1647, 1679, 1688, 1644, 1618, - /* 340 */ 1619, 1648, 1628, 1659, 1649, 1663, 1650, 1700, 1702, 1612, - /* 350 */ 1615, 1706, 1708, 1689, 1709, 1712, 1713, 1715, 1691, 1698, - /* 360 */ 1699, 1701, 1693, 1704, 1707, 1705, 1714, 1703, 1718, 1710, - /* 370 */ 1720, 1721, 1632, 1634, 1664, 1666, 1729, 1751, 1635, 1636, - /* 380 */ 1692, 1694, 1716, 1722, 1684, 1763, 1685, 1723, 1724, 1727, - /* 390 */ 1730, 1768, 1783, 1784, 1793, 1794, 1796, 1683, 1686, 1690, - /* 400 */ 1782, 1779, 1780, 1781, 1785, 1788, 1774, 1775, 1786, 1787, - /* 410 */ 1789, 1798, + /* 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, }; static const YYACTIONTYPE yy_default[] = { - /* 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, 1543, 1545, 1508, 1420, 1419, - /* 70 */ 1418, 1417, 1526, 1385, 1411, 1404, 1408, 1487, 1488, 1486, - /* 80 */ 1641, 1493, 1492, 1254, 1407, 1455, 1471, 1454, 1254, 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 */ 1463, 1470, 1469, 1468, 1477, 1467, 1464, 1457, 1456, 1458, - /* 150 */ 1459, 1278, 1254, 1275, 1329, 1254, 1254, 1254, 1254, 1254, - /* 160 */ 1460, 1287, 1448, 1447, 1446, 1254, 1474, 1461, 1473, 1472, - /* 170 */ 1551, 1615, 1614, 1509, 1254, 1254, 1254, 1254, 1254, 1254, - /* 180 */ 1578, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 190 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 200 */ 1254, 1254, 1254, 1387, 1578, 1578, 1254, 1287, 1578, 1578, - /* 210 */ 1388, 1388, 1283, 1283, 1391, 1558, 1358, 1358, 1358, 1358, - /* 220 */ 1367, 1358, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 230 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1548, 1546, 1254, - /* 240 */ 1254, 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, 1363, 1254, 1254, 1254, - /* 270 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1608, 1254, - /* 280 */ 1521, 1343, 1363, 1363, 1363, 1363, 1365, 1344, 1342, 1357, - /* 290 */ 1288, 1261, 1655, 1423, 1412, 1364, 1412, 1652, 1410, 1423, - /* 300 */ 1423, 1410, 1423, 1364, 1652, 1304, 1630, 1299, 1397, 1397, - /* 310 */ 1397, 1387, 1387, 1387, 1387, 1391, 1391, 1489, 1364, 1357, - /* 320 */ 1254, 1655, 1655, 1373, 1373, 1654, 1654, 1373, 1509, 1638, - /* 330 */ 1432, 1332, 1338, 1338, 1338, 1338, 1373, 1272, 1410, 1638, - /* 340 */ 1638, 1410, 1432, 1332, 1410, 1332, 1410, 1373, 1272, 1525, - /* 350 */ 1649, 1373, 1272, 1499, 1373, 1272, 1373, 1272, 1499, 1330, - /* 360 */ 1330, 1330, 1319, 1254, 1254, 1499, 1330, 1304, 1330, 1319, - /* 370 */ 1330, 1330, 1596, 1254, 1503, 1503, 1499, 1373, 1588, 1588, - /* 380 */ 1400, 1400, 1405, 1391, 1494, 1373, 1254, 1405, 1403, 1401, - /* 390 */ 1410, 1322, 1611, 1611, 1607, 1607, 1607, 1660, 1660, 1558, - /* 400 */ 1623, 1287, 1287, 1287, 1287, 1623, 1306, 1306, 1288, 1288, - /* 410 */ 1287, 1623, 1254, 1254, 1254, 1254, 1254, 1254, 1618, 1254, - /* 420 */ 1553, 1510, 1377, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 430 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1564, - /* 440 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 450 */ 1254, 1437, 1254, 1257, 1555, 1254, 1254, 1254, 1254, 1254, - /* 460 */ 1254, 1254, 1254, 1414, 1415, 1378, 1254, 1254, 1254, 1254, - /* 470 */ 1254, 1254, 1254, 1429, 1254, 1254, 1254, 1424, 1254, 1254, - /* 480 */ 1254, 1254, 1254, 1254, 1254, 1254, 1651, 1254, 1254, 1254, - /* 490 */ 1254, 1254, 1254, 1524, 1523, 1254, 1254, 1375, 1254, 1254, - /* 500 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 510 */ 1254, 1302, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 520 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 530 */ 1254, 1254, 1254, 1254, 1254, 1402, 1254, 1254, 1254, 1254, - /* 540 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 550 */ 1593, 1392, 1254, 1254, 1254, 1254, 1642, 1254, 1254, 1254, - /* 560 */ 1254, 1352, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 570 */ 1254, 1254, 1254, 1634, 1346, 1438, 1254, 1441, 1276, 1254, - /* 580 */ 1266, 1254, 1254, + /* 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, }; /********** End of lemon-generated parsing tables *****************************/ @@ -173892,8 +166707,8 @@ static const YYCODETYPE yyFallback[] = { 0, /* TRUEFALSE => nothing */ 0, /* ISNOT => nothing */ 0, /* FUNCTION => nothing */ - 0, /* UPLUS => nothing */ 0, /* UMINUS => nothing */ + 0, /* UPLUS => nothing */ 0, /* TRUTH => nothing */ 0, /* REGISTER => nothing */ 0, /* VECTOR => nothing */ @@ -173902,7 +166717,6 @@ static const YYCODETYPE yyFallback[] = { 0, /* ASTERISK => nothing */ 0, /* SPAN => nothing */ 0, /* ERROR => nothing */ - 0, /* QNUMBER => nothing */ 0, /* SPACE => nothing */ 0, /* ILLEGAL => nothing */ }; @@ -173945,9 +166759,14 @@ struct yyParser { #endif sqlite3ParserARG_SDECL /* A place to hold %extra_argument */ sqlite3ParserCTX_SDECL /* A place to hold %extra_context */ - yyStackEntry *yystackEnd; /* Last entry in the stack */ - yyStackEntry *yystack; /* The parser stack */ - yyStackEntry yystk0[YYSTACKDEPTH]; /* Initial stack space */ +#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 }; typedef struct yyParser yyParser; @@ -174161,8 +166980,8 @@ static const char *const yyTokenName[] = { /* 170 */ "TRUEFALSE", /* 171 */ "ISNOT", /* 172 */ "FUNCTION", - /* 173 */ "UPLUS", - /* 174 */ "UMINUS", + /* 173 */ "UMINUS", + /* 174 */ "UPLUS", /* 175 */ "TRUTH", /* 176 */ "REGISTER", /* 177 */ "VECTOR", @@ -174171,145 +166990,142 @@ static const char *const yyTokenName[] = { /* 180 */ "ASTERISK", /* 181 */ "SPAN", /* 182 */ "ERROR", - /* 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", + /* 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", }; #endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */ @@ -174412,363 +167228,351 @@ 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 */ "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 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", + /* 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 ::=", }; #endif /* NDEBUG */ -#if YYGROWABLESTACK +#if YYSTACKDEPTH<=0 /* ** 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 = 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])); + 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; }else{ - pNew = YYREALLOC(p->yystack, newSize*sizeof(pNew[0])); - if( pNew==0 ) return 1; + pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); } - p->yystack = pNew; - p->yytos = &p->yystack[idx]; + if( pNew ){ + p->yystack = pNew; + p->yytos = &p->yystack[idx]; #ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", - yyTracePrompt, oldSize, newSize); - } + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", + yyTracePrompt, p->yystksz, newSize); + } #endif - p->yystackEnd = &p->yystack[newSize-1]; - return 0; + p->yystksz = newSize; + } + return pNew==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 @@ -174788,14 +167592,24 @@ SQLITE_PRIVATE void sqlite3ParserInit(void *yypRawParser sqlite3ParserCTX_PDECL) #ifdef YYTRACKMAXSTACKDEPTH yypParser->yyhwm = 0; #endif - yypParser->yystack = yypParser->yystk0; - yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1]; +#if YYSTACKDEPTH<=0 + yypParser->yytos = NULL; + yypParser->yystack = NULL; + yypParser->yystksz = 0; + if( yyGrowStack(yypParser) ){ + yypParser->yystack = &yypParser->yystk0; + yypParser->yystksz = 1; + } +#endif #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 sqlite3Parser_ENGINEALWAYSONSTACK @@ -174849,98 +167663,97 @@ static void yy_destructor( ** inside the C code. */ /********* Begin destructor definitions ***************************************/ - case 205: /* select */ - case 240: /* selectnowith */ - case 241: /* oneselect */ - case 253: /* values */ - case 255: /* mvalues */ + case 204: /* select */ + case 239: /* selectnowith */ + case 240: /* oneselect */ + case 252: /* values */ { -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 */ +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 */ { -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 */ +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 */ { -sqlite3ExprListDelete(pParse->db, (yypminor->yy14)); +sqlite3ExprListDelete(pParse->db, (yypminor->yy322)); } break; - case 239: /* fullname */ - case 246: /* from */ - case 258: /* seltablist */ - case 259: /* stl_prefix */ - case 264: /* xfullname */ + case 238: /* fullname */ + case 245: /* from */ + case 256: /* seltablist */ + case 257: /* stl_prefix */ + case 262: /* xfullname */ { -sqlite3SrcListDelete(pParse->db, (yypminor->yy203)); +sqlite3SrcListDelete(pParse->db, (yypminor->yy131)); } break; - case 242: /* wqlist */ + case 241: /* wqlist */ { -sqlite3WithDelete(pParse->db, (yypminor->yy59)); +sqlite3WithDelete(pParse->db, (yypminor->yy521)); } break; - case 252: /* window_clause */ - case 309: /* windowdefn_list */ + case 251: /* window_clause */ + case 306: /* windowdefn_list */ { -sqlite3WindowListDelete(pParse->db, (yypminor->yy211)); +sqlite3WindowListDelete(pParse->db, (yypminor->yy41)); } break; - case 265: /* idlist */ - case 272: /* idlist_opt */ + case 263: /* idlist */ + case 270: /* idlist_opt */ { -sqlite3IdListDelete(pParse->db, (yypminor->yy132)); +sqlite3IdListDelete(pParse->db, (yypminor->yy254)); } break; - case 275: /* filter_over */ - case 310: /* windowdefn */ - case 311: /* window */ - case 312: /* frame_opt */ - case 315: /* over_clause */ + case 273: /* filter_over */ + case 307: /* windowdefn */ + case 308: /* window */ + case 309: /* frame_opt */ + case 312: /* over_clause */ { -sqlite3WindowDelete(pParse->db, (yypminor->yy211)); +sqlite3WindowDelete(pParse->db, (yypminor->yy41)); } break; - case 288: /* trigger_cmd_list */ - case 293: /* trigger_cmd */ + case 286: /* trigger_cmd_list */ + case 291: /* trigger_cmd */ { -sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy427)); +sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy33)); } break; - case 290: /* trigger_event */ + case 288: /* trigger_event */ { -sqlite3IdListDelete(pParse->db, (yypminor->yy286).b); +sqlite3IdListDelete(pParse->db, (yypminor->yy180).b); } break; - case 317: /* frame_bound */ - case 318: /* frame_bound_s */ - case 319: /* frame_bound_e */ + case 314: /* frame_bound */ + case 315: /* frame_bound_s */ + case 316: /* frame_bound_e */ { -sqlite3ExprDelete(pParse->db, (yypminor->yy509).pExpr); +sqlite3ExprDelete(pParse->db, (yypminor->yy595).pExpr); } break; /********* End destructor definitions *****************************************/ @@ -174974,26 +167787,9 @@ static void yy_pop_parser_stack(yyParser *pParser){ */ SQLITE_PRIVATE void sqlite3ParserFinalize(void *p){ yyParser *pParser = (yyParser*)p; - - /* 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); + while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser); +#if YYSTACKDEPTH<=0 + if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack); #endif } @@ -175176,7 +167972,7 @@ static void yyStackOverflow(yyParser *yypParser){ ** stack every overflows */ /******** Begin %stack_overflow code ******************************************/ - sqlite3OomFault(pParse->db); + sqlite3ErrorMsg(pParse, "parser stack overflow"); /******** End %stack_overflow code ********************************************/ sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument var */ sqlite3ParserCTX_STORE @@ -175220,19 +168016,25 @@ static void yy_shift( assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) ); } #endif - yytos = yypParser->yytos; - if( yytos>yypParser->yystackEnd ){ +#if YYSTACKDEPTH>0 + if( yypParser->yytos>yypParser->yystackEnd ){ + yypParser->yytos--; + yyStackOverflow(yypParser); + return; + } +#else + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){ 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; @@ -175242,415 +168044,411 @@ static void yy_shift( /* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side ** of that rule */ static const YYCODETYPE yyRuleInfoLhs[] = { - 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 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 */ + 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 ::= */ }; /* For rule J, yyRuleInfoNRhs[J] contains the negative of the number @@ -175751,320 +168549,316 @@ 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 */ - -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 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 */ + -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 ::= */ }; static void yy_accept(yyParser*); /* Forward Declaration */ @@ -176107,25 +168901,25 @@ static YYACTIONTYPE yy_reduce( /********** Begin reduce actions **********************************************/ YYMINORTYPE yylhsminor; case 0: /* explain ::= EXPLAIN */ -{ if( pParse->pReprepare==0 ) pParse->explain = 1; } +{ pParse->explain = 1; } break; case 1: /* explain ::= EXPLAIN QUERY PLAN */ -{ if( pParse->pReprepare==0 ) pParse->explain = 2; } +{ pParse->explain = 2; } break; case 2: /* cmdx ::= cmd */ { sqlite3FinishCoding(pParse); } break; case 3: /* cmd ::= BEGIN transtype trans_opt */ -{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy144);} +{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy394);} break; case 4: /* transtype ::= */ -{yymsp[1].minor.yy144 = TK_DEFERRED;} +{yymsp[1].minor.yy394 = TK_DEFERRED;} break; case 5: /* transtype ::= DEFERRED */ case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6); case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7); - case 324: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==324); -{yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-X*/} + case 323: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==323); +{yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/} break; case 8: /* cmd ::= COMMIT|END trans_opt */ case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9); @@ -176148,7 +168942,7 @@ static YYACTIONTYPE yy_reduce( break; case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ { - sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy144,0,0,yymsp[-2].minor.yy144); + sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy394,0,0,yymsp[-2].minor.yy394); } break; case 14: /* createkw ::= CREATE */ @@ -176160,40 +168954,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 100: /* distinct ::= */ yytestcase(yyruleno==100); - case 246: /* collate ::= */ yytestcase(yyruleno==246); -{yymsp[1].minor.yy144 = 0;} + case 98: /* distinct ::= */ yytestcase(yyruleno==98); + case 244: /* collate ::= */ yytestcase(yyruleno==244); +{yymsp[1].minor.yy394 = 0;} break; case 16: /* ifnotexists ::= IF NOT EXISTS */ -{yymsp[-2].minor.yy144 = 1;} +{yymsp[-2].minor.yy394 = 1;} break; case 17: /* temp ::= TEMP */ -{yymsp[0].minor.yy144 = pParse->db->init.busy==0;} +{yymsp[0].minor.yy394 = pParse->db->init.busy==0;} break; case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_option_set */ { - sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy391,0); + sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy285,0); } break; case 20: /* create_table_args ::= AS select */ { - sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy555); - sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy555); + sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy47); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy47); } break; case 21: /* table_option_set ::= */ -{yymsp[1].minor.yy391 = 0;} +{yymsp[1].minor.yy285 = 0;} break; case 22: /* table_option_set ::= table_option_set COMMA table_option */ -{yylhsminor.yy391 = yymsp[-2].minor.yy391|yymsp[0].minor.yy391;} - yymsp[-2].minor.yy391 = yylhsminor.yy391; +{yylhsminor.yy285 = yymsp[-2].minor.yy285|yymsp[0].minor.yy285;} + yymsp[-2].minor.yy285 = yylhsminor.yy285; break; case 23: /* table_option ::= WITHOUT nm */ { if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){ - yymsp[-1].minor.yy391 = TF_WithoutRowid | TF_NoVisibleRowid; + yymsp[-1].minor.yy285 = TF_WithoutRowid | TF_NoVisibleRowid; }else{ - yymsp[-1].minor.yy391 = 0; + yymsp[-1].minor.yy285 = 0; sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z); } } @@ -176201,20 +168995,20 @@ static YYACTIONTYPE yy_reduce( case 24: /* table_option ::= nm */ { if( yymsp[0].minor.yy0.n==6 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"strict",6)==0 ){ - yylhsminor.yy391 = TF_Strict; + yylhsminor.yy285 = TF_Strict; }else{ - yylhsminor.yy391 = 0; + yylhsminor.yy285 = 0; sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z); } } - yymsp[0].minor.yy391 = yylhsminor.yy391; + yymsp[0].minor.yy285 = yylhsminor.yy285; break; case 25: /* columnname ::= nm typetoken */ {sqlite3AddColumn(pParse,yymsp[-1].minor.yy0,yymsp[0].minor.yy0);} break; case 26: /* typetoken ::= */ case 65: /* conslist_opt ::= */ yytestcase(yyruleno==65); - case 106: /* as ::= */ yytestcase(yyruleno==106); + case 104: /* as ::= */ yytestcase(yyruleno==104); {yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;} break; case 27: /* typetoken ::= typename LP signed RP */ @@ -176233,7 +169027,7 @@ static YYACTIONTYPE yy_reduce( case 30: /* scanpt ::= */ { assert( yyLookahead!=YYNOCODE ); - yymsp[1].minor.yy168 = yyLookaheadToken.z; + yymsp[1].minor.yy522 = yyLookaheadToken.z; } break; case 31: /* scantok ::= */ @@ -176247,17 +169041,17 @@ static YYACTIONTYPE yy_reduce( {pParse->constraintName = yymsp[0].minor.yy0;} break; case 33: /* ccons ::= DEFAULT scantok term */ -{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy454,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} +{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy528,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} break; case 34: /* ccons ::= DEFAULT LP expr RP */ -{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy454,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);} +{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy528,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);} break; case 35: /* ccons ::= DEFAULT PLUS scantok term */ -{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy454,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} +{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy528,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 = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy454, 0); + Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy528, 0); sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]); } break; @@ -176272,160 +169066,161 @@ static YYACTIONTYPE yy_reduce( } break; case 38: /* ccons ::= NOT NULL onconf */ -{sqlite3AddNotNull(pParse, yymsp[0].minor.yy144);} +{sqlite3AddNotNull(pParse, yymsp[0].minor.yy394);} break; case 39: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ -{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy144,yymsp[0].minor.yy144,yymsp[-2].minor.yy144);} +{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy394,yymsp[0].minor.yy394,yymsp[-2].minor.yy394);} break; case 40: /* ccons ::= UNIQUE onconf */ -{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy144,0,0,0,0, +{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy394,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; case 41: /* ccons ::= CHECK LP expr RP */ -{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy454,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);} +{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy528,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);} break; case 42: /* ccons ::= REFERENCES nm eidlist_opt refargs */ -{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy14,yymsp[0].minor.yy144);} +{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy322,yymsp[0].minor.yy394);} break; case 43: /* ccons ::= defer_subclause */ -{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy144);} +{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy394);} break; case 44: /* ccons ::= COLLATE ID|STRING */ {sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);} break; case 45: /* generated ::= LP expr RP */ -{sqlite3AddGenerated(pParse,yymsp[-1].minor.yy454,0);} +{sqlite3AddGenerated(pParse,yymsp[-1].minor.yy528,0);} break; case 46: /* generated ::= LP expr RP ID */ -{sqlite3AddGenerated(pParse,yymsp[-2].minor.yy454,&yymsp[0].minor.yy0);} +{sqlite3AddGenerated(pParse,yymsp[-2].minor.yy528,&yymsp[0].minor.yy0);} break; case 48: /* autoinc ::= AUTOINCR */ -{yymsp[0].minor.yy144 = 1;} +{yymsp[0].minor.yy394 = 1;} break; case 49: /* refargs ::= */ -{ yymsp[1].minor.yy144 = OE_None*0x0101; /* EV: R-19803-45884 */} +{ yymsp[1].minor.yy394 = OE_None*0x0101; /* EV: R-19803-45884 */} break; case 50: /* refargs ::= refargs refarg */ -{ yymsp[-1].minor.yy144 = (yymsp[-1].minor.yy144 & ~yymsp[0].minor.yy383.mask) | yymsp[0].minor.yy383.value; } +{ yymsp[-1].minor.yy394 = (yymsp[-1].minor.yy394 & ~yymsp[0].minor.yy231.mask) | yymsp[0].minor.yy231.value; } break; case 51: /* refarg ::= MATCH nm */ -{ yymsp[-1].minor.yy383.value = 0; yymsp[-1].minor.yy383.mask = 0x000000; } +{ yymsp[-1].minor.yy231.value = 0; yymsp[-1].minor.yy231.mask = 0x000000; } break; case 52: /* refarg ::= ON INSERT refact */ -{ yymsp[-2].minor.yy383.value = 0; yymsp[-2].minor.yy383.mask = 0x000000; } +{ yymsp[-2].minor.yy231.value = 0; yymsp[-2].minor.yy231.mask = 0x000000; } break; case 53: /* refarg ::= ON DELETE refact */ -{ yymsp[-2].minor.yy383.value = yymsp[0].minor.yy144; yymsp[-2].minor.yy383.mask = 0x0000ff; } +{ yymsp[-2].minor.yy231.value = yymsp[0].minor.yy394; yymsp[-2].minor.yy231.mask = 0x0000ff; } break; case 54: /* refarg ::= ON UPDATE refact */ -{ yymsp[-2].minor.yy383.value = yymsp[0].minor.yy144<<8; yymsp[-2].minor.yy383.mask = 0x00ff00; } +{ yymsp[-2].minor.yy231.value = yymsp[0].minor.yy394<<8; yymsp[-2].minor.yy231.mask = 0x00ff00; } break; case 55: /* refact ::= SET NULL */ -{ yymsp[-1].minor.yy144 = OE_SetNull; /* EV: R-33326-45252 */} +{ yymsp[-1].minor.yy394 = OE_SetNull; /* EV: R-33326-45252 */} break; case 56: /* refact ::= SET DEFAULT */ -{ yymsp[-1].minor.yy144 = OE_SetDflt; /* EV: R-33326-45252 */} +{ yymsp[-1].minor.yy394 = OE_SetDflt; /* EV: R-33326-45252 */} break; case 57: /* refact ::= CASCADE */ -{ yymsp[0].minor.yy144 = OE_Cascade; /* EV: R-33326-45252 */} +{ yymsp[0].minor.yy394 = OE_Cascade; /* EV: R-33326-45252 */} break; case 58: /* refact ::= RESTRICT */ -{ yymsp[0].minor.yy144 = OE_Restrict; /* EV: R-33326-45252 */} +{ yymsp[0].minor.yy394 = OE_Restrict; /* EV: R-33326-45252 */} break; case 59: /* refact ::= NO ACTION */ -{ yymsp[-1].minor.yy144 = OE_None; /* EV: R-33326-45252 */} +{ yymsp[-1].minor.yy394 = OE_None; /* EV: R-33326-45252 */} break; case 60: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ -{yymsp[-2].minor.yy144 = 0;} +{yymsp[-2].minor.yy394 = 0;} break; case 61: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ case 76: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==76); - case 173: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==173); -{yymsp[-1].minor.yy144 = yymsp[0].minor.yy144;} + case 171: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==171); +{yymsp[-1].minor.yy394 = yymsp[0].minor.yy394;} break; case 63: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ case 80: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==80); - 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;} + 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;} break; case 64: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ -{yymsp[-1].minor.yy144 = 0;} +{yymsp[-1].minor.yy394 = 0;} break; case 66: /* tconscomma ::= COMMA */ {pParse->constraintName.n = 0;} break; case 68: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ -{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy14,yymsp[0].minor.yy144,yymsp[-2].minor.yy144,0);} +{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy322,yymsp[0].minor.yy394,yymsp[-2].minor.yy394,0);} break; case 69: /* tcons ::= UNIQUE LP sortlist RP onconf */ -{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy14,yymsp[0].minor.yy144,0,0,0,0, +{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy322,yymsp[0].minor.yy394,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; case 70: /* tcons ::= CHECK LP expr RP onconf */ -{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy454,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);} +{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy528,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 */ { - sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy14, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[-1].minor.yy144); - sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy144); + sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy322, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[-1].minor.yy394); + sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy394); } break; case 73: /* onconf ::= */ case 75: /* orconf ::= */ yytestcase(yyruleno==75); -{yymsp[1].minor.yy144 = OE_Default;} +{yymsp[1].minor.yy394 = OE_Default;} break; case 74: /* onconf ::= ON CONFLICT resolvetype */ -{yymsp[-2].minor.yy144 = yymsp[0].minor.yy144;} +{yymsp[-2].minor.yy394 = yymsp[0].minor.yy394;} break; case 77: /* resolvetype ::= IGNORE */ -{yymsp[0].minor.yy144 = OE_Ignore;} +{yymsp[0].minor.yy394 = OE_Ignore;} break; case 78: /* resolvetype ::= REPLACE */ - case 174: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==174); -{yymsp[0].minor.yy144 = OE_Replace;} + case 172: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==172); +{yymsp[0].minor.yy394 = OE_Replace;} break; case 79: /* cmd ::= DROP TABLE ifexists fullname */ { - sqlite3DropTable(pParse, yymsp[0].minor.yy203, 0, yymsp[-1].minor.yy144); + sqlite3DropTable(pParse, yymsp[0].minor.yy131, 0, yymsp[-1].minor.yy394); } break; case 82: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ { - 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); + 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); } break; case 83: /* cmd ::= DROP VIEW ifexists fullname */ { - sqlite3DropTable(pParse, yymsp[0].minor.yy203, 1, yymsp[-1].minor.yy144); + sqlite3DropTable(pParse, yymsp[0].minor.yy131, 1, yymsp[-1].minor.yy394); } break; case 84: /* cmd ::= select */ { SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0}; - sqlite3Select(pParse, yymsp[0].minor.yy555, &dest); - sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy555); + sqlite3Select(pParse, yymsp[0].minor.yy47, &dest); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy47); } break; case 85: /* select ::= WITH wqlist selectnowith */ -{yymsp[-2].minor.yy555 = attachWithToSelect(pParse,yymsp[0].minor.yy555,yymsp[-1].minor.yy59);} +{yymsp[-2].minor.yy47 = attachWithToSelect(pParse,yymsp[0].minor.yy47,yymsp[-1].minor.yy521);} break; case 86: /* select ::= WITH RECURSIVE wqlist selectnowith */ -{yymsp[-3].minor.yy555 = attachWithToSelect(pParse,yymsp[0].minor.yy555,yymsp[-1].minor.yy59);} +{yymsp[-3].minor.yy47 = attachWithToSelect(pParse,yymsp[0].minor.yy47,yymsp[-1].minor.yy521);} break; case 87: /* select ::= selectnowith */ { - Select *p = yymsp[0].minor.yy555; + Select *p = yymsp[0].minor.yy47; 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.yy555; - Select *pLhs = yymsp[-2].minor.yy555; + Select *pRhs = yymsp[0].minor.yy47; + Select *pLhs = yymsp[-2].minor.yy47; if( pRhs && pRhs->pPrior ){ SrcList *pFrom; Token x; @@ -176435,145 +169230,145 @@ static YYACTIONTYPE yy_reduce( pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0); } if( pRhs ){ - pRhs->op = (u8)yymsp[-1].minor.yy144; + pRhs->op = (u8)yymsp[-1].minor.yy394; pRhs->pPrior = pLhs; if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue; pRhs->selFlags &= ~SF_MultiValue; - if( yymsp[-1].minor.yy144!=TK_ALL ) pParse->hasCompound = 1; + if( yymsp[-1].minor.yy394!=TK_ALL ) pParse->hasCompound = 1; }else{ sqlite3SelectDelete(pParse->db, pLhs); } - yymsp[-2].minor.yy555 = pRhs; + yymsp[-2].minor.yy47 = pRhs; } break; case 89: /* multiselect_op ::= UNION */ case 91: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==91); -{yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-OP*/} +{yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-OP*/} break; case 90: /* multiselect_op ::= UNION ALL */ -{yymsp[-1].minor.yy144 = TK_ALL;} +{yymsp[-1].minor.yy394 = TK_ALL;} break; case 92: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ { - yymsp[-8].minor.yy555 = 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); + yymsp[-8].minor.yy47 = 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); } break; case 93: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ { - yymsp[-9].minor.yy555 = 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; + yymsp[-9].minor.yy47 = 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; }else{ - sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy211); + sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy41); } } break; case 94: /* values ::= VALUES LP nexprlist RP */ { - yymsp[-3].minor.yy555 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy14,0,0,0,0,0,SF_Values,0); + yymsp[-3].minor.yy47 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values,0); } break; - case 95: /* oneselect ::= mvalues */ + case 95: /* values ::= values COMMA LP nexprlist RP */ { - 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 = sqlite3MultiValues(pParse, yymsp[-4].minor.yy555, yymsp[-1].minor.yy14); + Select *pRight, *pLeft = yymsp[-4].minor.yy47; + pRight = 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; + } } break; - case 98: /* distinct ::= DISTINCT */ -{yymsp[0].minor.yy144 = SF_Distinct;} + case 96: /* distinct ::= DISTINCT */ +{yymsp[0].minor.yy394 = SF_Distinct;} break; - case 99: /* distinct ::= ALL */ -{yymsp[0].minor.yy144 = SF_All;} + case 97: /* distinct ::= ALL */ +{yymsp[0].minor.yy394 = SF_All;} break; - 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;} + 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;} break; - case 102: /* selcollist ::= sclp scanpt expr scanpt as */ + case 100: /* selcollist ::= sclp scanpt expr scanpt as */ { - yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy14, yymsp[-2].minor.yy454); - if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy14, &yymsp[0].minor.yy0, 1); - sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy14,yymsp[-3].minor.yy168,yymsp[-1].minor.yy168); + yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[-2].minor.yy528); + if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[0].minor.yy0, 1); + sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy322,yymsp[-3].minor.yy522,yymsp[-1].minor.yy522); } break; - case 103: /* selcollist ::= sclp scanpt STAR */ + case 101: /* selcollist ::= sclp scanpt STAR */ { Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); - sqlite3ExprSetErrorOffset(p, (int)(yymsp[0].minor.yy0.z - pParse->zTail)); - yymsp[-2].minor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy14, p); + yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy322, p); } break; - case 104: /* selcollist ::= sclp scanpt nm DOT STAR */ + case 102: /* selcollist ::= sclp scanpt nm DOT STAR */ { - Expr *pRight, *pLeft, *pDot; - pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0); - sqlite3ExprSetErrorOffset(pRight, (int)(yymsp[0].minor.yy0.z - pParse->zTail)); - pLeft = tokenExpr(pParse, TK_ID, yymsp[-2].minor.yy0); - pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight); - yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, pDot); -} - break; - 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); + Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0); + Expr *pLeft = tokenExpr(pParse, TK_ID, yymsp[-2].minor.yy0); + Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight); + yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, 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); {yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;} break; - case 107: /* from ::= */ - case 110: /* stl_prefix ::= */ yytestcase(yyruleno==110); -{yymsp[1].minor.yy203 = 0;} + case 105: /* from ::= */ + case 108: /* stl_prefix ::= */ yytestcase(yyruleno==108); +{yymsp[1].minor.yy131 = 0;} break; - case 108: /* from ::= FROM seltablist */ + case 106: /* from ::= FROM seltablist */ { - yymsp[-1].minor.yy203 = yymsp[0].minor.yy203; - sqlite3SrcListShiftJoinType(pParse,yymsp[-1].minor.yy203); + yymsp[-1].minor.yy131 = yymsp[0].minor.yy131; + sqlite3SrcListShiftJoinType(pParse,yymsp[-1].minor.yy131); } break; - case 109: /* stl_prefix ::= seltablist joinop */ + case 107: /* stl_prefix ::= seltablist joinop */ { - 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; + 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; } break; - case 111: /* seltablist ::= stl_prefix nm dbnm as on_using */ + case 109: /* seltablist ::= stl_prefix nm dbnm as on_using */ { - yymsp[-4].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-4].minor.yy203,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269); + yymsp[-4].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-4].minor.yy131,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561); } break; - case 112: /* seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ + case 110: /* seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ { - yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy269); - sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy203, &yymsp[-1].minor.yy0); + yymsp[-5].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy561); + sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy131, &yymsp[-1].minor.yy0); } break; - case 113: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ + case 111: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ { - yymsp[-7].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy203,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269); - sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy203, yymsp[-3].minor.yy14); + yymsp[-7].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy131,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561); + sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy131, yymsp[-3].minor.yy322); } break; - case 114: /* seltablist ::= stl_prefix LP select RP as on_using */ + case 112: /* seltablist ::= stl_prefix LP select RP as on_using */ { - yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,yymsp[-3].minor.yy555,&yymsp[0].minor.yy269); + yymsp[-5].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,yymsp[-3].minor.yy47,&yymsp[0].minor.yy561); } break; - case 115: /* seltablist ::= stl_prefix LP seltablist RP as on_using */ + case 113: /* seltablist ::= stl_prefix LP seltablist RP as on_using */ { - 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 = 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; + 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 = 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; pNew->zName = pOld->zName; pNew->zDatabase = pOld->zDatabase; pNew->pSelect = pOld->pSelect; @@ -176589,153 +169384,153 @@ static YYACTIONTYPE yy_reduce( pOld->zName = pOld->zDatabase = 0; pOld->pSelect = 0; } - sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy203); + sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy131); }else{ Select *pSubquery; - sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy203); - pSubquery = sqlite3SelectNew(pParse,0,yymsp[-3].minor.yy203,0,0,0,0,SF_NestedFrom,0); - yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,pSubquery,&yymsp[0].minor.yy269); + sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy131); + pSubquery = sqlite3SelectNew(pParse,0,yymsp[-3].minor.yy131,0,0,0,0,SF_NestedFrom,0); + yymsp[-5].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,pSubquery,&yymsp[0].minor.yy561); } } break; - case 116: /* dbnm ::= */ - case 131: /* indexed_opt ::= */ yytestcase(yyruleno==131); + case 114: /* dbnm ::= */ + case 129: /* indexed_opt ::= */ yytestcase(yyruleno==129); {yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;} break; - case 118: /* fullname ::= nm */ + case 116: /* fullname ::= nm */ { - yylhsminor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); - if( IN_RENAME_OBJECT && yylhsminor.yy203 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[0].minor.yy0); + yylhsminor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); + if( IN_RENAME_OBJECT && yylhsminor.yy131 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy131->a[0].zName, &yymsp[0].minor.yy0); } - yymsp[0].minor.yy203 = yylhsminor.yy203; + yymsp[0].minor.yy131 = yylhsminor.yy131; break; - case 119: /* fullname ::= nm DOT nm */ + case 117: /* fullname ::= nm DOT nm */ { - yylhsminor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); - if( IN_RENAME_OBJECT && yylhsminor.yy203 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[0].minor.yy0); + yylhsminor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); + if( IN_RENAME_OBJECT && yylhsminor.yy131 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy131->a[0].zName, &yymsp[0].minor.yy0); } - yymsp[-2].minor.yy203 = yylhsminor.yy203; + yymsp[-2].minor.yy131 = yylhsminor.yy131; break; - case 120: /* xfullname ::= nm */ -{yymsp[0].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/} + case 118: /* xfullname ::= nm */ +{yymsp[0].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/} break; - case 121: /* xfullname ::= nm DOT nm */ -{yymsp[-2].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} + case 119: /* xfullname ::= nm DOT nm */ +{yymsp[-2].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} break; - case 122: /* xfullname ::= nm DOT nm AS nm */ + case 120: /* xfullname ::= nm DOT nm AS nm */ { - yymsp[-4].minor.yy203 = 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 = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); + yymsp[-4].minor.yy131 = 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 = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); } break; - case 123: /* xfullname ::= nm AS nm */ + case 121: /* xfullname ::= nm AS nm */ { - yymsp[-2].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/ - if( yymsp[-2].minor.yy203 ) yymsp[-2].minor.yy203->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); + yymsp[-2].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/ + if( yymsp[-2].minor.yy131 ) yymsp[-2].minor.yy131->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); } break; - case 124: /* joinop ::= COMMA|JOIN */ -{ yymsp[0].minor.yy144 = JT_INNER; } + case 122: /* joinop ::= COMMA|JOIN */ +{ yymsp[0].minor.yy394 = JT_INNER; } break; - case 125: /* joinop ::= JOIN_KW JOIN */ -{yymsp[-1].minor.yy144 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} + case 123: /* joinop ::= JOIN_KW JOIN */ +{yymsp[-1].minor.yy394 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} break; - case 126: /* joinop ::= JOIN_KW nm JOIN */ -{yymsp[-2].minor.yy144 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} + case 124: /* joinop ::= JOIN_KW nm JOIN */ +{yymsp[-2].minor.yy394 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} break; - case 127: /* joinop ::= JOIN_KW nm nm JOIN */ -{yymsp[-3].minor.yy144 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} + case 125: /* joinop ::= JOIN_KW nm nm JOIN */ +{yymsp[-3].minor.yy394 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} break; - case 128: /* on_using ::= ON expr */ -{yymsp[-1].minor.yy269.pOn = yymsp[0].minor.yy454; yymsp[-1].minor.yy269.pUsing = 0;} + case 126: /* on_using ::= ON expr */ +{yymsp[-1].minor.yy561.pOn = yymsp[0].minor.yy528; yymsp[-1].minor.yy561.pUsing = 0;} break; - case 129: /* on_using ::= USING LP idlist RP */ -{yymsp[-3].minor.yy269.pOn = 0; yymsp[-3].minor.yy269.pUsing = yymsp[-1].minor.yy132;} + case 127: /* on_using ::= USING LP idlist RP */ +{yymsp[-3].minor.yy561.pOn = 0; yymsp[-3].minor.yy561.pUsing = yymsp[-1].minor.yy254;} break; - case 130: /* on_using ::= */ -{yymsp[1].minor.yy269.pOn = 0; yymsp[1].minor.yy269.pUsing = 0;} + case 128: /* on_using ::= */ +{yymsp[1].minor.yy561.pOn = 0; yymsp[1].minor.yy561.pUsing = 0;} break; - case 132: /* indexed_by ::= INDEXED BY nm */ + case 130: /* indexed_by ::= INDEXED BY nm */ {yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;} break; - case 133: /* indexed_by ::= NOT INDEXED */ + case 131: /* indexed_by ::= NOT INDEXED */ {yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;} break; - 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;} + 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;} break; - case 136: /* sortlist ::= sortlist COMMA expr sortorder nulls */ + case 134: /* sortlist ::= sortlist COMMA expr sortorder nulls */ { - yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14,yymsp[-2].minor.yy454); - sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy14,yymsp[-1].minor.yy144,yymsp[0].minor.yy144); + yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322,yymsp[-2].minor.yy528); + sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy322,yymsp[-1].minor.yy394,yymsp[0].minor.yy394); } break; - case 137: /* sortlist ::= expr sortorder nulls */ + case 135: /* sortlist ::= expr sortorder nulls */ { - yymsp[-2].minor.yy14 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy454); /*A-overwrites-Y*/ - sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy14,yymsp[-1].minor.yy144,yymsp[0].minor.yy144); + yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy528); /*A-overwrites-Y*/ + sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy322,yymsp[-1].minor.yy394,yymsp[0].minor.yy394); } break; - case 138: /* sortorder ::= ASC */ -{yymsp[0].minor.yy144 = SQLITE_SO_ASC;} + case 136: /* sortorder ::= ASC */ +{yymsp[0].minor.yy394 = SQLITE_SO_ASC;} break; - case 139: /* sortorder ::= DESC */ -{yymsp[0].minor.yy144 = SQLITE_SO_DESC;} + case 137: /* sortorder ::= DESC */ +{yymsp[0].minor.yy394 = SQLITE_SO_DESC;} break; - case 140: /* sortorder ::= */ - case 143: /* nulls ::= */ yytestcase(yyruleno==143); -{yymsp[1].minor.yy144 = SQLITE_SO_UNDEFINED;} + case 138: /* sortorder ::= */ + case 141: /* nulls ::= */ yytestcase(yyruleno==141); +{yymsp[1].minor.yy394 = SQLITE_SO_UNDEFINED;} break; - case 141: /* nulls ::= NULLS FIRST */ -{yymsp[-1].minor.yy144 = SQLITE_SO_ASC;} + case 139: /* nulls ::= NULLS FIRST */ +{yymsp[-1].minor.yy394 = SQLITE_SO_ASC;} break; - case 142: /* nulls ::= NULLS LAST */ -{yymsp[-1].minor.yy144 = SQLITE_SO_DESC;} + case 140: /* nulls ::= NULLS LAST */ +{yymsp[-1].minor.yy394 = SQLITE_SO_DESC;} break; - 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;} + 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;} break; - 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;} + 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;} break; - case 149: /* limit_opt ::= LIMIT expr */ -{yymsp[-1].minor.yy454 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy454,0);} + case 147: /* limit_opt ::= LIMIT expr */ +{yymsp[-1].minor.yy528 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy528,0);} break; - case 150: /* limit_opt ::= LIMIT expr OFFSET expr */ -{yymsp[-3].minor.yy454 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);} + case 148: /* limit_opt ::= LIMIT expr OFFSET expr */ +{yymsp[-3].minor.yy528 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);} break; - case 151: /* limit_opt ::= LIMIT expr COMMA expr */ -{yymsp[-3].minor.yy454 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy454,yymsp[-2].minor.yy454);} + case 149: /* limit_opt ::= LIMIT expr COMMA expr */ +{yymsp[-3].minor.yy528 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy528,yymsp[-2].minor.yy528);} break; - case 152: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */ + case 150: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */ { - sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy203, &yymsp[-1].minor.yy0); - sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy203,yymsp[0].minor.yy454,0,0); + sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy131, &yymsp[-1].minor.yy0); + sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy131,yymsp[0].minor.yy528,0,0); } break; - case 157: /* where_opt_ret ::= RETURNING selcollist */ -{sqlite3AddReturning(pParse,yymsp[0].minor.yy14); yymsp[-1].minor.yy454 = 0;} + case 155: /* where_opt_ret ::= RETURNING selcollist */ +{sqlite3AddReturning(pParse,yymsp[0].minor.yy322); yymsp[-1].minor.yy528 = 0;} break; - case 158: /* where_opt_ret ::= WHERE expr RETURNING selcollist */ -{sqlite3AddReturning(pParse,yymsp[0].minor.yy14); yymsp[-3].minor.yy454 = yymsp[-2].minor.yy454;} + case 156: /* where_opt_ret ::= WHERE expr RETURNING selcollist */ +{sqlite3AddReturning(pParse,yymsp[0].minor.yy322); yymsp[-3].minor.yy528 = yymsp[-2].minor.yy528;} break; - case 159: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */ + case 157: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */ { - sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy203, &yymsp[-4].minor.yy0); - sqlite3ExprListCheckLength(pParse,yymsp[-2].minor.yy14,"set list"); - if( yymsp[-1].minor.yy203 ){ - SrcList *pFromClause = yymsp[-1].minor.yy203; + sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy131, &yymsp[-4].minor.yy0); + sqlite3ExprListCheckLength(pParse,yymsp[-2].minor.yy322,"set list"); + if( yymsp[-1].minor.yy131 ){ + SrcList *pFromClause = yymsp[-1].minor.yy131; if( pFromClause->nSrc>1 ){ Select *pSubquery; Token as; @@ -176744,92 +169539,93 @@ static YYACTIONTYPE yy_reduce( as.z = 0; pFromClause = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0); } - yymsp[-5].minor.yy203 = sqlite3SrcListAppendList(pParse, yymsp[-5].minor.yy203, pFromClause); + yymsp[-5].minor.yy131 = sqlite3SrcListAppendList(pParse, yymsp[-5].minor.yy131, pFromClause); } - sqlite3Update(pParse,yymsp[-5].minor.yy203,yymsp[-2].minor.yy14,yymsp[0].minor.yy454,yymsp[-6].minor.yy144,0,0,0); + sqlite3Update(pParse,yymsp[-5].minor.yy131,yymsp[-2].minor.yy322,yymsp[0].minor.yy528,yymsp[-6].minor.yy394,0,0,0); } break; - case 160: /* setlist ::= setlist COMMA nm EQ expr */ + case 158: /* setlist ::= setlist COMMA nm EQ expr */ { - yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy14, yymsp[0].minor.yy454); - sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy14, &yymsp[-2].minor.yy0, 1); + yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[0].minor.yy528); + sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, 1); } break; - case 161: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ + case 159: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ { - yymsp[-6].minor.yy14 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy14, yymsp[-3].minor.yy132, yymsp[0].minor.yy454); + yymsp[-6].minor.yy322 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy322, yymsp[-3].minor.yy254, yymsp[0].minor.yy528); } break; - case 162: /* setlist ::= nm EQ expr */ + case 160: /* setlist ::= nm EQ expr */ { - yylhsminor.yy14 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy454); - sqlite3ExprListSetName(pParse, yylhsminor.yy14, &yymsp[-2].minor.yy0, 1); + yylhsminor.yy322 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy528); + sqlite3ExprListSetName(pParse, yylhsminor.yy322, &yymsp[-2].minor.yy0, 1); } - yymsp[-2].minor.yy14 = yylhsminor.yy14; + yymsp[-2].minor.yy322 = yylhsminor.yy322; break; - case 163: /* setlist ::= LP idlist RP EQ expr */ + case 161: /* setlist ::= LP idlist RP EQ expr */ { - yymsp[-4].minor.yy14 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy132, yymsp[0].minor.yy454); + yymsp[-4].minor.yy322 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy254, yymsp[0].minor.yy528); } break; - case 164: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + case 162: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ { - sqlite3Insert(pParse, yymsp[-3].minor.yy203, yymsp[-1].minor.yy555, yymsp[-2].minor.yy132, yymsp[-5].minor.yy144, yymsp[0].minor.yy122); + sqlite3Insert(pParse, yymsp[-3].minor.yy131, yymsp[-1].minor.yy47, yymsp[-2].minor.yy254, yymsp[-5].minor.yy394, yymsp[0].minor.yy444); } break; - case 165: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ + case 163: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ { - sqlite3Insert(pParse, yymsp[-4].minor.yy203, 0, yymsp[-3].minor.yy132, yymsp[-6].minor.yy144, 0); + sqlite3Insert(pParse, yymsp[-4].minor.yy131, 0, yymsp[-3].minor.yy254, yymsp[-6].minor.yy394, 0); } break; - case 166: /* upsert ::= */ -{ yymsp[1].minor.yy122 = 0; } + case 164: /* upsert ::= */ +{ yymsp[1].minor.yy444 = 0; } break; - case 167: /* upsert ::= RETURNING selcollist */ -{ yymsp[-1].minor.yy122 = 0; sqlite3AddReturning(pParse,yymsp[0].minor.yy14); } + case 165: /* upsert ::= RETURNING selcollist */ +{ yymsp[-1].minor.yy444 = 0; sqlite3AddReturning(pParse,yymsp[0].minor.yy322); } break; - case 168: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ -{ yymsp[-11].minor.yy122 = sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy14,yymsp[-6].minor.yy454,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454,yymsp[0].minor.yy122);} + case 166: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ +{ yymsp[-11].minor.yy444 = sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy322,yymsp[-6].minor.yy528,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528,yymsp[0].minor.yy444);} break; - case 169: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ -{ yymsp[-8].minor.yy122 = sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy14,yymsp[-3].minor.yy454,0,0,yymsp[0].minor.yy122); } + case 167: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ +{ yymsp[-8].minor.yy444 = sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy322,yymsp[-3].minor.yy528,0,0,yymsp[0].minor.yy444); } break; - case 170: /* upsert ::= ON CONFLICT DO NOTHING returning */ -{ yymsp[-4].minor.yy122 = sqlite3UpsertNew(pParse->db,0,0,0,0,0); } + case 168: /* upsert ::= ON CONFLICT DO NOTHING returning */ +{ yymsp[-4].minor.yy444 = sqlite3UpsertNew(pParse->db,0,0,0,0,0); } break; - case 171: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ -{ yymsp[-7].minor.yy122 = sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454,0);} + case 169: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ +{ yymsp[-7].minor.yy444 = sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528,0);} break; - case 172: /* returning ::= RETURNING selcollist */ -{sqlite3AddReturning(pParse,yymsp[0].minor.yy14);} + case 170: /* returning ::= RETURNING selcollist */ +{sqlite3AddReturning(pParse,yymsp[0].minor.yy322);} break; - case 175: /* idlist_opt ::= */ -{yymsp[1].minor.yy132 = 0;} + case 173: /* idlist_opt ::= */ +{yymsp[1].minor.yy254 = 0;} break; - case 176: /* idlist_opt ::= LP idlist RP */ -{yymsp[-2].minor.yy132 = yymsp[-1].minor.yy132;} + case 174: /* idlist_opt ::= LP idlist RP */ +{yymsp[-2].minor.yy254 = yymsp[-1].minor.yy254;} break; - case 177: /* idlist ::= idlist COMMA nm */ -{yymsp[-2].minor.yy132 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy132,&yymsp[0].minor.yy0);} + case 175: /* idlist ::= idlist COMMA nm */ +{yymsp[-2].minor.yy254 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy254,&yymsp[0].minor.yy0);} break; - case 178: /* idlist ::= nm */ -{yymsp[0].minor.yy132 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} + case 176: /* idlist ::= nm */ +{yymsp[0].minor.yy254 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} break; - case 179: /* expr ::= LP expr RP */ -{yymsp[-2].minor.yy454 = yymsp[-1].minor.yy454;} + case 177: /* expr ::= LP expr RP */ +{yymsp[-2].minor.yy528 = yymsp[-1].minor.yy528;} break; - case 180: /* expr ::= ID|INDEXED|JOIN_KW */ -{yymsp[0].minor.yy454=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} + 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*/} break; - case 181: /* expr ::= nm DOT nm */ + case 180: /* 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.yy454 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); + yylhsminor.yy528 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); } - yymsp[-2].minor.yy454 = yylhsminor.yy454; + yymsp[-2].minor.yy528 = yylhsminor.yy528; break; - case 182: /* expr ::= nm DOT nm DOT nm */ + case 181: /* 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); @@ -176838,27 +169634,27 @@ static YYACTIONTYPE yy_reduce( if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, 0, temp1); } - yylhsminor.yy454 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); + yylhsminor.yy528 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); } - yymsp[-4].minor.yy454 = yylhsminor.yy454; + yymsp[-4].minor.yy528 = yylhsminor.yy528; break; - 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*/} + 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*/} break; - case 185: /* term ::= INTEGER */ + case 184: /* term ::= INTEGER */ { - yylhsminor.yy454 = 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); + yylhsminor.yy528 = 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); } - yymsp[0].minor.yy454 = yylhsminor.yy454; + yymsp[0].minor.yy528 = yylhsminor.yy528; break; - case 186: /* expr ::= VARIABLE */ + case 185: /* expr ::= VARIABLE */ { if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){ u32 n = yymsp[0].minor.yy0.n; - yymsp[0].minor.yy454 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0); - sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy454, n); + yymsp[0].minor.yy528 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0); + sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy528, 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 @@ -176867,203 +169663,179 @@ static YYACTIONTYPE yy_reduce( assert( t.n>=2 ); if( pParse->nested==0 ){ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t); - yymsp[0].minor.yy454 = 0; + yymsp[0].minor.yy528 = 0; }else{ - yymsp[0].minor.yy454 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); - if( yymsp[0].minor.yy454 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy454->iTable); + yymsp[0].minor.yy528 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); + if( yymsp[0].minor.yy528 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy528->iTable); } } } break; - case 187: /* expr ::= expr COLLATE ID|STRING */ -{ - yymsp[-2].minor.yy454 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy454, &yymsp[0].minor.yy0, 1); -} - break; - case 188: /* expr ::= CAST LP expr AS typetoken RP */ + case 186: /* expr ::= expr COLLATE ID|STRING */ { - yymsp[-5].minor.yy454 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); - sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy454, yymsp[-3].minor.yy454, 0); + yymsp[-2].minor.yy528 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy528, &yymsp[0].minor.yy0, 1); } break; - case 189: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ + case 187: /* expr ::= CAST LP expr AS typetoken RP */ { - yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy14, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy144); + yymsp[-5].minor.yy528 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); + sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy528, yymsp[-3].minor.yy528, 0); } - yymsp[-4].minor.yy454 = yylhsminor.yy454; break; - case 190: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ + case 188: /* expr ::= ID|INDEXED LP distinct exprlist RP */ { - yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-4].minor.yy14, &yymsp[-7].minor.yy0, yymsp[-5].minor.yy144); - sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy454, yymsp[-1].minor.yy14); + yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy394); } - yymsp[-7].minor.yy454 = yylhsminor.yy454; + yymsp[-4].minor.yy528 = yylhsminor.yy528; break; - case 191: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ + case 189: /* expr ::= ID|INDEXED LP STAR RP */ { - yylhsminor.yy454 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0); + yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0); } - yymsp[-3].minor.yy454 = yylhsminor.yy454; + yymsp[-3].minor.yy528 = yylhsminor.yy528; break; - case 192: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ + case 190: /* expr ::= ID|INDEXED LP distinct exprlist RP filter_over */ { - yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy14, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy144); - sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211); + yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy322, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy394); + sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41); } - yymsp[-5].minor.yy454 = yylhsminor.yy454; + yymsp[-5].minor.yy528 = yylhsminor.yy528; break; - case 193: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ + case 191: /* expr ::= ID|INDEXED LP STAR RP filter_over */ { - yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-5].minor.yy14, &yymsp[-8].minor.yy0, yymsp[-6].minor.yy144); - sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211); - sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy454, yymsp[-2].minor.yy14); + yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0); + sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41); } - yymsp[-8].minor.yy454 = yylhsminor.yy454; + yymsp[-4].minor.yy528 = yylhsminor.yy528; break; - case 194: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ + case 192: /* term ::= CTIME_KW */ { - yylhsminor.yy454 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0); - sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211); + yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0); } - yymsp[-4].minor.yy454 = yylhsminor.yy454; + yymsp[0].minor.yy528 = yylhsminor.yy528; break; - case 195: /* term ::= CTIME_KW */ + case 193: /* expr ::= LP nexprlist COMMA expr RP */ { - yylhsminor.yy454 = 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 = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy14, yymsp[-1].minor.yy454); - yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); - if( yymsp[-4].minor.yy454 ){ - yymsp[-4].minor.yy454->x.pList = pList; + ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy322, yymsp[-1].minor.yy528); + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); + if( yymsp[-4].minor.yy528 ){ + yymsp[-4].minor.yy528->x.pList = pList; if( ALWAYS(pList->nExpr) ){ - yymsp[-4].minor.yy454->flags |= pList->a[0].pExpr->flags & EP_Propagate; + yymsp[-4].minor.yy528->flags |= pList->a[0].pExpr->flags & EP_Propagate; } }else{ sqlite3ExprListDelete(pParse->db, pList); } } break; - case 197: /* expr ::= expr AND expr */ -{yymsp[-2].minor.yy454=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);} + case 194: /* expr ::= expr AND expr */ +{yymsp[-2].minor.yy528=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);} break; - 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=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);} + 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=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);} break; - case 205: /* likeop ::= NOT LIKE_KW|MATCH */ + case 202: /* 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 206: /* expr ::= expr likeop expr */ + case 203: /* expr ::= expr likeop expr */ { ExprList *pList; int bNot = yymsp[-1].minor.yy0.n & 0x80000000; yymsp[-1].minor.yy0.n &= 0x7fffffff; - pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy454); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy454); - yymsp[-2].minor.yy454 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); - if( bNot ) yymsp[-2].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy454, 0); - if( yymsp[-2].minor.yy454 ) yymsp[-2].minor.yy454->flags |= EP_InfixFunc; + pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy528); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy528); + yymsp[-2].minor.yy528 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); + if( bNot ) yymsp[-2].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy528, 0); + if( yymsp[-2].minor.yy528 ) yymsp[-2].minor.yy528->flags |= EP_InfixFunc; } break; - case 207: /* expr ::= expr likeop expr ESCAPE expr */ + case 204: /* expr ::= expr likeop expr ESCAPE expr */ { ExprList *pList; int bNot = yymsp[-3].minor.yy0.n & 0x80000000; yymsp[-3].minor.yy0.n &= 0x7fffffff; - pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy454); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy454); - yymsp[-4].minor.yy454 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0); - if( bNot ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0); - if( yymsp[-4].minor.yy454 ) yymsp[-4].minor.yy454->flags |= EP_InfixFunc; + pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy528); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy528); + yymsp[-4].minor.yy528 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0); + if( bNot ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); + if( yymsp[-4].minor.yy528 ) yymsp[-4].minor.yy528->flags |= EP_InfixFunc; } break; - case 208: /* expr ::= expr ISNULL|NOTNULL */ -{yymsp[-1].minor.yy454 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy454,0);} + case 205: /* expr ::= expr ISNULL|NOTNULL */ +{yymsp[-1].minor.yy528 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy528,0);} break; - case 209: /* expr ::= expr NOT NULL */ -{yymsp[-2].minor.yy454 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy454,0);} + case 206: /* expr ::= expr NOT NULL */ +{yymsp[-2].minor.yy528 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy528,0);} break; - case 210: /* expr ::= expr IS expr */ + case 207: /* expr ::= expr IS expr */ { - yymsp[-2].minor.yy454 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy454,yymsp[0].minor.yy454); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-2].minor.yy454, TK_ISNULL); + yymsp[-2].minor.yy528 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy528,yymsp[0].minor.yy528); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-2].minor.yy528, TK_ISNULL); } break; - case 211: /* expr ::= expr IS NOT expr */ + case 208: /* expr ::= expr IS NOT expr */ { - yymsp[-3].minor.yy454 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy454,yymsp[0].minor.yy454); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-3].minor.yy454, TK_NOTNULL); + yymsp[-3].minor.yy528 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy528,yymsp[0].minor.yy528); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-3].minor.yy528, TK_NOTNULL); } break; - case 212: /* expr ::= expr IS NOT DISTINCT FROM expr */ + case 209: /* expr ::= expr IS NOT DISTINCT FROM expr */ { - yymsp[-5].minor.yy454 = sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy454,yymsp[0].minor.yy454); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-5].minor.yy454, TK_ISNULL); + yymsp[-5].minor.yy528 = sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy528,yymsp[0].minor.yy528); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-5].minor.yy528, TK_ISNULL); } break; - case 213: /* expr ::= expr IS DISTINCT FROM expr */ + case 210: /* expr ::= expr IS DISTINCT FROM expr */ { - yymsp[-4].minor.yy454 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy454,yymsp[0].minor.yy454); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-4].minor.yy454, TK_NOTNULL); + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy528,yymsp[0].minor.yy528); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-4].minor.yy528, TK_NOTNULL); } break; - case 214: /* expr ::= NOT expr */ - case 215: /* expr ::= BITNOT expr */ yytestcase(yyruleno==215); -{yymsp[-1].minor.yy454 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy454, 0);/*A-overwrites-B*/} + case 211: /* expr ::= NOT expr */ + case 212: /* expr ::= BITNOT expr */ yytestcase(yyruleno==212); +{yymsp[-1].minor.yy528 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy528, 0);/*A-overwrites-B*/} break; - case 216: /* expr ::= PLUS|MINUS expr */ + case 213: /* expr ::= PLUS|MINUS expr */ { - 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 = sqlite3PExpr(pParse, op, p, 0); - /*A-overwrites-B*/ - } + yymsp[-1].minor.yy528 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy528, 0); + /*A-overwrites-B*/ } break; - case 217: /* expr ::= expr PTR expr */ + case 214: /* expr ::= expr PTR expr */ { - ExprList *pList = sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy454); - pList = sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy454); - yylhsminor.yy454 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); + ExprList *pList = sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy528); + pList = sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy528); + yylhsminor.yy528 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); } - yymsp[-2].minor.yy454 = yylhsminor.yy454; + yymsp[-2].minor.yy528 = yylhsminor.yy528; break; - case 218: /* between_op ::= BETWEEN */ - case 221: /* in_op ::= IN */ yytestcase(yyruleno==221); -{yymsp[0].minor.yy144 = 0;} + case 215: /* between_op ::= BETWEEN */ + case 218: /* in_op ::= IN */ yytestcase(yyruleno==218); +{yymsp[0].minor.yy394 = 0;} break; - case 220: /* expr ::= expr between_op expr AND expr */ + case 217: /* expr ::= expr between_op expr AND expr */ { - ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy454); - yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy454, 0); - if( yymsp[-4].minor.yy454 ){ - yymsp[-4].minor.yy454->x.pList = pList; + ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy528); + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy528, 0); + if( yymsp[-4].minor.yy528 ){ + yymsp[-4].minor.yy528->x.pList = pList; }else{ sqlite3ExprListDelete(pParse->db, pList); } - if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0); + if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); } break; - case 223: /* expr ::= expr in_op LP exprlist RP */ + case 220: /* expr ::= expr in_op LP exprlist RP */ { - if( yymsp[-1].minor.yy14==0 ){ + if( yymsp[-1].minor.yy322==0 ){ /* Expressions of the form ** ** expr1 IN () @@ -177072,208 +169844,206 @@ static YYACTIONTYPE yy_reduce( ** simplify to constants 0 (false) and 1 (true), respectively, ** regardless of the value of expr1. */ - sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy454); - yymsp[-4].minor.yy454 = sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy144 ? "true" : "false"); - if( yymsp[-4].minor.yy454 ) sqlite3ExprIdToTrueFalse(yymsp[-4].minor.yy454); - }else{ - Expr *pRHS = yymsp[-1].minor.yy14->a[0].pExpr; - if( yymsp[-1].minor.yy14->nExpr==1 && sqlite3ExprIsConstant(pParse,pRHS) && yymsp[-4].minor.yy454->op!=TK_VECTOR ){ - yymsp[-1].minor.yy14->a[0].pExpr = 0; - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14); + sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy528); + yymsp[-4].minor.yy528 = sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy394 ? "true" : "false"); + if( yymsp[-4].minor.yy528 ) sqlite3ExprIdToTrueFalse(yymsp[-4].minor.yy528); + }else{ + Expr *pRHS = yymsp[-1].minor.yy322->a[0].pExpr; + if( yymsp[-1].minor.yy322->nExpr==1 && sqlite3ExprIsConstant(pRHS) && yymsp[-4].minor.yy528->op!=TK_VECTOR ){ + yymsp[-1].minor.yy322->a[0].pExpr = 0; + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322); pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0); - yymsp[-4].minor.yy454 = 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 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pRHS->x.pSelect); - pRHS->x.pSelect = 0; - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14); - }else{ - yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0); - if( yymsp[-4].minor.yy454==0 ){ - 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 = sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy14); + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy528, pRHS); + }else{ + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0); + if( yymsp[-4].minor.yy528==0 ){ + 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 = sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy322); if( pSelectRHS ){ parserDoubleLinkSelect(pParse, pSelectRHS); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pSelectRHS); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pSelectRHS); } }else{ - yymsp[-4].minor.yy454->x.pList = yymsp[-1].minor.yy14; - sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy454); + yymsp[-4].minor.yy528->x.pList = yymsp[-1].minor.yy322; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy528); } } - if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0); + if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); } } break; - case 224: /* expr ::= LP select RP */ + case 221: /* expr ::= LP select RP */ { - yymsp[-2].minor.yy454 = sqlite3PExpr(pParse, TK_SELECT, 0, 0); - sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy454, yymsp[-1].minor.yy555); + yymsp[-2].minor.yy528 = sqlite3PExpr(pParse, TK_SELECT, 0, 0); + sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy528, yymsp[-1].minor.yy47); } break; - case 225: /* expr ::= expr in_op LP select RP */ + case 222: /* expr ::= expr in_op LP select RP */ { - yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, yymsp[-1].minor.yy555); - if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0); + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, yymsp[-1].minor.yy47); + if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); } break; - case 226: /* expr ::= expr in_op nm dbnm paren_exprlist */ + case 223: /* expr ::= expr in_op nm dbnm paren_exprlist */ { SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0); - if( yymsp[0].minor.yy14 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy14); - yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pSelect); - if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0); + if( yymsp[0].minor.yy322 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy322); + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pSelect); + if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); } break; - case 227: /* expr ::= EXISTS LP select RP */ + case 224: /* expr ::= EXISTS LP select RP */ { Expr *p; - p = yymsp[-3].minor.yy454 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); - sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy555); + p = yymsp[-3].minor.yy528 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); + sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy47); } break; - case 228: /* expr ::= CASE case_operand case_exprlist case_else END */ + case 225: /* expr ::= CASE case_operand case_exprlist case_else END */ { - yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy454, 0); - if( yymsp[-4].minor.yy454 ){ - yymsp[-4].minor.yy454->x.pList = yymsp[-1].minor.yy454 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454) : yymsp[-2].minor.yy14; - sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy454); + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy528, 0); + if( yymsp[-4].minor.yy528 ){ + yymsp[-4].minor.yy528->x.pList = yymsp[-1].minor.yy528 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528) : yymsp[-2].minor.yy322; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy528); }else{ - sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy14); - sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy454); + sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy322); + sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy528); } } break; - case 229: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ + case 226: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ { - yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, yymsp[-2].minor.yy454); - yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, yymsp[0].minor.yy454); + yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[-2].minor.yy528); + yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[0].minor.yy528); } break; - case 230: /* case_exprlist ::= WHEN expr THEN expr */ + case 227: /* case_exprlist ::= WHEN expr THEN expr */ { - yymsp[-3].minor.yy14 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454); - yymsp[-3].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy14, yymsp[0].minor.yy454); + yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528); + yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322, yymsp[0].minor.yy528); } break; - case 235: /* nexprlist ::= nexprlist COMMA expr */ -{yymsp[-2].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[0].minor.yy454);} + case 230: /* case_operand ::= expr */ +{yymsp[0].minor.yy528 = yymsp[0].minor.yy528; /*A-overwrites-X*/} break; - case 236: /* nexprlist ::= expr */ -{yymsp[0].minor.yy14 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy454); /*A-overwrites-Y*/} + case 233: /* nexprlist ::= nexprlist COMMA expr */ +{yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[0].minor.yy528);} break; - 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;} + case 234: /* nexprlist ::= expr */ +{yymsp[0].minor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy528); /*A-overwrites-Y*/} break; - case 239: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + 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 */ { sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, - 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); + 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); if( IN_RENAME_OBJECT && pParse->pNewIndex ){ sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &yymsp[-4].minor.yy0); } } break; - case 240: /* uniqueflag ::= UNIQUE */ - case 282: /* raisetype ::= ABORT */ yytestcase(yyruleno==282); -{yymsp[0].minor.yy144 = OE_Abort;} + case 238: /* uniqueflag ::= UNIQUE */ + case 280: /* raisetype ::= ABORT */ yytestcase(yyruleno==280); +{yymsp[0].minor.yy394 = OE_Abort;} break; - case 241: /* uniqueflag ::= */ -{yymsp[1].minor.yy144 = OE_None;} + case 239: /* uniqueflag ::= */ +{yymsp[1].minor.yy394 = OE_None;} break; - case 244: /* eidlist ::= eidlist COMMA nm collate sortorder */ + case 242: /* eidlist ::= eidlist COMMA nm collate sortorder */ { - yymsp[-4].minor.yy14 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy14, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy144, yymsp[0].minor.yy144); + yymsp[-4].minor.yy322 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy394, yymsp[0].minor.yy394); } break; - case 245: /* eidlist ::= nm collate sortorder */ + case 243: /* eidlist ::= nm collate sortorder */ { - yymsp[-2].minor.yy14 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy144, yymsp[0].minor.yy144); /*A-overwrites-Y*/ + yymsp[-2].minor.yy322 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy394, yymsp[0].minor.yy394); /*A-overwrites-Y*/ } break; - case 248: /* cmd ::= DROP INDEX ifexists fullname */ -{sqlite3DropIndex(pParse, yymsp[0].minor.yy203, yymsp[-1].minor.yy144);} + case 246: /* cmd ::= DROP INDEX ifexists fullname */ +{sqlite3DropIndex(pParse, yymsp[0].minor.yy131, yymsp[-1].minor.yy394);} break; - case 249: /* cmd ::= VACUUM vinto */ -{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy454);} + case 247: /* cmd ::= VACUUM vinto */ +{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy528);} break; - case 250: /* cmd ::= VACUUM nm vinto */ -{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy454);} + case 248: /* cmd ::= VACUUM nm vinto */ +{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy528);} break; - case 253: /* cmd ::= PRAGMA nm dbnm */ + case 251: /* cmd ::= PRAGMA nm dbnm */ {sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);} break; - case 254: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ + case 252: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);} break; - case 255: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ + case 253: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);} break; - case 256: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ + case 254: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);} break; - case 257: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ + case 255: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);} break; - case 260: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + case 258: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ { Token all; all.z = yymsp[-3].minor.yy0.z; all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n; - sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy427, &all); + sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy33, &all); } break; - case 261: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + case 259: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ { - sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.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); + 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); yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ } break; - case 262: /* trigger_time ::= BEFORE|AFTER */ -{ yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-X*/ } + case 260: /* trigger_time ::= BEFORE|AFTER */ +{ yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/ } break; - case 263: /* trigger_time ::= INSTEAD OF */ -{ yymsp[-1].minor.yy144 = TK_INSTEAD;} + case 261: /* trigger_time ::= INSTEAD OF */ +{ yymsp[-1].minor.yy394 = TK_INSTEAD;} break; - case 264: /* trigger_time ::= */ -{ yymsp[1].minor.yy144 = TK_BEFORE; } + case 262: /* trigger_time ::= */ +{ yymsp[1].minor.yy394 = TK_BEFORE; } break; - 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;} + 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;} break; - case 267: /* trigger_event ::= UPDATE OF idlist */ -{yymsp[-2].minor.yy286.a = TK_UPDATE; yymsp[-2].minor.yy286.b = yymsp[0].minor.yy132;} + case 265: /* trigger_event ::= UPDATE OF idlist */ +{yymsp[-2].minor.yy180.a = TK_UPDATE; yymsp[-2].minor.yy180.b = yymsp[0].minor.yy254;} break; - case 268: /* when_clause ::= */ - case 287: /* key_opt ::= */ yytestcase(yyruleno==287); -{ yymsp[1].minor.yy454 = 0; } + case 266: /* when_clause ::= */ + case 285: /* key_opt ::= */ yytestcase(yyruleno==285); +{ yymsp[1].minor.yy528 = 0; } break; - case 269: /* when_clause ::= WHEN expr */ - case 288: /* key_opt ::= KEY expr */ yytestcase(yyruleno==288); -{ yymsp[-1].minor.yy454 = yymsp[0].minor.yy454; } + case 267: /* when_clause ::= WHEN expr */ + case 286: /* key_opt ::= KEY expr */ yytestcase(yyruleno==286); +{ yymsp[-1].minor.yy528 = yymsp[0].minor.yy528; } break; - case 270: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + case 268: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ { - 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; + 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; } break; - case 271: /* trigger_cmd_list ::= trigger_cmd SEMI */ + case 269: /* trigger_cmd_list ::= trigger_cmd SEMI */ { - assert( yymsp[-1].minor.yy427!=0 ); - yymsp[-1].minor.yy427->pLast = yymsp[-1].minor.yy427; + assert( yymsp[-1].minor.yy33!=0 ); + yymsp[-1].minor.yy33->pLast = yymsp[-1].minor.yy33; } break; - case 272: /* trnm ::= nm DOT nm */ + case 270: /* trnm ::= nm DOT nm */ { yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; sqlite3ErrorMsg(pParse, @@ -177281,377 +170051,370 @@ static YYACTIONTYPE yy_reduce( "statements within triggers"); } break; - case 273: /* tridxby ::= INDEXED BY nm */ + case 271: /* tridxby ::= INDEXED BY nm */ { sqlite3ErrorMsg(pParse, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 274: /* tridxby ::= NOT INDEXED */ + case 272: /* tridxby ::= NOT INDEXED */ { sqlite3ErrorMsg(pParse, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 275: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ -{yylhsminor.yy427 = 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; + case 273: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ +{yylhsminor.yy33 = 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; break; - case 276: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + case 274: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ { - yylhsminor.yy427 = 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*/ + yylhsminor.yy33 = 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*/ } - yymsp[-7].minor.yy427 = yylhsminor.yy427; + yymsp[-7].minor.yy33 = yylhsminor.yy33; break; - case 277: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ -{yylhsminor.yy427 = 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; + case 275: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ +{yylhsminor.yy33 = 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; break; - case 278: /* trigger_cmd ::= scanpt select scanpt */ -{yylhsminor.yy427 = 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; + case 276: /* trigger_cmd ::= scanpt select scanpt */ +{yylhsminor.yy33 = 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; break; - case 279: /* expr ::= RAISE LP IGNORE RP */ + case 277: /* expr ::= RAISE LP IGNORE RP */ { - yymsp[-3].minor.yy454 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); - if( yymsp[-3].minor.yy454 ){ - yymsp[-3].minor.yy454->affExpr = OE_Ignore; + yymsp[-3].minor.yy528 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); + if( yymsp[-3].minor.yy528 ){ + yymsp[-3].minor.yy528->affExpr = OE_Ignore; } } break; - case 280: /* expr ::= RAISE LP raisetype COMMA nm RP */ + case 278: /* expr ::= RAISE LP raisetype COMMA nm RP */ { - yymsp[-5].minor.yy454 = 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; + yymsp[-5].minor.yy528 = 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; } } break; - case 281: /* raisetype ::= ROLLBACK */ -{yymsp[0].minor.yy144 = OE_Rollback;} + case 279: /* raisetype ::= ROLLBACK */ +{yymsp[0].minor.yy394 = OE_Rollback;} break; - case 283: /* raisetype ::= FAIL */ -{yymsp[0].minor.yy144 = OE_Fail;} + case 281: /* raisetype ::= FAIL */ +{yymsp[0].minor.yy394 = OE_Fail;} break; - case 284: /* cmd ::= DROP TRIGGER ifexists fullname */ + case 282: /* cmd ::= DROP TRIGGER ifexists fullname */ { - sqlite3DropTrigger(pParse,yymsp[0].minor.yy203,yymsp[-1].minor.yy144); + sqlite3DropTrigger(pParse,yymsp[0].minor.yy131,yymsp[-1].minor.yy394); } break; - case 285: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + case 283: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ { - sqlite3Attach(pParse, yymsp[-3].minor.yy454, yymsp[-1].minor.yy454, yymsp[0].minor.yy454); + sqlite3Attach(pParse, yymsp[-3].minor.yy528, yymsp[-1].minor.yy528, yymsp[0].minor.yy528); } break; - case 286: /* cmd ::= DETACH database_kw_opt expr */ + case 284: /* cmd ::= DETACH database_kw_opt expr */ { - sqlite3Detach(pParse, yymsp[0].minor.yy454); + sqlite3Detach(pParse, yymsp[0].minor.yy528); } break; - case 289: /* cmd ::= REINDEX */ + case 287: /* cmd ::= REINDEX */ {sqlite3Reindex(pParse, 0, 0);} break; - case 290: /* cmd ::= REINDEX nm dbnm */ + case 288: /* cmd ::= REINDEX nm dbnm */ {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 291: /* cmd ::= ANALYZE */ + case 289: /* cmd ::= ANALYZE */ {sqlite3Analyze(pParse, 0, 0);} break; - case 292: /* cmd ::= ANALYZE nm dbnm */ + case 290: /* cmd ::= ANALYZE nm dbnm */ {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 293: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ + case 291: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ { - sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy203,&yymsp[0].minor.yy0); + sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy131,&yymsp[0].minor.yy0); } break; - case 294: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + case 292: /* 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; sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0); } break; - case 295: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ + case 293: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ { - sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy203, &yymsp[0].minor.yy0); + sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy131, &yymsp[0].minor.yy0); } break; - case 296: /* add_column_fullname ::= fullname */ + case 294: /* add_column_fullname ::= fullname */ { disableLookaside(pParse); - sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy203); + sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy131); } break; - case 297: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + case 295: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ { - sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy203, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); + sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy131, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); } break; - case 298: /* cmd ::= create_vtab */ + case 296: /* cmd ::= create_vtab */ {sqlite3VtabFinishParse(pParse,0);} break; - case 299: /* cmd ::= create_vtab LP vtabarglist RP */ + case 297: /* cmd ::= create_vtab LP vtabarglist RP */ {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} break; - case 300: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + case 298: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ { - sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy144); + sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy394); } break; - case 301: /* vtabarg ::= */ + case 299: /* vtabarg ::= */ {sqlite3VtabArgInit(pParse);} break; - case 302: /* vtabargtoken ::= ANY */ - case 303: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==303); - case 304: /* lp ::= LP */ yytestcase(yyruleno==304); + case 300: /* vtabargtoken ::= ANY */ + case 301: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==301); + case 302: /* lp ::= LP */ yytestcase(yyruleno==302); {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} break; - case 305: /* with ::= WITH wqlist */ - case 306: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==306); -{ sqlite3WithPush(pParse, yymsp[0].minor.yy59, 1); } + case 303: /* with ::= WITH wqlist */ + case 304: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==304); +{ sqlite3WithPush(pParse, yymsp[0].minor.yy521, 1); } break; - case 307: /* wqas ::= AS */ -{yymsp[0].minor.yy462 = M10d_Any;} + case 305: /* wqas ::= AS */ +{yymsp[0].minor.yy516 = M10d_Any;} break; - case 308: /* wqas ::= AS MATERIALIZED */ -{yymsp[-1].minor.yy462 = M10d_Yes;} + case 306: /* wqas ::= AS MATERIALIZED */ +{yymsp[-1].minor.yy516 = M10d_Yes;} break; - case 309: /* wqas ::= AS NOT MATERIALIZED */ -{yymsp[-2].minor.yy462 = M10d_No;} + case 307: /* wqas ::= AS NOT MATERIALIZED */ +{yymsp[-2].minor.yy516 = M10d_No;} break; - case 310: /* wqitem ::= withnm eidlist_opt wqas LP select RP */ + case 308: /* wqitem ::= nm eidlist_opt wqas LP select RP */ { - yymsp[-5].minor.yy67 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy14, yymsp[-1].minor.yy555, yymsp[-3].minor.yy462); /*A-overwrites-X*/ + yymsp[-5].minor.yy385 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy47, yymsp[-3].minor.yy516); /*A-overwrites-X*/ } break; - case 311: /* withnm ::= nm */ -{pParse->bHasWith = 1;} - break; - case 312: /* wqlist ::= wqitem */ + case 309: /* wqlist ::= wqitem */ { - yymsp[0].minor.yy59 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy67); /*A-overwrites-X*/ + yymsp[0].minor.yy521 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy385); /*A-overwrites-X*/ } break; - case 313: /* wqlist ::= wqlist COMMA wqitem */ + case 310: /* wqlist ::= wqlist COMMA wqitem */ { - yymsp[-2].minor.yy59 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy59, yymsp[0].minor.yy67); + yymsp[-2].minor.yy521 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy521, yymsp[0].minor.yy385); } break; - case 314: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ + 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 */ { - assert( yymsp[0].minor.yy211!=0 ); - 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; + assert( yymsp[0].minor.yy41!=0 ); + 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.yy211 = yylhsminor.yy211; + yymsp[-2].minor.yy41 = yylhsminor.yy41; break; - case 315: /* windowdefn ::= nm AS LP window RP */ + case 313: /* windowdefn ::= nm AS LP window RP */ { - if( ALWAYS(yymsp[-1].minor.yy211) ){ - yymsp[-1].minor.yy211->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n); + if( ALWAYS(yymsp[-1].minor.yy41) ){ + yymsp[-1].minor.yy41->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n); } - yylhsminor.yy211 = yymsp[-1].minor.yy211; + yylhsminor.yy41 = yymsp[-1].minor.yy41; +} + yymsp[-4].minor.yy41 = yylhsminor.yy41; + break; + case 314: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */ +{ + yymsp[-4].minor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, 0); } - yymsp[-4].minor.yy211 = yylhsminor.yy211; break; - case 316: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + case 315: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ { - yymsp[-4].minor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy14, yymsp[-1].minor.yy14, 0); + yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, &yymsp[-5].minor.yy0); } + yymsp[-5].minor.yy41 = yylhsminor.yy41; break; - case 317: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + case 316: /* window ::= ORDER BY sortlist frame_opt */ { - yylhsminor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy14, yymsp[-1].minor.yy14, &yymsp[-5].minor.yy0); + yymsp[-3].minor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, 0); } - yymsp[-5].minor.yy211 = yylhsminor.yy211; break; - case 318: /* window ::= ORDER BY sortlist frame_opt */ + case 317: /* window ::= nm ORDER BY sortlist frame_opt */ { - yymsp[-3].minor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, yymsp[-1].minor.yy14, 0); + yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0); } + yymsp[-4].minor.yy41 = yylhsminor.yy41; break; - case 319: /* window ::= nm ORDER BY sortlist frame_opt */ + case 318: /* window ::= frame_opt */ + case 337: /* filter_over ::= over_clause */ yytestcase(yyruleno==337); { - yylhsminor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, yymsp[-1].minor.yy14, &yymsp[-4].minor.yy0); + yylhsminor.yy41 = yymsp[0].minor.yy41; } - yymsp[-4].minor.yy211 = yylhsminor.yy211; + yymsp[0].minor.yy41 = yylhsminor.yy41; break; - case 320: /* window ::= nm frame_opt */ + case 319: /* window ::= nm frame_opt */ { - yylhsminor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, 0, &yymsp[-1].minor.yy0); + yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, 0, &yymsp[-1].minor.yy0); } - yymsp[-1].minor.yy211 = yylhsminor.yy211; + yymsp[-1].minor.yy41 = yylhsminor.yy41; break; - case 321: /* frame_opt ::= */ + case 320: /* frame_opt ::= */ { - yymsp[1].minor.yy211 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0); + yymsp[1].minor.yy41 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0); } break; - case 322: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + case 321: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ { - yylhsminor.yy211 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy144, yymsp[-1].minor.yy509.eType, yymsp[-1].minor.yy509.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy462); + yylhsminor.yy41 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy394, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy516); } - yymsp[-2].minor.yy211 = yylhsminor.yy211; + yymsp[-2].minor.yy41 = yylhsminor.yy41; break; - case 323: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + case 322: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ { - yylhsminor.yy211 = 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); + yylhsminor.yy41 = 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); } - yymsp[-5].minor.yy211 = yylhsminor.yy211; + yymsp[-5].minor.yy41 = yylhsminor.yy41; break; - 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; + 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; break; - 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; + 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; break; - 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; + 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; break; - case 331: /* frame_exclude_opt ::= */ -{yymsp[1].minor.yy462 = 0;} + case 330: /* frame_exclude_opt ::= */ +{yymsp[1].minor.yy516 = 0;} break; - case 332: /* frame_exclude_opt ::= EXCLUDE frame_exclude */ -{yymsp[-1].minor.yy462 = yymsp[0].minor.yy462;} + case 331: /* frame_exclude_opt ::= EXCLUDE frame_exclude */ +{yymsp[-1].minor.yy516 = yymsp[0].minor.yy516;} break; - 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*/} + 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*/} break; - case 335: /* frame_exclude ::= GROUP|TIES */ -{yymsp[0].minor.yy462 = yymsp[0].major; /*A-overwrites-X*/} + case 334: /* frame_exclude ::= GROUP|TIES */ +{yymsp[0].minor.yy516 = yymsp[0].major; /*A-overwrites-X*/} break; - case 336: /* window_clause ::= WINDOW windowdefn_list */ -{ yymsp[-1].minor.yy211 = yymsp[0].minor.yy211; } + case 335: /* window_clause ::= WINDOW windowdefn_list */ +{ yymsp[-1].minor.yy41 = yymsp[0].minor.yy41; } break; - case 337: /* filter_over ::= filter_clause over_clause */ + case 336: /* filter_over ::= filter_clause over_clause */ { - if( yymsp[0].minor.yy211 ){ - yymsp[0].minor.yy211->pFilter = yymsp[-1].minor.yy454; + if( yymsp[0].minor.yy41 ){ + yymsp[0].minor.yy41->pFilter = yymsp[-1].minor.yy528; }else{ - sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy454); + sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy528); } - yylhsminor.yy211 = yymsp[0].minor.yy211; + yylhsminor.yy41 = yymsp[0].minor.yy41; } - yymsp[-1].minor.yy211 = yylhsminor.yy211; + yymsp[-1].minor.yy41 = yylhsminor.yy41; break; - case 338: /* filter_over ::= over_clause */ + case 338: /* filter_over ::= filter_clause */ { - yylhsminor.yy211 = yymsp[0].minor.yy211; -} - yymsp[0].minor.yy211 = yylhsminor.yy211; - break; - case 339: /* filter_over ::= filter_clause */ -{ - yylhsminor.yy211 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); - if( yylhsminor.yy211 ){ - yylhsminor.yy211->eFrmType = TK_FILTER; - yylhsminor.yy211->pFilter = yymsp[0].minor.yy454; + yylhsminor.yy41 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); + if( yylhsminor.yy41 ){ + yylhsminor.yy41->eFrmType = TK_FILTER; + yylhsminor.yy41->pFilter = yymsp[0].minor.yy528; }else{ - sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy454); + sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy528); } } - yymsp[0].minor.yy211 = yylhsminor.yy211; + yymsp[0].minor.yy41 = yylhsminor.yy41; break; - case 340: /* over_clause ::= OVER LP window RP */ + case 339: /* over_clause ::= OVER LP window RP */ { - yymsp[-3].minor.yy211 = yymsp[-1].minor.yy211; - assert( yymsp[-3].minor.yy211!=0 ); + yymsp[-3].minor.yy41 = yymsp[-1].minor.yy41; + assert( yymsp[-3].minor.yy41!=0 ); } break; - case 341: /* over_clause ::= OVER nm */ + case 340: /* over_clause ::= OVER nm */ { - yymsp[-1].minor.yy211 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); - if( yymsp[-1].minor.yy211 ){ - yymsp[-1].minor.yy211->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n); + yymsp[-1].minor.yy41 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); + if( yymsp[-1].minor.yy41 ){ + yymsp[-1].minor.yy41->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n); } } break; - 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); - sqlite3DequoteNumber(pParse, yylhsminor.yy454); -} - yymsp[0].minor.yy454 = yylhsminor.yy454; + case 341: /* filter_clause ::= FILTER LP WHERE expr RP */ +{ yymsp[-4].minor.yy528 = yymsp[-1].minor.yy528; } break; default: - /* (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); + /* (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); break; /********** End reduce actions ************************************************/ }; @@ -177838,12 +170601,19 @@ SQLITE_PRIVATE void 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 sqlite3ParserCTX_PARAM); }else if( yyact <= YY_MAX_SHIFTREDUCE ){ @@ -178220,7 +170990,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[148] = {0, +static const unsigned char aKWNext[147] = { 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, @@ -178235,7 +171005,7 @@ static const unsigned char aKWNext[148] = {0, 102, 0, 0, 87, }; /* aKWLen[i] is the length (in bytes) of the i-th keyword */ -static const unsigned char aKWLen[148] = {0, +static const unsigned char aKWLen[147] = { 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, @@ -178251,7 +171021,7 @@ static const unsigned char aKWLen[148] = {0, }; /* aKWOffset[i] is the index into zKWText[] of the start of ** the text for the i-th keyword. */ -static const unsigned short int aKWOffset[148] = {0, +static const unsigned short int aKWOffset[147] = { 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, @@ -178266,7 +171036,7 @@ static const unsigned short int aKWOffset[148] = {0, 648, 650, 655, 659, }; /* aKWCode[i] is the parser symbol code for the i-th keyword */ -static const unsigned char aKWCode[148] = {0, +static const unsigned char aKWCode[147] = { 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, @@ -178433,185 +171203,185 @@ static const unsigned char aKWCode[148] = {0, static int keywordCode(const char *z, int n, int *pType){ int i, j; const char *zKW; - 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]]; + 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]]; #ifdef SQLITE_ASCII - if( (z[0]&~0x20)!=zKW[0] ) continue; - if( (z[1]&~0x20)!=zKW[1] ) continue; - j = 2; - while( j=2 ) keywordCode((char*)z, n, &id); + keywordCode((char*)z, n, &id); return id; } #define SQLITE_N_KEYWORD 147 SQLITE_API int 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; @@ -178910,62 +171680,31 @@ SQLITE_PRIVATE int 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]=='.' ); + testcase( z[0]=='9' ); *tokenType = TK_INTEGER; #ifndef SQLITE_OMIT_HEX_INTEGER if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){ - for(i=3; 1; i++){ - if( sqlite3Isxdigit(z[i])==0 ){ - if( z[i]==SQLITE_DIGIT_SEPARATOR ){ - *tokenType = TK_QNUMBER; - }else{ - break; - } - } - } - }else + for(i=3; sqlite3Isxdigit(z[i]); i++){} + return i; + } #endif - { - for(i=0; 1; i++){ - if( sqlite3Isdigit(z[i])==0 ){ - if( z[i]==SQLITE_DIGIT_SEPARATOR ){ - *tokenType = TK_QNUMBER; - }else{ - break; - } - } - } + for(i=0; sqlite3Isdigit(z[i]); i++){} #ifndef SQLITE_OMIT_FLOATING_POINT - if( z[i]=='.' ){ - if( *tokenType==TK_INTEGER ) *tokenType = TK_FLOAT; - for(i++; 1; i++){ - if( sqlite3Isdigit(z[i])==0 ){ - if( z[i]==SQLITE_DIGIT_SEPARATOR ){ - *tokenType = TK_QNUMBER; - }else{ - break; - } - } - } - } - if( (z[i]=='e' || z[i]=='E') && - ( sqlite3Isdigit(z[i+1]) - || ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2])) - ) - ){ - if( *tokenType==TK_INTEGER ) *tokenType = TK_FLOAT; - for(i+=2; 1; i++){ - if( sqlite3Isdigit(z[i])==0 ){ - if( z[i]==SQLITE_DIGIT_SEPARATOR ){ - *tokenType = TK_QNUMBER; - }else{ - break; - } - } - } - } -#endif + if( z[i]=='.' ){ + i++; + while( sqlite3Isdigit(z[i]) ){ i++; } + *tokenType = TK_FLOAT; } + if( (z[i]=='e' || z[i]=='E') && + ( sqlite3Isdigit(z[i+1]) + || ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2])) + ) + ){ + i += 2; + while( sqlite3Isdigit(z[i]) ){ i++; } + *tokenType = TK_FLOAT; + } +#endif while( IdChar(z[i]) ){ *tokenType = TK_ILLEGAL; i++; @@ -179013,8 +171752,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ return i; } case CC_KYWD0: { - if( aiClass[z[1]]>CC_KYWD ){ i = 1; break; } - for(i=2; aiClass[z[i]]<=CC_KYWD; i++){} + for(i=1; aiClass[z[i]]<=CC_KYWD; i++){} if( IdChar(z[i]) ){ /* This token started out using characters that can appear in keywords, ** but z[i] is a character not allowed within keywords, so this must @@ -179130,13 +171868,10 @@ SQLITE_PRIVATE int 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 - || tokenType==TK_QNUMBER - ); + assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL ); #endif /* SQLITE_OMIT_WINDOWFUNC */ if( AtomicLoad(&db->u1.isInterrupted) ){ pParse->rc = SQLITE_INTERRUPT; @@ -179169,7 +171904,7 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql){ assert( n==6 ); tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed); #endif /* SQLITE_OMIT_WINDOWFUNC */ - }else if( tokenType!=TK_QNUMBER ){ + }else{ Token x; x.z = zSql; x.n = n; @@ -179796,20 +172531,30 @@ static int sqlite3TestExtInit(sqlite3 *db){ ** Forward declarations of external module initializer functions ** for modules that need them. */ +#ifdef SQLITE_ENABLE_FTS1 +SQLITE_PRIVATE int sqlite3Fts1Init(sqlite3*); +#endif +#ifdef SQLITE_ENABLE_FTS2 +SQLITE_PRIVATE int sqlite3Fts2Init(sqlite3*); +#endif #ifdef SQLITE_ENABLE_FTS5 SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3*); #endif #ifdef SQLITE_ENABLE_STMTVTAB SQLITE_PRIVATE int sqlite3StmtVtabInit(sqlite3*); #endif -#ifdef SQLITE_EXTRA_AUTOEXT -int SQLITE_EXTRA_AUTOEXT(sqlite3*); -#endif + /* ** An array of pointers to extension initializer functions for ** built-in extensions. */ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = { +#ifdef SQLITE_ENABLE_FTS1 + sqlite3Fts1Init, +#endif +#ifdef SQLITE_ENABLE_FTS2 + sqlite3Fts2Init, +#endif #ifdef SQLITE_ENABLE_FTS3 sqlite3Fts3Init, #endif @@ -179838,9 +172583,6 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = { #ifdef SQLITE_ENABLE_BYTECODE_VTAB sqlite3VdbeBytecodeVtabInit, #endif -#ifdef SQLITE_EXTRA_AUTOEXT - SQLITE_EXTRA_AUTOEXT, -#endif }; #ifndef SQLITE_AMALGAMATION @@ -179914,32 +172656,6 @@ SQLITE_API char *sqlite3_temp_directory = 0; */ SQLITE_API char *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. ** @@ -180135,12 +172851,6 @@ SQLITE_API int sqlite3_initialize(void){ } #endif - /* Experimentally determine if high-precision floating point is - ** available. */ -#ifndef SQLITE_OMIT_WSD - sqlite3Config.bUseLongDouble = hasHighPrecisionDouble(rc); -#endif - return rc; } @@ -180210,21 +172920,9 @@ SQLITE_API int sqlite3_config(int op, ...){ va_list ap; int rc = SQLITE_OK; - /* 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( 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 ); - } + /* sqlite3_config() shall return SQLITE_MISUSE if it is invoked while + ** the SQLite library is in use. */ + if( sqlite3GlobalConfig.isInit ) return SQLITE_MISUSE_BKPT; va_start(ap, op); switch( op ){ @@ -180293,7 +172991,6 @@ SQLITE_API int sqlite3_config(int op, ...){ break; } case SQLITE_CONFIG_MEMSTATUS: { - assert( !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. */ @@ -180417,10 +173114,8 @@ SQLITE_API int sqlite3_config(int op, ...){ ** sqlite3GlobalConfig.xLog = va_arg(ap, void(*)(void*,int,const char*)); */ typedef void(*LOGFUNC_t)(void*,int,const char*); - LOGFUNC_t xLog = va_arg(ap, LOGFUNC_t); - void *pLogArg = va_arg(ap, void*); - AtomicStore(&sqlite3GlobalConfig.xLog, xLog); - AtomicStore(&sqlite3GlobalConfig.pLogArg, pLogArg); + sqlite3GlobalConfig.xLog = va_arg(ap, LOGFUNC_t); + sqlite3GlobalConfig.pLogArg = va_arg(ap, void*); break; } @@ -180434,8 +173129,7 @@ SQLITE_API int 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. */ - int bOpenUri = va_arg(ap, int); - AtomicStore(&sqlite3GlobalConfig.bOpenUri, bOpenUri); + sqlite3GlobalConfig.bOpenUri = va_arg(ap, int); break; } @@ -180520,18 +173214,6 @@ SQLITE_API int 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 ) sqlite3GlobalConfig.mNoVisibleRowid = TF_NoVisibleRowid; - if( 1==*pVal ) sqlite3GlobalConfig.mNoVisibleRowid = 0; - *pVal = (sqlite3GlobalConfig.mNoVisibleRowid==0); -#else - *pVal = 0; -#endif - break; - } - default: { rc = SQLITE_ERROR; break; @@ -180723,10 +173405,6 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3 *db){ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ va_list ap; int rc; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif sqlite3_mutex_enter(db->mutex); va_start(ap, op); switch( op ){ @@ -180766,8 +173444,6 @@ SQLITE_API int sqlite3_db_config(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 */ @@ -181056,14 +173732,6 @@ static int sqlite3Close(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); - sqlite3_free(p); - } - /* Convert the connection into a zombie and then close it. */ db->eOpenState = SQLITE_STATE_ZOMBIE; @@ -181388,7 +174056,6 @@ SQLITE_PRIVATE const char *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; @@ -181481,9 +174148,9 @@ static int sqliteDefaultBusyCallback( void *ptr, /* Database connection */ int count /* Number of times table has been busy */ ){ -#if SQLITE_OS_WIN || !defined(HAVE_NANOSLEEP) || HAVE_NANOSLEEP +#if SQLITE_OS_WIN || HAVE_USLEEP /* This case is for systems that have support for sleeping for fractions of - ** a second. Examples: All windows systems, unix systems with nanosleep() */ + ** a second. Examples: All windows systems, unix systems with usleep() */ static const u8 delays[] = { 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 }; static const u8 totals[] = @@ -181618,9 +174285,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){ */ SQLITE_API void sqlite3_interrupt(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) - && (db==0 || db->eOpenState!=SQLITE_STATE_ZOMBIE) - ){ + if( !sqlite3SafetyCheckOk(db) && (db==0 || db->eOpenState!=SQLITE_STATE_ZOMBIE) ){ (void)SQLITE_MISUSE_BKPT; return; } @@ -181628,21 +174293,6 @@ SQLITE_API void sqlite3_interrupt(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 sqlite3_is_interrupted(sqlite3 *db){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !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 sqlite3_create_function(), except @@ -181681,13 +174331,13 @@ SQLITE_PRIVATE int sqlite3CreateFunc( assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC ); assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY ); extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY| - SQLITE_SUBTYPE|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE); + SQLITE_SUBTYPE|SQLITE_INNOCUOUS); 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; /* tag-20230109-1 */ + extraFlags ^= SQLITE_FUNC_UNSAFE; #ifndef SQLITE_OMIT_UTF16 @@ -181705,11 +174355,11 @@ SQLITE_PRIVATE int sqlite3CreateFunc( case SQLITE_ANY: { int rc; rc = sqlite3CreateFunc(db, zFunctionName, nArg, - (SQLITE_UTF8|extraFlags)^SQLITE_FUNC_UNSAFE, /* tag-20230109-1 */ + (SQLITE_UTF8|extraFlags)^SQLITE_FUNC_UNSAFE, pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor); if( rc==SQLITE_OK ){ rc = sqlite3CreateFunc(db, zFunctionName, nArg, - (SQLITE_UTF16LE|extraFlags)^SQLITE_FUNC_UNSAFE, /* tag-20230109-1*/ + (SQLITE_UTF16LE|extraFlags)^SQLITE_FUNC_UNSAFE, pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor); } if( rc!=SQLITE_OK ){ @@ -182138,12 +174788,6 @@ SQLITE_API void *sqlite3_preupdate_hook( void *pArg /* First callback argument */ ){ void *pRet; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( db==0 ){ - return 0; - } -#endif sqlite3_mutex_enter(db->mutex); pRet = db->pPreUpdateArg; db->xPreUpdateCallback = xCallback; @@ -182290,7 +174934,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2( if( eModeSQLITE_CHECKPOINT_TRUNCATE ){ /* EVIDENCE-OF: R-03996-12088 The M parameter must be a valid checkpoint ** mode: */ - return SQLITE_MISUSE_BKPT; + return SQLITE_MISUSE; } sqlite3_mutex_enter(db->mutex); @@ -182767,9 +175411,9 @@ SQLITE_PRIVATE int sqlite3ParseUri( assert( *pzErrMsg==0 ); - if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */ - || AtomicLoad(&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 */ + || 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 */ @@ -183127,7 +175771,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 encouraged to use +** and so that is the default. But developers are encouranged to use ** -DSQLITE_DQS=0 (best) or -DSQLITE_DQS=1 (second choice) if possible. */ #if !defined(SQLITE_DQS) @@ -183175,9 +175819,6 @@ static int openDatabase( #endif #if defined(SQLITE_DEFAULT_LEGACY_ALTER_TABLE) | SQLITE_LegacyAlter -#endif -#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) - | SQLITE_StmtScanStatus #endif ; sqlite3HashInit(&db->aCollSeq); @@ -183527,69 +176168,6 @@ SQLITE_API int sqlite3_collation_needed16( } #endif /* SQLITE_OMIT_UTF16 */ -/* -** Find existing client data. -*/ -SQLITE_API void *sqlite3_get_clientdata(sqlite3 *db, const char *zName){ - DbClientData *p; - sqlite3_mutex_enter(db->mutex); - for(p=db->pDbData; p; p=p->pNext){ - if( strcmp(p->zName, zName)==0 ){ - void *pResult = p->pData; - sqlite3_mutex_leave(db->mutex); - return pResult; - } - } - sqlite3_mutex_leave(db->mutex); - return 0; -} - -/* -** Add new client data to a database connection. -*/ -SQLITE_API int sqlite3_set_clientdata( - 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; - 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; - sqlite3_free(p); - sqlite3_mutex_leave(db->mutex); - return SQLITE_OK; - } - }else if( pData==0 ){ - sqlite3_mutex_leave(db->mutex); - return SQLITE_OK; - }else{ - size_t n = strlen(zName); - p = sqlite3_malloc64( sizeof(DbClientData)+n+1 ); - if( p==0 ){ - if( xDestructor ) xDestructor(pData); - 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; - 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 @@ -183725,7 +176303,7 @@ SQLITE_API int sqlite3_table_column_metadata( /* Find the column for which info is requested */ if( zColumnName==0 ){ - /* Query for existence of table only */ + /* Query for existance of table only */ }else{ for(iCol=0; iColnCol; iCol++){ pCol = &pTab->aCol[iCol]; @@ -183806,7 +176384,7 @@ SQLITE_API int sqlite3_sleep(int ms){ /* This function works in milliseconds, but the underlying OsSleep() ** API uses microseconds. Hence the 1000's. */ - rc = (sqlite3OsSleep(pVfs, ms<0 ? 0 : 1000*ms)/1000); + rc = (sqlite3OsSleep(pVfs, 1000*ms)/1000); return rc; } @@ -183939,28 +176517,6 @@ SQLITE_API int sqlite3_test_control(int op, ...){ } #endif - /* sqlite3_test_control(SQLITE_TESTCTRL_FK_NO_ACTION, 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: { - sqlite3 *db = va_arg(ap, sqlite3*); - int b = va_arg(ap, int); - if( b ){ - db->flags |= SQLITE_FkNoAction; - }else{ - db->flags &= ~SQLITE_FkNoAction; - } - break; - } - /* ** sqlite3_test_control(BITVEC_TEST, size, program) ** @@ -184067,12 +176623,10 @@ SQLITE_API int sqlite3_test_control(int op, ...){ sqlite3ShowSrcList(0); sqlite3ShowWith(0); sqlite3ShowUpsert(0); -#ifndef SQLITE_OMIT_TRIGGER sqlite3ShowTriggerStep(0); sqlite3ShowTriggerStepList(0); sqlite3ShowTrigger(0); sqlite3ShowTriggerList(0); -#endif #ifndef SQLITE_OMIT_WINDOWFUNC sqlite3ShowWindow(0); sqlite3ShowWinFunc(0); @@ -184189,7 +176743,7 @@ SQLITE_API int 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 demonstrate invariants on well-formed database files. + ** that demonstrat invariants on well-formed database files. */ case SQLITE_TESTCTRL_NEVER_CORRUPT: { sqlite3GlobalConfig.neverCorrupt = va_arg(ap, int); @@ -184343,7 +176897,7 @@ SQLITE_API int sqlite3_test_control(int op, ...){ ** ** op==0 Store the current sqlite3TreeTrace in *ptr ** op==1 Set sqlite3TreeTrace to the value *ptr - ** op==2 Store the current sqlite3WhereTrace in *ptr + ** op==3 Store the current sqlite3WhereTrace in *ptr ** op==3 Set sqlite3WhereTrace to the value *ptr */ case SQLITE_TESTCTRL_TRACEFLAGS: { @@ -184379,23 +176933,6 @@ SQLITE_API int sqlite3_test_control(int op, ...){ break; } -#if !defined(SQLITE_OMIT_WSD) - /* 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 ) sqlite3Config.bUseLongDouble = b>0; - rc = sqlite3Config.bUseLongDouble!=0; - break; - } -#endif - #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD) /* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue) @@ -184426,28 +176963,6 @@ SQLITE_API int sqlite3_test_control(int op, ...){ break; } #endif - - /* 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 = sqlite3Config.bJsonSelfcheck; - }else{ - sqlite3Config.bJsonSelfcheck = (u8)((*pOnOff)&0xff); - } -#endif - break; - } } va_end(ap); #endif /* SQLITE_UNTESTABLE */ @@ -184718,7 +177233,7 @@ SQLITE_API int sqlite3_snapshot_get( } /* -** Open a read-transaction on the snapshot identified by pSnapshot. +** Open a read-transaction on the snapshot idendified by pSnapshot. */ SQLITE_API int sqlite3_snapshot_open( sqlite3 *db, @@ -184825,7 +177340,7 @@ SQLITE_API int sqlite3_compileoption_used(const char *zOptName){ int nOpt; const char **azCompileOpt; -#ifdef SQLITE_ENABLE_API_ARMOR +#if SQLITE_ENABLE_API_ARMOR if( zOptName==0 ){ (void)SQLITE_MISUSE_BKPT; return 0; @@ -185020,9 +177535,6 @@ SQLITE_API int sqlite3_unlock_notify( ){ int rc = SQLITE_OK; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif sqlite3_mutex_enter(db->mutex); enterMutex(); @@ -186044,7 +178556,6 @@ struct Fts3Table { int nPgsz; /* Page size for host database */ char *zSegmentsTbl; /* Name of %_segments table */ sqlite3_blob *pSegments; /* Blob handle open on %_segments table */ - int iSavepoint; /* ** The following array of hash tables is used to buffer pending index @@ -186430,10 +178941,6 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int); SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int); #endif -SQLITE_PRIVATE int sqlite3Fts3ExprIterate(Fts3Expr*, int (*x)(Fts3Expr*,int,void*), void*); - -SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk); - #endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */ #endif /* _FTSINT_H */ @@ -186790,7 +179297,6 @@ static void fts3DeclareVtab(int *pRc, Fts3Table *p){ zLanguageid = (p->zLanguageid ? p->zLanguageid : "__langid"); sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); - sqlite3_vtab_config(p->db, SQLITE_VTAB_INNOCUOUS); /* Create a list of user columns for the virtual table */ zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]); @@ -190040,8 +182546,6 @@ static int fts3RenameMethod( rc = sqlite3Fts3PendingTermsFlush(p); } - p->bIgnoreSavepoint = 1; - if( p->zContentTbl==0 ){ fts3DbExec(&rc, db, "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';", @@ -190069,8 +182573,6 @@ static int fts3RenameMethod( "ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';", p->zDb, p->zName, zName ); - - p->bIgnoreSavepoint = 0; return rc; } @@ -190081,28 +182583,12 @@ static int fts3RenameMethod( */ static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ int rc = SQLITE_OK; - 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 = sqlite3_mprintf("INSERT INTO %Q.%Q(%Q) VALUES('flush')", - pTab->zDb, pTab->zName, pTab->zName - ); - if( zSql ){ - pTab->bIgnoreSavepoint = 1; - rc = sqlite3_exec(pTab->db, zSql, 0, 0, 0); - pTab->bIgnoreSavepoint = 0; - sqlite3_free(zSql); - }else{ - rc = SQLITE_NOMEM; - } - } - if( rc==SQLITE_OK ){ - pTab->iSavepoint = iSavepoint+1; - } + 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); } return rc; } @@ -190113,11 +182599,12 @@ static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ ** This is a no-op. */ static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ - Fts3Table *pTab = (Fts3Table*)pVtab; - assert( pTab->inTransaction ); - assert( pTab->mxSavepoint >= iSavepoint ); - TESTONLY( pTab->mxSavepoint = iSavepoint-1 ); - pTab->iSavepoint = iSavepoint; + TESTONLY( Fts3Table *p = (Fts3Table*)pVtab ); + UNUSED_PARAMETER(iSavepoint); + UNUSED_PARAMETER(pVtab); + assert( p->inTransaction ); + assert( p->mxSavepoint >= iSavepoint ); + TESTONLY( p->mxSavepoint = iSavepoint-1 ); return SQLITE_OK; } @@ -190127,13 +182614,11 @@ static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ ** Discard the contents of the pending terms table. */ static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ - Fts3Table *pTab = (Fts3Table*)pVtab; + Fts3Table *p = (Fts3Table*)pVtab; UNUSED_PARAMETER(iSavepoint); - assert( pTab->inTransaction ); - TESTONLY( pTab->mxSavepoint = iSavepoint ); - if( (iSavepoint+1)<=pTab->iSavepoint ){ - sqlite3Fts3PendingTermsClear(pTab); - } + assert( p->inTransaction ); + TESTONLY( p->mxSavepoint = iSavepoint ); + sqlite3Fts3PendingTermsClear(p); return SQLITE_OK; } @@ -190152,42 +182637,8 @@ static int fts3ShadowName(const char *zName){ return 0; } -/* -** Implementation of the xIntegrity() method on the FTS3/FTS4 virtual -** table. -*/ -static int fts3IntegrityMethod( - 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 = sqlite3Fts3IntegrityCheck(p, &bOk); - assert( rc!=SQLITE_CORRUPT_VTAB ); - if( rc==SQLITE_ERROR || (rc&0xFF)==SQLITE_CORRUPT ){ - *pzErr = sqlite3_mprintf("unable to validate the inverted index for" - " FTS%d table %s.%s: %s", - p->bFts4 ? 4 : 3, zSchema, zTabname, sqlite3_errstr(rc)); - if( *pzErr ) rc = SQLITE_OK; - }else if( rc==SQLITE_OK && bOk==0 ){ - *pzErr = sqlite3_mprintf("malformed inverted index for FTS%d table %s.%s", - p->bFts4 ? 4 : 3, zSchema, zTabname); - if( *pzErr==0 ) rc = SQLITE_NOMEM; - } - sqlite3Fts3SegmentsClose(p); - return rc; -} - - - static const sqlite3_module fts3Module = { - /* iVersion */ 4, + /* iVersion */ 3, /* xCreate */ fts3CreateMethod, /* xConnect */ fts3ConnectMethod, /* xBestIndex */ fts3BestIndexMethod, @@ -190211,7 +182662,6 @@ static const sqlite3_module fts3Module = { /* xRelease */ fts3ReleaseMethod, /* xRollbackTo */ fts3RollbackToMethod, /* xShadowName */ fts3ShadowName, - /* xIntegrity */ fts3IntegrityMethod, }; /* @@ -191494,8 +183944,9 @@ static void fts3EvalNextRow( Fts3Expr *pExpr, /* Expr. to advance to next matching row */ int *pRc /* IN/OUT: Error code */ ){ - if( *pRc==SQLITE_OK && pExpr->bEof==0 ){ + if( *pRc==SQLITE_OK ){ int bDescDoclist = pCsr->bDesc; /* Used by DOCID_CMP() macro */ + assert( pExpr->bEof==0 ); pExpr->bStart = 1; switch( pExpr->eType ){ @@ -191971,22 +184422,6 @@ static void fts3EvalUpdateCounts(Fts3Expr *pExpr, int nCol){ } } -/* -** This is an 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 *)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. ** @@ -192008,6 +184443,7 @@ 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 */ sqlite3_int64 iPrevId = pCsr->iPrevId; sqlite3_int64 iDocid; @@ -192015,9 +184451,7 @@ static int fts3EvalGatherStats( /* Find the root of the NEAR expression */ pRoot = pExpr; - while( pRoot->pParent - && (pRoot->pParent->eType==FTSQUERY_NEAR || pRoot->bDeferred) - ){ + while( pRoot->pParent && pRoot->pParent->eType==FTSQUERY_NEAR ){ pRoot = pRoot->pParent; } iDocid = pRoot->iDocid; @@ -192025,8 +184459,14 @@ static int fts3EvalGatherStats( assert( pRoot->bStart ); /* Allocate space for the aMSI[] array of each FTSQUERY_PHRASE node */ - rc = sqlite3Fts3ExprIterate(pRoot, fts3AllocateMSI, (void*)pTab); - if( rc!=SQLITE_OK ) return rc; + for(p=pRoot; p; p=p->pLeft){ + Fts3Expr *pE = (p->eType==FTSQUERY_PHRASE?p:p->pRight); + assert( pE->aMI==0 ); + pE->aMI = (u32 *)sqlite3_malloc64(pTab->nColumn * 3 * sizeof(u32)); + if( !pE->aMI ) return SQLITE_NOMEM; + memset(pE->aMI, 0, pTab->nColumn * 3 * sizeof(u32)); + } + fts3EvalRestart(pCsr, pRoot, &rc); while( pCsr->isEof==0 && rc==SQLITE_OK ){ @@ -192182,7 +184622,6 @@ SQLITE_PRIVATE int 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, @@ -192197,30 +184636,25 @@ SQLITE_PRIVATE int 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 = pRun->bEof; - fts3EvalRestart(pCsr, pRun, &rc); - while( rc==SQLITE_OK && !pRun->bEof ){ - fts3EvalNextRow(pCsr, pRun, &rc); - if( bEofSave==0 && pRun->iDocid==iDocid ) break; + 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; } assert( rc!=SQLITE_OK || pPhrase->bIncr==0 ); - if( rc==SQLITE_OK && pRun->bEof!=bEofSave ){ + if( rc==SQLITE_OK && pNear->bEof!=bEofSave ){ rc = FTS_CORRUPT_VTAB; } } if( bTreeEof ){ - while( rc==SQLITE_OK && !pRun->bEof ){ - fts3EvalNextRow(pCsr, pRun, &rc); + while( rc==SQLITE_OK && !pNear->bEof ){ + fts3EvalNextRow(pCsr, pNear, &rc); } } if( rc!=SQLITE_OK ) return rc; @@ -192887,8 +185321,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - 0, /* xShadowName */ - 0 /* xIntegrity */ + 0 /* xShadowName */ }; int rc; /* Return code */ @@ -196454,8 +188887,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash, void(*xDestr 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - 0, /* xShadowName */ - 0 /* xIntegrity */ + 0 /* xShadowName */ }; int rc; /* Return code */ @@ -199138,18 +191570,16 @@ static int fts3MsrBufferData( char *pList, i64 nList ){ - if( (nList+FTS3_NODE_PADDING)>pMsr->nBuffer ){ + if( nList>pMsr->nBuffer ){ char *pNew; - int nNew = nList*2 + FTS3_NODE_PADDING; - pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, nNew); + pMsr->nBuffer = nList*2; + pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, pMsr->nBuffer); 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; } @@ -199796,6 +192226,7 @@ SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){ rc = fts3SegmentMerge(p, p->iPrevLangid, i, FTS3_SEGCURSOR_PENDING); if( rc==SQLITE_DONE ) rc = SQLITE_OK; } + sqlite3Fts3PendingTermsClear(p); /* Determine the auto-incr-merge setting if unknown. If enabled, ** estimate the number of leaf blocks of content to be written @@ -199817,10 +192248,6 @@ SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){ rc = sqlite3_reset(pStmt); } } - - if( rc==SQLITE_OK ){ - sqlite3Fts3PendingTermsClear(p); - } return rc; } @@ -200452,8 +192879,6 @@ 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; @@ -200510,13 +192935,9 @@ static int fts3IncrmergeAppend( nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist; /* If the current block is not empty, and if adding this term/doclist - ** to the current block would make it larger than Fts3Table.nNodeSize bytes, - ** 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) - ){ + ** to the current block would make it larger than Fts3Table.nNodeSize + ** bytes, write this block out to the database. */ + if( pLeaf->block.n>0 && (pLeaf->block.n + nSpace)>p->nNodeSize ){ rc = fts3WriteSegment(p, pLeaf->iBlock, pLeaf->block.a, pLeaf->block.n); pWriter->nWork++; @@ -200827,7 +193248,6 @@ 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){ @@ -200848,7 +193268,7 @@ static int fts3IncrmergeLoad( rc = 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; @@ -201698,7 +194118,7 @@ static u64 fts3ChecksumIndex( int rc; u64 cksum = 0; - if( *pRc ) return 0; + assert( *pRc==SQLITE_OK ); memset(&filter, 0, sizeof(filter)); memset(&csr, 0, sizeof(csr)); @@ -201765,7 +194185,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. */ -SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk){ +static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){ int rc = SQLITE_OK; /* Return code */ u64 cksum1 = 0; /* Checksum based on FTS index contents */ u64 cksum2 = 0; /* Checksum based on %_content contents */ @@ -201843,12 +194263,7 @@ SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk){ sqlite3_finalize(pStmt); } - if( rc==SQLITE_CORRUPT_VTAB ){ - rc = SQLITE_OK; - *pbOk = 0; - }else{ - *pbOk = (rc==SQLITE_OK && cksum1==cksum2); - } + *pbOk = (cksum1==cksum2); return rc; } @@ -201888,7 +194303,7 @@ static int fts3DoIntegrityCheck( ){ int rc; int bOk = 0; - rc = sqlite3Fts3IntegrityCheck(p, &bOk); + rc = fts3IntegrityCheck(p, &bOk); if( rc==SQLITE_OK && bOk==0 ) rc = FTS_CORRUPT_VTAB; return rc; } @@ -201918,11 +194333,8 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){ rc = fts3DoIncrmerge(p, &zVal[6]); }else if( nVal>10 && 0==sqlite3_strnicmp(zVal, "automerge=", 10) ){ rc = fts3DoAutoincrmerge(p, &zVal[10]); - }else if( nVal==5 && 0==sqlite3_strnicmp(zVal, "flush", 5) ){ - rc = sqlite3Fts3PendingTermsFlush(p); - } #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) - else{ + }else{ int v; if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){ v = atoi(&zVal[9]); @@ -201940,8 +194352,8 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){ if( v>=4 && v<=FTS3_MERGE_COUNT && (v&1)==0 ) p->nMergeCount = v; rc = SQLITE_OK; } - } #endif + } return rc; } @@ -202349,7 +194761,7 @@ typedef sqlite3_int64 i64; /* -** Used as an sqlite3Fts3ExprIterate() context when loading phrase doclists to +** Used as an fts3ExprIterate() context when loading phrase doclists to ** Fts3Expr.aDoclist[]/nDoclist. */ typedef struct LoadDoclistCtx LoadDoclistCtx; @@ -202393,7 +194805,7 @@ struct SnippetFragment { }; /* -** This type is used as an sqlite3Fts3ExprIterate() context object while +** This type is used as an fts3ExprIterate() context object while ** accumulating the data returned by the matchinfo() function. */ typedef struct MatchInfo MatchInfo; @@ -202552,7 +194964,7 @@ static void fts3GetDeltaPosition(char **pp, i64 *piPos){ } /* -** Helper function for sqlite3Fts3ExprIterate() (see below). +** Helper function for fts3ExprIterate() (see below). */ static int fts3ExprIterate2( Fts3Expr *pExpr, /* Expression to iterate phrases of */ @@ -202586,7 +194998,7 @@ static int fts3ExprIterate2( ** Otherwise, SQLITE_OK is returned after a callback has been made for ** all eligible phrase nodes. */ -SQLITE_PRIVATE int sqlite3Fts3ExprIterate( +static int fts3ExprIterate( 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 */ @@ -202595,9 +195007,10 @@ SQLITE_PRIVATE int sqlite3Fts3ExprIterate( return fts3ExprIterate2(pExpr, &iPhrase, x, pCtx); } + /* -** This is an sqlite3Fts3ExprIterate() callback used while loading the -** doclists for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also +** This is an fts3ExprIterate() 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){ @@ -202629,9 +195042,9 @@ static int fts3ExprLoadDoclists( int *pnToken /* OUT: Number of tokens in query */ ){ int rc; /* Return Code */ - LoadDoclistCtx sCtx = {0,0,0}; /* Context for sqlite3Fts3ExprIterate() */ + LoadDoclistCtx sCtx = {0,0,0}; /* Context for fts3ExprIterate() */ sCtx.pCsr = pCsr; - rc = sqlite3Fts3ExprIterate(pCsr->pExpr,fts3ExprLoadDoclistsCb,(void*)&sCtx); + rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb, (void *)&sCtx); if( pnPhrase ) *pnPhrase = sCtx.nPhrase; if( pnToken ) *pnToken = sCtx.nToken; return rc; @@ -202644,7 +195057,7 @@ static int fts3ExprPhraseCountCb(Fts3Expr *pExpr, int iPhrase, void *ctx){ } static int fts3ExprPhraseCount(Fts3Expr *pExpr){ int nPhrase = 0; - (void)sqlite3Fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase); + (void)fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase); return nPhrase; } @@ -202754,7 +195167,7 @@ static void fts3SnippetDetails( } mCover |= mPhrase; - for(j=0; jnToken && jnSnippet; j++){ + for(j=0; jnToken; j++){ mHighlight |= (mPos>>j); } @@ -202772,9 +195185,8 @@ static void fts3SnippetDetails( } /* -** This function is an sqlite3Fts3ExprIterate() callback used by -** fts3BestSnippet(). Each invocation populates an element of the -** SnippetIter.aPhrase[] array. +** This function is an fts3ExprIterate() 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; @@ -202864,9 +195276,7 @@ static int fts3BestSnippet( sIter.nSnippet = nSnippet; sIter.nPhrase = nList; sIter.iCurrent = -1; - rc = sqlite3Fts3ExprIterate( - pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter - ); + rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter); if( rc==SQLITE_OK ){ /* Set the *pmSeen output variable. */ @@ -203227,10 +195637,10 @@ static int fts3ExprLHitGather( } /* -** sqlite3Fts3ExprIterate() callback used to collect the "global" matchinfo -** stats for a single query. +** fts3ExprIterate() callback used to collect the "global" matchinfo stats +** for a single query. ** -** sqlite3Fts3ExprIterate() callback to load the 'global' elements of a +** fts3ExprIterate() callback to load the 'global' elements of a ** FTS3_MATCHINFO_HITS matchinfo array. The global stats are those elements ** of the matchinfo array that are constant for all rows returned by the ** current query. @@ -203265,7 +195675,7 @@ static int fts3ExprGlobalHitsCb( } /* -** sqlite3Fts3ExprIterate() callback used to collect the "local" part of the +** fts3ExprIterate() callback used to collect the "local" part of the ** FTS3_MATCHINFO_HITS array. The local stats are those elements of the ** array that are different for each row returned by the query. */ @@ -203461,7 +195871,7 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){ **/ aIter = sqlite3Fts3MallocZero(sizeof(LcsIterator) * pCsr->nPhrase); if( !aIter ) return SQLITE_NOMEM; - (void)sqlite3Fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter); + (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter); for(i=0; inPhrase; i++){ LcsIterator *pIter = &aIter[i]; @@ -203638,11 +196048,11 @@ static int fts3MatchinfoValues( rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc,0,0); if( rc!=SQLITE_OK ) break; } - rc = sqlite3Fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo); + rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo); sqlite3Fts3EvalTestDeferred(pCsr, &rc); if( rc!=SQLITE_OK ) break; } - (void)sqlite3Fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo); + (void)fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo); break; } } @@ -203865,7 +196275,7 @@ struct TermOffsetCtx { }; /* -** This function is an sqlite3Fts3ExprIterate() callback used by sqlite3Fts3Offsets(). +** This function is an fts3ExprIterate() callback used by sqlite3Fts3Offsets(). */ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){ TermOffsetCtx *p = (TermOffsetCtx *)ctx; @@ -203947,9 +196357,7 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets( */ sCtx.iCol = iCol; sCtx.iTerm = 0; - rc = sqlite3Fts3ExprIterate( - pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx - ); + rc = fts3ExprIterate(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 @@ -204862,242 +197270,59 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){ ** ****************************************************************************** ** -** SQLite JSON functions. +** This 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. ** -** 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. +** 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.) */ #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 text-JSON parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). +** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). */ static const char jsonIsSpace[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; -#define 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 + 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 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 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 { - 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 { sqlite3_context *pCtx; /* Function context - put error messages here */ @@ -205105,227 +197330,89 @@ 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 eErr; /* True if an error has been encountered */ + u8 bErr; /* True if an error has been encountered */ char zSpace[100]; /* Initial static space */ }; -/* 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 sqlite3_result */ - -/* The "subtype" set for text JSON values passed through using -** sqlite3_result_subtype() and sqlite3_value_subtype(). +/* JSON type values */ +#define JSON_NULL 0 +#define JSON_TRUE 1 +#define JSON_FALSE 2 +#define JSON_INT 3 +#define JSON_REAL 4 +#define JSON_STRING 5 +#define JSON_ARRAY 6 +#define JSON_OBJECT 7 + +/* The "subtype" set for JSON values */ #define JSON_SUBTYPE 74 /* Ascii for "J" */ /* -** Bit values for the flags passed into various SQL function implementations -** via the sqlite3_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() */ -#define JSON_BLOB 0x08 /* Use the BLOB output format */ - - -/* 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. +** Names of the various JSON types: */ -struct JsonParse { - 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 */ - sqlite3 *db; /* The database connection to which this object belongs */ - int nJson; /* Length of the zJson string in bytes */ - 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 */ +static const char * const jsonType[] = { + "null", "true", "false", "integer", "real", "text", "array", "object" }; -/* 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 1000 is far deeper than any sane JSON -** should go. Historical note: This limit was 2000 prior to version 3.42.0 +/* Bit values for the JsonNode.jnFlag field */ -#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 */ +#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 */ -/************************************************************************** -** Forward references -**************************************************************************/ -static void jsonReturnStringAsBlob(JsonString*); -static int jsonFuncArgMightBeBinary(sqlite3_value *pJson); -static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*); -static void jsonReturnParse(sqlite3_context*,JsonParse*); -static JsonParse *jsonParseFuncArg(sqlite3_context*,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. +/* A single node of parsed JSON */ -static void jsonCacheDelete(JsonCache *p){ - int i; - for(i=0; inUsed; i++){ - jsonParseFree(p->a[i]); - } - sqlite3DbFree(p->db, p); -} -static void jsonCacheDeleteGeneric(void *p){ - jsonCacheDelete((JsonCache*)p); -} +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; +}; -/* -** 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. +/* A completely parsed JSON string */ -static int jsonCacheInsert( - 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 = sqlite3_get_auxdata(ctx, JSON_CACHE_ID); - if( p==0 ){ - sqlite3 *db = sqlite3_context_db_handle(ctx); - p = sqlite3DbMallocZero(db, sizeof(*p)); - if( p==0 ) return SQLITE_NOMEM; - p->db = db; - sqlite3_set_auxdata(ctx, JSON_CACHE_ID, p, jsonCacheDeleteGeneric); - p = 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; -} +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 */ + int nJson; /* Length of the zJson string in bytes */ + u32 iHold; /* Replace cache line with the lowest iHold value */ +}; /* -** 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. +** Maximum nesting depth of JSON for this implementation. ** -** 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. +** 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. */ -static JsonParse *jsonCacheSearch( - sqlite3_context *ctx, /* The SQL statement context holding the cache */ - sqlite3_value *pArg /* Function argument containing SQL text */ -){ - JsonCache *p; - int i; - const char *zJson; - int nJson; - - if( sqlite3_value_type(pArg)!=SQLITE_TEXT ){ - return 0; - } - zJson = (const char*)sqlite3_value_text(pArg); - if( zJson==0 ) return 0; - nJson = sqlite3_value_bytes(pArg); - - p = sqlite3_get_auxdata(ctx, JSON_CACHE_ID); - if( p==0 ){ - return 0; - } - for(i=0; inUsed; i++){ - if( p->a[i]->zJson==zJson ) break; - } - if( i>=p->nUsed ){ - for(i=0; inUsed; i++){ - if( p->a[i]->nJson!=nJson ) continue; - if( memcmp(p->a[i]->zJson, zJson, nJson)==0 ) break; - } - } - if( inUsed ){ - if( inUsed-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; - } -} +#define JSON_MAX_DEPTH 2000 /************************************************************************** ** Utility routines for dealing with JsonString objects **************************************************************************/ -/* Turn uninitialized bulk memory into a valid JsonString object -** holding a zero-length string. +/* Set the JsonString object to an empty string */ -static void jsonStringZero(JsonString *p){ +static void jsonZero(JsonString *p){ p->zBuf = p->zSpace; p->nAlloc = sizeof(p->zSpace); p->nUsed = 0; @@ -205334,51 +197421,53 @@ static void jsonStringZero(JsonString *p){ /* Initialize the JsonString object */ -static void jsonStringInit(JsonString *p, sqlite3_context *pCtx){ +static void jsonInit(JsonString *p, sqlite3_context *pCtx){ p->pCtx = pCtx; - p->eErr = 0; - jsonStringZero(p); + p->bErr = 0; + jsonZero(p); } + /* Free all allocated memory and reset the JsonString object back to its ** initial state. */ -static void jsonStringReset(JsonString *p){ - if( !p->bStatic ) sqlite3RCStrUnref(p->zBuf); - jsonStringZero(p); +static void jsonReset(JsonString *p){ + if( !p->bStatic ) sqlite3_free(p->zBuf); + jsonZero(p); } + /* Report an out-of-memory (OOM) condition */ -static void jsonStringOom(JsonString *p){ - p->eErr |= JSTRING_OOM; - if( p->pCtx ) sqlite3_result_error_nomem(p->pCtx); - jsonStringReset(p); +static void jsonOom(JsonString *p){ + p->bErr = 1; + sqlite3_result_error_nomem(p->pCtx); + jsonReset(p); } /* Enlarge pJson->zBuf so that it can hold at least N more bytes. ** Return zero on success. Return non-zero on an OOM error */ -static int jsonStringGrow(JsonString *p, u32 N){ +static int jsonGrow(JsonString *p, u32 N){ u64 nTotal = NnAlloc ? p->nAlloc*2 : p->nAlloc+N+10; char *zNew; if( p->bStatic ){ - if( p->eErr ) return 1; - zNew = sqlite3RCStrNew(nTotal); + if( p->bErr ) return 1; + zNew = sqlite3_malloc64(nTotal); if( zNew==0 ){ - jsonStringOom(p); + jsonOom(p); return SQLITE_NOMEM; } memcpy(zNew, p->zBuf, (size_t)p->nUsed); p->zBuf = zNew; p->bStatic = 0; }else{ - p->zBuf = sqlite3RCStrResize(p->zBuf, nTotal); - if( p->zBuf==0 ){ - p->eErr |= JSTRING_OOM; - jsonStringZero(p); + zNew = sqlite3_realloc64(p->zBuf, nTotal); + if( zNew==0 ){ + jsonOom(p); return SQLITE_NOMEM; } + p->zBuf = zNew; } p->nAlloc = nTotal; return SQLITE_OK; @@ -205386,40 +197475,18 @@ static int jsonStringGrow(JsonString *p, u32 N){ /* Append N bytes from zIn onto the end of the JsonString string. */ -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; - } + if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return; + memcpy(p->zBuf+p->nUsed, zIn, N); + p->nUsed += N; } /* Append formatted text (not to exceed N bytes) to the JsonString. */ static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){ va_list ap; - if( (p->nUsed + N >= p->nAlloc) && jsonStringGrow(p, N) ) return; + if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return; va_start(ap, zFormat); sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap); va_end(ap); @@ -205428,37 +197495,9 @@ static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){ /* Append a single character */ -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; + if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return; + p->zBuf[p->nUsed++] = c; } /* Append a comma separator to the output buffer, if the previous @@ -205468,137 +197507,68 @@ static void jsonAppendSeparator(JsonString *p){ char c; if( p->nUsed==0 ) return; c = p->zBuf[p->nUsed-1]; - 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 && cnUsed+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; - } + if( c!='[' && c!='{' ) jsonAppendChar(p, ','); } /* Append the N-byte string in zIn to the end of the JsonString string -** under construction. Enclose the string in double-quotes ("...") and -** escape any double-quotes or backslash characters contained within the +** under construction. Enclose the string in "..." 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 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; + u32 i; + if( zIn==0 || ((N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0) ) return; p->zBuf[p->nUsed++] = '"'; - while( 1 /*exit-by-break*/ ){ - k = 0; - /* The following while() is the 4-way unwound equivalent of - ** - ** while( k=N ){ - while( 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]; + for(i=0; inUsed+N+3 > p->nAlloc) && jsonStringGrow(p,N+3)!=0 ) return; + json_simple_escape: + if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return; p->zBuf[p->nUsed++] = '\\'; - 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); + }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]; } - z++; - N--; + p->zBuf[p->nUsed++] = c; } p->zBuf[p->nUsed++] = '"'; assert( p->nUsednAlloc ); } /* -** Append an sqlite3_value (such as a function parameter) to the JSON -** string under construction in p. +** Append a function parameter value to the JSON string under +** construction. */ -static void jsonAppendSqlValue( +static void jsonAppendValue( JsonString *p, /* Append to this JSON string */ sqlite3_value *pValue /* Value to append */ ){ switch( sqlite3_value_type(pValue) ){ case SQLITE_NULL: { - jsonAppendRawNZ(p, "null", 4); + jsonAppendRaw(p, "null", 4); break; } + case SQLITE_INTEGER: case SQLITE_FLOAT: { - jsonPrintf(100, p, "%!0.15g", sqlite3_value_double(pValue)); - break; - } - case SQLITE_INTEGER: { const char *z = (const char*)sqlite3_value_text(pValue); u32 n = (u32)sqlite3_value_bytes(pValue); jsonAppendRaw(p, z, n); @@ -205615,127 +197585,184 @@ static void jsonAppendSqlValue( break; } default: { - if( jsonFuncArgMightBeBinary(pValue) ){ - JsonParse px; - memset(&px, 0, sizeof(px)); - px.aBlob = (u8*)sqlite3_value_blob(pValue); - px.nBlob = sqlite3_value_bytes(pValue); - jsonTranslateBlobToText(&px, 0, p); - }else if( p->eErr==0 ){ + if( p->bErr==0 ){ sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); - p->eErr = JSTRING_ERR; - jsonStringReset(p); + p->bErr = 2; + jsonReset(p); } break; } } } -/* 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. + +/* Make the JSON in p the result of the SQL function. */ -static void jsonReturnString( - JsonString *p, /* String to return */ - JsonParse *pParse, /* JSONB source or NULL */ - 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(sqlite3_user_data(p->pCtx)); - if( flags & JSON_BLOB ){ - jsonReturnStringAsBlob(p); - }else if( p->bStatic ){ - 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 = sqlite3RCStrRef(p->zBuf); - pParse->nJson = p->nUsed; - pParse->bJsonIsRCStr = 1; - rc = jsonCacheInsert(ctx, pParse); - if( rc==SQLITE_NOMEM ){ - sqlite3_result_error_nomem(ctx); - jsonStringReset(p); - return; - } - } - sqlite3_result_text64(p->pCtx, sqlite3RCStrRef(p->zBuf), p->nUsed, - sqlite3RCStrUnref, - SQLITE_UTF8); - }else{ - sqlite3_result_error_nomem(p->pCtx); - } - }else if( p->eErr & JSTRING_OOM ){ - sqlite3_result_error_nomem(p->pCtx); - }else if( p->eErr & JSTRING_MALFORMED ){ - sqlite3_result_error(p->pCtx, "malformed JSON", -1); +static void jsonResult(JsonString *p){ + if( p->bErr==0 ){ + sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, + p->bStatic ? SQLITE_TRANSIENT : sqlite3_free, + SQLITE_UTF8); + jsonZero(p); } - jsonStringReset(p); + assert( p->bStatic ); } /************************************************************************** -** Utility routines for dealing with JsonParse objects +** Utility routines for dealing with JsonNode and JsonParse objects **************************************************************************/ +/* +** Return the number of consecutive JsonNode slots need to represent +** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and +** OBJECT types, the number might be larger. +** +** Appended elements are not counted. The value returned is the number +** by which the JsonNode counter should increment in order to go to the +** next peer value. +*/ +static u32 jsonNodeSize(JsonNode *pNode){ + return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1; +} + /* ** Reclaim all memory allocated by a JsonParse object. But do not ** delete the JsonParse object itself. */ static void jsonParseReset(JsonParse *pParse){ - assert( pParse->nJPRef<=1 ); - if( pParse->bJsonIsRCStr ){ - sqlite3RCStrUnref(pParse->zJson); - pParse->zJson = 0; - pParse->nJson = 0; - pParse->bJsonIsRCStr = 0; - } - if( pParse->nBlobAlloc ){ - sqlite3DbFree(pParse->db, pParse->aBlob); - pParse->aBlob = 0; - pParse->nBlob = 0; - pParse->nBlobAlloc = 0; - } + sqlite3_free(pParse->aNode); + pParse->aNode = 0; + pParse->nNode = 0; + pParse->nAlloc = 0; + sqlite3_free(pParse->aUp); + pParse->aUp = 0; } /* -** Decrement the reference count on the JsonParse object. When the -** count reaches zero, free the object. +** Free a JsonParse object that was obtained from sqlite3_malloc(). */ static void jsonParseFree(JsonParse *pParse){ - if( pParse ){ - if( pParse->nJPRef>1 ){ - pParse->nJPRef--; - }else{ - jsonParseReset(pParse); - sqlite3DbFree(pParse->db, pParse); + jsonParseReset(pParse); + 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 */ + 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; } } } -/************************************************************************** -** Utility routines for the JSON text parser -**************************************************************************/ +/* +** Return a JsonNode and all its descendents as a JSON string. +*/ +static void jsonReturnJson( + JsonNode *pNode, /* Node to return */ + sqlite3_context *pCtx, /* Return value for this function */ + sqlite3_value **aReplace /* Array of replacement values */ +){ + JsonString s; + jsonInit(&s, pCtx); + jsonRenderNode(pNode, &s, aReplace); + jsonResult(&s); + sqlite3_result_subtype(pCtx, JSON_SUBTYPE); +} /* ** Translate a single byte of Hex into an integer. -** This routine only gives a correct answer if h really is a valid hexadecimal -** character: 0..9a..fA..F. But unlike sqlite3HexToInt(), it does not -** assert() if the digit is not hex. +** This routine only works if h really is a valid hexadecimal +** character: 0..9a..fA..F */ static u8 jsonHexToInt(int h){ -#ifdef SQLITE_ASCII - h += 9*(1&(h>>6)); -#endif + assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') ); #ifdef SQLITE_EBCDIC h += 9*(1&~(h>>4)); +#else + h += 9*(1&(h>>6)); #endif return (u8)(h & 0xf); } @@ -205745,6 +197772,10 @@ static u8 jsonHexToInt(int h){ */ static u32 jsonHexToInt4(const char *z){ u32 v; + assert( sqlite3Isxdigit(z[0]) ); + assert( sqlite3Isxdigit(z[1]) ); + assert( sqlite3Isxdigit(z[2]) ); + assert( sqlite3Isxdigit(z[3]) ); v = (jsonHexToInt(z[0])<<12) + (jsonHexToInt(z[1])<<8) + (jsonHexToInt(z[2])<<4) @@ -205753,1108 +197784,420 @@ static u32 jsonHexToInt4(const char *z){ } /* -** Return true if z[] begins with 2 (or more) hexadecimal digits +** Make the JsonNode the return value of the function. */ -static int jsonIs2Hex(const char *z){ - return sqlite3Isxdigit(z[0]) && 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; +static void jsonReturn( + JsonNode *pNode, /* Node to return */ + sqlite3_context *pCtx, /* Return value for this function */ + sqlite3_value **aReplace /* Array of replacement values */ +){ + switch( pNode->eType ){ + default: { + assert( pNode->eType==JSON_NULL ); + sqlite3_result_null(pCtx); + break; + } + case JSON_TRUE: { + sqlite3_result_int(pCtx, 1); + break; + } + case JSON_FALSE: { + sqlite3_result_int(pCtx, 0); + break; + } + case JSON_INT: { + sqlite3_int64 i = 0; + const char *z; + 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]=='-' ){ + sqlite3_result_int64(pCtx, SMALLEST_INT64); + goto int_done; + }else{ + goto int_as_real; } } - n = j; - if( z[n] ) n++; - break; } - goto whitespace_done; + i = i*10 + v; } - case 0xc2: { - if( z[n+1]==0xa0 ){ - n += 2; - break; - } - goto whitespace_done; - } - case 0xe1: { - if( z[n+1]==0x9a && z[n+2]==0x80 ){ - n += 3; + if( pNode->u.zJContent[0]=='-' ){ i = -i; } + 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; + sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8); +#else + assert( pNode->eU==1 ); + r = strtod(pNode->u.zJContent, 0); +#endif + sqlite3_result_double(pCtx, r); + break; + } + case JSON_STRING: { +#if 0 /* Never happens because JNODE_RAW is only set by json_set(), + ** json_insert() and json_replace() and those routines do not + ** call jsonReturn() */ + if( pNode->jnFlags & JNODE_RAW ){ + assert( pNode->eU==1 ); + 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 ); + 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 = sqlite3_malloc( n+1 ); + if( zOut==0 ){ + sqlite3_result_error_nomem(pCtx); 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; + for(i=1, j=0; i>6)); + zOut[j++] = 0x80 | (v&0x3f); + }else{ + u32 vlo; + if( (v&0xfc00)==0xd800 + && i>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; + } } - }else if( z[n+1]==0x81 && z[n+2]==0x9f ){ - n += 3; - break; - } - 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; + zOut[j] = 0; + sqlite3_result_text(pCtx, zOut, j, sqlite3_free); } + break; + } + case JSON_ARRAY: + case JSON_OBJECT: { + jsonReturnJson(pNode, pCtx, aReplace); + break; } } - whitespace_done: - return n; } -/* -** Extra floating-point literals to allow in JSON. -*/ -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" }, -}; - +/* Forward reference */ +static int jsonParseAddNode(JsonParse*,u32,u32,const char*); /* -** Report the wrong number of arguments for json_insert(), json_replace() -** or json_set(). +** A macro to hint to the compiler that a function should not be +** inlined. */ -static void jsonWrongNumArgs( - sqlite3_context *pCtx, - const char *zFuncName -){ - char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments", - zFuncName); - sqlite3_result_error(pCtx, zMsg, -1); - sqlite3_free(zMsg); -} +#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 -/**************************************************************************** -** 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; +static JSON_NOINLINE int jsonParseAddNodeExpand( + JsonParse *pParse, /* Append the node to this object */ + u32 eType, /* Node type */ + u32 n, /* Content size or sub-node count */ + const char *zContent /* Content */ +){ + u32 nNew; + JsonNode *pNew; + assert( pParse->nNode>=pParse->nAlloc ); + if( pParse->oom ) return -1; + nNew = pParse->nAlloc*2 + 10; + pNew = sqlite3_realloc64(pParse->aNode, sizeof(JsonNode)*nNew); + if( pNew==0 ){ + pParse->oom = 1; + return -1; } - if( tdb, pParse->aBlob, t); - if( aNew==0 ){ pParse->oom = 1; return 1; } - pParse->aBlob = aNew; - pParse->nBlobAlloc = t; - return 0; + pParse->nAlloc = nNew; + pParse->aNode = pNew; + assert( pParse->nNodenAlloc ); + return jsonParseAddNode(pParse, eType, n, zContent); } /* -** If pParse->aBlob is not previously editable (because it is taken -** from 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. +** Create a new JsonNode instance based on the arguments and append that +** instance to the JsonParse. Return the index in pParse->aNode[] of the +** new node, or -1 if a memory allocation fails. */ -static int 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 +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 */ ){ - jsonBlobExpand(pParse, pParse->nBlob+1); - if( pParse->oom==0 ){ - assert( pParse->nBlob+1<=pParse->nBlobAlloc ); - pParse->aBlob[pParse->nBlob++] = c; + JsonNode *p; + if( pParse->aNode==0 || pParse->nNode>=pParse->nAlloc ){ + return jsonParseAddNodeExpand(pParse, eType, n, zContent); } + 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. +/* +** Return true if z[] begins with 4 (or more) hexadecimal digits */ -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; -} - -/* -** 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 jsonIs4HexB(const char *z, int *pOp){ - if( z[0]!='u' ) return 0; - if( !jsonIs4Hex(&z[1]) ) return 0; - *pOp = JSONB_TEXTJ; +static int jsonIs4Hex(const char *z){ + int i; + for(i=0; i<4; i++) if( !sqlite3Isxdigit(z[i]) ) return 0; return 1; } /* -** 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( jk ) return j+1; - if( z[j+1]!='.' && z[j+1]!='e' && z[j+1]!='E' ) return j+1; - j++; - } - for(; j0 ) return j+1; - if( x==JSONB_FLOAT && (j==k-1 || !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 ){ - 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( jk ) 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( jk ) return j+1; - if( (cnt & 1)==0 ){ - x = z[j] & 0x0f; - if( xJSONB_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. +** Parse a single JSON value which begins at pParse->zJson[i]. Return the +** index of the first character past the end of the value parsed. ** -** Return the index of the first character past the end of the element parsed, -** or one of the following special result codes: -** -** 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 / +** Return negative for a syntax error. Special cases: return -2 if the +** first non-whitespace character is '}' and return -3 if the first +** non-whitespace character is ']'. */ -static int jsonTranslateTextToBlob(JsonParse *pParse, u32 i){ +static int jsonParseValue(JsonParse *pParse, u32 i){ char c; u32 j; - u32 iThis, iStart; + int iThis; int x; - u8 t; + JsonNode *pNode; const char *z = pParse->zJson; -json_parse_restart: - switch( (u8)z[i] ){ - case '{': { + while( fast_isspace(z[i]) ){ i++; } + if( (c = z[i])=='{' ){ /* Parse object */ - 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; + iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); + if( iThis<0 ) return -1; for(j=i+1;;j++){ - 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( sqlite3JsonId1(z[j]) - || (z[j]=='\\' && jsonIs4HexB(&z[j+1], &op)) - ){ - int k = j+1; - while( (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; - t = pParse->aBlob[iBlob] & 0x0f; - if( tJSONB_TEXTRAW ){ - pParse->iErr = 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; } + if( pParse->oom ) return -1; + pNode = &pParse->aNode[pParse->nNode-1]; + if( pNode->eType!=JSON_STRING ) return -1; + pNode->jnFlags |= JNODE_LABEL; j = x; - 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; - } + while( fast_isspace(z[j]) ){ j++; } + if( z[j]!=':' ) return -1; + j++; + x = jsonParseValue(pParse, j); + pParse->iDepth--; + if( x<0 ) return -1; j = x; - 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; + while( fast_isspace(z[j]) ){ j++; } + c = z[j]; + if( c==',' ) continue; + if( c!='}' ) return -1; + break; } - jsonBlobChangePayloadSize(pParse, iThis, pParse->nBlob - iStart); - pParse->iDepth--; + pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; return j+1; - } - case '[': { + }else if( c=='[' ){ /* Parse array */ - 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; - } + iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); + if( iThis<0 ) return -1; + memset(&pParse->aNode[iThis].u, 0, sizeof(pParse->aNode[iThis].u)); for(j=i+1;;j++){ - 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; + 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; return -1; } j = x; - 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; + while( fast_isspace(z[j]) ){ j++; } + c = z[j]; + if( c==',' ) continue; + if( c!=']' ) return -1; + break; } - jsonBlobChangePayloadSize(pParse, iThis, pParse->nBlob - iStart); - pParse->iDepth--; + pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; return j+1; - } - case '\'': { - u8 opcode; - char cDelim; - pParse->hasNonstd = 1; - opcode = JSONB_TEXT; - goto parse_string; - case '"': + }else if( c=='"' ){ /* Parse string */ - opcode = JSONB_TEXT; - parse_string: - cDelim = z[i]; + u8 jnFlags = 0; j = i+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; - } - } + for(;;){ c = z[j]; - if( c==cDelim ){ - break; - }else if( c=='\\' ){ + if( (c & ~0x1f)==0 ){ + /* Control characters are not allowed in strings */ + return -1; + } + 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])) ){ - 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; + || (c=='u' && jsonIs4Hex(z+j+1)) ){ + jnFlags = JNODE_ESCAPE; }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=='"' ){ - opcode = JSONB_TEXT5; + break; } j++; } - jsonBlobAppendNode(pParse, opcode, j-1-i, &z[i+1]); + jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]); + if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags; return j+1; - } - case 't': { - if( strncmp(z+i,"true",4)==0 && !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 && !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( 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': + }else if( c=='n' + && strncmp(z+i,"null",4)==0 + && !sqlite3Isalnum(z[i+4]) ){ + jsonParseAddNode(pParse, JSON_NULL, 0, 0); + return i+4; + }else if( c=='t' + && strncmp(z+i,"true",4)==0 + && !sqlite3Isalnum(z[i+4]) ){ + jsonParseAddNode(pParse, JSON_TRUE, 0, 0); + return i+4; + }else if( c=='f' + && strncmp(z+i,"false",5)==0 + && !sqlite3Isalnum(z[i+5]) ){ + jsonParseAddNode(pParse, JSON_FALSE, 0, 0); + return i+5; + }else if( c=='-' || (c>='0' && c<='9') ){ /* Parse number */ - t = 0x00; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */ - parse_number: - seenE = 0; + u8 seenDP = 0; + u8 seenE = 0; assert( '-' < '0' ); - assert( '+' < '0' ); - assert( '.' < '0' ); - c = z[i]; - if( c<='0' ){ - if( c=='0' ){ - if( (z[i+1]=='x' || z[i+1]=='X') && sqlite3Isxdigit(z[i+2]) ){ - assert( t==0x00 ); - pParse->hasNonstd = 1; - t = 0x01; - for(j=i+3; sqlite3Isxdigit(z[j]); j++){} - goto parse_number_finish; - }else if( sqlite3Isdigit(z[i+1]) ){ - pParse->iErr = i+1; - return -1; - } - }else{ - if( !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') - && 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 + (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( sqlite3Isdigit(z[i+2]) ){ - pParse->iErr = i+1; - return -1; - }else if( (z[i+2]=='x' || z[i+2]=='X') && sqlite3Isxdigit(z[i+3]) ){ - pParse->hasNonstd = 1; - t |= 0x01; - for(j=i+4; sqlite3Isxdigit(z[j]); j++){} - goto parse_number_finish; - } - } - } + j = c=='-' ? i+1 : i; + if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1; } - - parse_number_2: - for(j=i+1;; j++){ + j = i+1; + for(;; j++){ c = z[j]; - if( sqlite3Isdigit(c) ) continue; + if( c>='0' && c<='9' ) continue; if( c=='.' ){ - if( (t & 0x02)!=0 ){ - pParse->iErr = j; - return -1; - } - t |= 0x02; + if( z[j-1]=='-' ) return -1; + if( seenDP ) return -1; + seenDP = 1; continue; } if( c=='e' || c=='E' ){ - if( z[j-1]<'0' ){ - if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && 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; + if( z[j-1]<'0' ) return -1; + if( seenE ) return -1; + seenDP = seenE = 1; c = z[j+1]; if( c=='+' || c=='-' ){ j++; c = z[j+1]; } - if( c<'0' || c>'9' ){ - pParse->iErr = j; - return -1; - } + if( c<'0' || c>'9' ) return -1; continue; } break; } - if( z[j-1]<'0' ){ - if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && 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]); + if( z[j-1]<'0' ) return -1; + jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT, + j - i, &z[i]); return j; - } - case '}': { - pParse->iErr = i; + }else if( c=='}' ){ return -2; /* End of {...} */ - } - case ']': { - pParse->iErr = i; + }else if( c==']' ){ return -3; /* End of [...] */ - } - case ',': { - pParse->iErr = i; - return -4; /* List separator */ - } - case ':': { - pParse->iErr = i; - return -5; /* Object label/value separator */ - } - case 0: { + }else if( c==0 ){ return 0; /* End of file */ - } - 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 && !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; khasNonstd = 1; - return i + nn; - } - pParse->iErr = i; + }else{ 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 held by pParse, -** but not pParse itself. +** are any errors. If an error occurs, free all memory associated with +** pParse. ** -** pParse must be initialized to an empty parse object prior to calling -** this routine. +** pParse is uninitialized when this routine is called. */ -static int jsonConvertTextToBlob( +static int jsonParse( JsonParse *pParse, /* Initialize and fill this JsonParse object */ - sqlite3_context *pCtx /* Report errors here */ + sqlite3_context *pCtx, /* Report errors here */ + const char *zJson /* Input JSON text to be parsed */ ){ int i; - const char *zJson = pParse->zJson; - i = jsonTranslateTextToBlob(pParse, 0); + memset(pParse, 0, sizeof(*pParse)); + if( zJson==0 ) return 1; + pParse->zJson = zJson; + i = jsonParseValue(pParse, 0); if( pParse->oom ) i = -1; if( i>0 ){ -#ifdef SQLITE_DEBUG assert( pParse->iDepth==0 ); - if( 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 ) sqlite3_result_error(pCtx, "malformed JSON", -1); - jsonParseReset(pParse); - return 1; - } - pParse->hasNonstd = 1; - } + while( fast_isspace(zJson[i]) ) i++; + if( zJson[i] ) i = -1; } if( i<=0 ){ if( pCtx!=0 ){ @@ -206870,832 +198213,161 @@ static int jsonConvertTextToBlob( return 0; } -/* -** 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 jsonReturnStringAsBlob(JsonString *pStr){ - JsonParse px; - memset(&px, 0, sizeof(px)); - jsonStringTerminate(pStr); - if( pStr->eErr ){ - sqlite3_result_error_nomem(pStr->pCtx); - return; - } - px.zJson = pStr->zBuf; - px.nJson = pStr->nUsed; - px.db = sqlite3_context_db_handle(pStr->pCtx); - (void)jsonTranslateTextToBlob(&px, 0); - if( px.oom ){ - sqlite3DbFree(px.db, px.aBlob); - sqlite3_result_error_nomem(pStr->pCtx); - }else{ - assert( px.nBlobAlloc>0 ); - assert( !px.bReadOnly ); - 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. +/* Mark node i of pParse as being a child of iParent. Call recursively +** to fill in all the descendants of node i. */ -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; - 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(; keErr |= JSTRING_MALFORMED; - break; - }else if( (u>>60)!=0 ){ - bOverflow = 1; - }else{ - u = u*16 + 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(; kaNode[i]; + u32 j; + pParse->aUp[i] = iParent; + switch( pNode->eType ){ + case JSON_ARRAY: { + for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){ + jsonParseFillInParentage(pParse, i+j, i); } break; } - case 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; k0 ){ - 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; + 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); } - 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( jeErr==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( jeErr==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; jjnIndent; 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. +** Compute the parentage of all nodes in a completed parse. */ -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( jnIndent++; - 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( jnIndent++; - 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; - } +static int jsonParseFindParents(JsonParse *pParse){ + u32 *aUp; + assert( pParse->aUp==0 ); + aUp = pParse->aUp = sqlite3_malloc64( sizeof(u32)*pParse->nNode ); + if( aUp==0 ){ + pParse->oom = 1; + return SQLITE_NOMEM; } - 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(sqlite3_value *pJson){ - u32 sz, n; - const u8 *aBlob; - int nBlob; - JsonParse s; - if( sqlite3_value_type(pJson)!=SQLITE_BLOB ) return 0; - aBlob = sqlite3_value_blob(pJson); - nBlob = 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; + jsonParseFillInParentage(pParse, 0, 0); + return SQLITE_OK; } /* -** Given that a JSONB_ARRAY object starts at offset i, return -** the number of entries in that array. +** Magic number used for the JSON parse cache in sqlite3_get_auxdata() */ -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 && idelta. +** Obtain a complete parse of the JSON found in the first argument +** of the argv array. Use the 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 sqlite3_get_auxdata() calls. */ -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 */ +static JsonParse *jsonParseCached( + sqlite3_context *pCtx, + sqlite3_value **argv, + sqlite3_context *pErrCtx ){ - i64 d = (i64)nIns - (i64)nDel; - if( d!=0 ){ - if( pParse->nBlob + d > pParse->nBlobAlloc ){ - jsonBlobExpand(pParse, pParse->nBlob+d); - if( pParse->oom ) return; - } - 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+1nJson==nJson + && memcmp(p->zJson,zJson,nJson)==0 ){ - i += 4; - continue; + p->nErr = 0; + pMatch = p; + }else if( p->iHoldiHold; + iMinKey = iKey; + } + if( p->iHold>iMaxHold ){ + iMaxHold = p->iHold; } - break; } - 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; + if( pMatch ){ + pMatch->nErr = 0; + pMatch->iHold = iMaxHold+1; + return pMatch; } - 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 = sqlite3Utf8ReadLimited((u8*)&z[nSkip], n-nSkip, piOut); - return nSkip + sz; - } - } - default: { - *piOut = JSON_INVALID_CHAR; - return 2; - } + p = sqlite3_malloc64( sizeof(*p) + nJson + 1 ); + if( p==0 ){ + sqlite3_result_error_nomem(pCtx); + 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 = 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 = 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; + memset(p, 0, sizeof(*p)); + p->zJson = (char*)&p[1]; + memcpy((char*)p->zJson, zJson, nJson+1); + if( jsonParse(p, pErrCtx, p->zJson) ){ + sqlite3_free(p); + return 0; } + p->nJson = nJson; + p->iHold = iMaxHold+1; + sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p, + (void(*)(void*))jsonParseFree); + return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey); } /* -** Compare two object labels. Return 1 if they are equal and -** 0 if they differ. Return -1 if an OOM occurs. +** Compare the OBJECT label at pNode against zKey,nKey. Return true on +** a match. */ -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; +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; }else{ - return jsonLabelCompareEscaped(zLeft, nLeft, rawLeft, - zRight, nRight, rawRight); + if( pNode->n!=nKey+2 ) return 0; + return strncmp(pNode->u.zJContent+1, zKey, nKey)==0; } } -/* -** 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 */ -} +/* forward declaration */ +static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**); /* -** Search along zPath to find the Json element specified. Return an -** index into pParse->aBlob[] for the start of that element's value. -** -** 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. +** 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. ** -** 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. +** If pApnd!=0, then try to append new nodes to complete zPath if it is +** possible to do so and if no existing node corresponds to zPath. If +** new nodes are appended *pApnd is set to 1. */ -static u32 jsonLookupStep( +static JsonNode *jsonLookupStep( JsonParse *pParse, /* The JSON to search */ - u32 iRoot, /* Begin the search at this element of aBlob[] */ + u32 iRoot, /* Begin the search at this node */ const char *zPath, /* The path to search */ - u32 iLabel /* Label if iRoot is a value of in an object */ + int *pApnd, /* Append nodes to complete path if not NULL */ + const char **pzErr /* Make *pzErr point to any syntax error in zPath */ ){ - u32 i, j, k, nKey, sz, n, iEnd, rc; + u32 i, j, nKey; const char *zKey; - 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; - } + JsonNode *pRoot = &pParse->aNode[iRoot]; + if( zPath[0]==0 ) return pRoot; + if( pRoot->jnFlags & JNODE_REPLACE ) return 0; if( zPath[0]=='.' ){ - int rawKey = 1; - x = pParse->aBlob[iRoot]; + if( pRoot->eType!=JSON_OBJECT ) return 0; zPath++; if( zPath[0]=='"' ){ zKey = zPath + 1; @@ -207704,851 +198376,303 @@ static u32 jsonLookupStep( if( zPath[i] ){ i++; }else{ - return JSON_LOOKUP_PATHERROR; + *pzErr = zPath; + return 0; } 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 ){ - 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( jaBlob[j] & 0x0f; - if( xJSONB_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; + *pzErr = zPath; + return 0; } - 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]=='[' ){ - x = pParse->aBlob[iRoot] & 0x0f; - if( x!=JSONB_ARRAY ) return JSON_LOOKUP_NOTFOUND; - n = jsonbPayloadSize(pParse, iRoot, &sz); - k = 0; - i = 1; - while( sqlite3Isdigit(zPath[i]) ){ - k = k*10 + zPath[i] - '0'; - i++; - } - if( i<2 || zPath[i]!=']' ){ - if( zPath[1]=='#' ){ - k = jsonbArrayCount(pParse, iRoot); - i = 2; - if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){ - unsigned int nn = 0; - i = 3; - do{ - nn = nn*10 + zPath[i] - '0'; - i++; - }while( sqlite3Isdigit(zPath[i]) ); - if( nn>k ) return JSON_LOOKUP_NOTFOUND; - k -= nn; - } - if( zPath[i]!=']' ){ - return JSON_LOOKUP_PATHERROR; + j = 1; + for(;;){ + while( j<=pRoot->n ){ + if( jsonLabelCompare(pRoot+j, zKey, nKey) ){ + return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr); } - }else{ - return JSON_LOOKUP_PATHERROR; - } - } - j = iRoot+n; - iEnd = j+sz; - while( jdelta ) 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); - } - jsonParseReset(&v); - if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot); - return rc; - } - }else{ - return JSON_LOOKUP_PATHERROR; - } - return JSON_LOOKUP_NOTFOUND; -} - -/* -** Convert a JSON BLOB into text and make that text the return value -** of an SQL function. -*/ -static void jsonReturnTextJsonFromBlob( - sqlite3_context *ctx, - const u8 *aBlob, - u32 nBlob -){ - 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 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 void jsonReturnFromBlob( - JsonParse *pParse, /* Complete JSON parse tree */ - u32 i, /* Index of the node */ - sqlite3_context *pCtx, /* Return value for this function */ - int textOnly /* return text JSON. Disregard user-data */ -){ - u32 n, sz; - int rc; - sqlite3 *db = sqlite3_context_db_handle(pCtx); - - n = jsonbPayloadSize(pParse, i, &sz); - if( n==0 ){ - sqlite3_result_error(pCtx, "malformed JSON", -1); - return; - } - switch( pParse->aBlob[i] & 0x0f ){ - case JSONB_NULL: { - if( sz ) goto returnfromblob_malformed; - sqlite3_result_null(pCtx); - break; - } - case JSONB_TRUE: { - if( sz ) goto returnfromblob_malformed; - sqlite3_result_int(pCtx, 1); - break; - } - case JSONB_FALSE: { - if( sz ) goto returnfromblob_malformed; - sqlite3_result_int(pCtx, 0); - break; - } - case JSONB_INT5: - case JSONB_INT: { - 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 = sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz); - if( z==0 ) goto returnfromblob_oom; - rc = sqlite3DecOrHexToI64(z, &iRes); - sqlite3DbFree(db, z); - if( rc==0 ){ - sqlite3_result_int64(pCtx, bNeg ? -iRes : iRes); - }else if( rc==3 && bNeg ){ - sqlite3_result_int64(pCtx, SMALLEST_INT64); - }else if( rc==1 ){ - goto returnfromblob_malformed; - }else{ - if( bNeg ){ n--; sz++; } - goto to_double; + j++; + j += jsonNodeSize(&pRoot[j]); } - break; + if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; + assert( pRoot->eU==2 ); + iRoot += pRoot->u.iAppend; + pRoot = &pParse->aNode[iRoot]; + j = 1; } - case JSONB_FLOAT5: - case JSONB_FLOAT: { - double r; - char *z; - if( sz==0 ) goto returnfromblob_malformed; - to_double: - z = sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz); - if( z==0 ) goto returnfromblob_oom; - rc = sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8); - sqlite3DbFree(db, z); - if( rc<=0 ) goto returnfromblob_malformed; - sqlite3_result_double(pCtx, r); - break; + 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; } - case JSONB_TEXTRAW: - case JSONB_TEXT: { - sqlite3_result_text(pCtx, (char*)&pParse->aBlob[i+n], sz, - SQLITE_TRANSIENT); - break; + }else if( zPath[0]=='[' ){ + i = 0; + j = 1; + while( sqlite3Isdigit(zPath[j]) ){ + i = i*10 + zPath[j] - '0'; + j++; } - 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 = sqlite3DbMallocRaw(db, nOut+1); - if( zOut==0 ) goto returnfromblob_oom; - for(iIn=iOut=0; iIn=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); + if( j<2 || zPath[j]!=']' ){ + 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]); } - iIn += szEscape - 1; - }else{ - zOut[iOut++] = c; + if( (pBase->jnFlags & JNODE_APPEND)==0 ) break; + assert( pBase->eU==2 ); + iBase += pBase->u.iAppend; + pBase = &pParse->aNode[iBase]; + j = 1; + } + j = 2; + if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){ + unsigned int x = 0; + j = 3; + do{ + x = x*10 + zPath[j] - '0'; + j++; + }while( sqlite3Isdigit(zPath[j]) ); + if( x>i ) return 0; + i -= x; + } + if( zPath[j]!=']' ){ + *pzErr = zPath; + return 0; } - } /* end for() */ - assert( iOut<=nOut ); - zOut[iOut] = 0; - sqlite3_result_text(pCtx, zOut, iOut, SQLITE_DYNAMIC); - break; - } - case JSONB_ARRAY: - case JSONB_OBJECT: { - int flags = textOnly ? 0 : SQLITE_PTR_TO_INT(sqlite3_user_data(pCtx)); - if( flags & JSON_BLOB ){ - sqlite3_result_blob(pCtx, &pParse->aBlob[i], sz+n, SQLITE_TRANSIENT); }else{ - jsonReturnTextJsonFromBlob(pCtx, &pParse->aBlob[i], sz+n); + *pzErr = zPath; + return 0; } - break; - } - default: { - goto returnfromblob_malformed; } - } - return; - -returnfromblob_oom: - sqlite3_result_error_nomem(pCtx); - return; - -returnfromblob_malformed: - sqlite3_result_error(pCtx, "malformed JSON", -1); - return; -} - -/* -** 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. -** -** 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 sqlite3_value_blob(pArg). -** -** 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 int jsonFunctionArgToBlob( - sqlite3_context *ctx, - sqlite3_value *pArg, - JsonParse *pParse -){ - int eType = sqlite3_value_type(pArg); - static u8 aNull[] = { 0x00 }; - memset(pParse, 0, sizeof(pParse[0])); - pParse->db = 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*)sqlite3_value_blob(pArg); - pParse->nBlob = sqlite3_value_bytes(pArg); - }else{ - sqlite3_result_error(ctx, "JSON cannot hold BLOB values", -1); - return 1; - } - break; + 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; } - case SQLITE_TEXT: { - const char *zJson = (const char*)sqlite3_value_text(pArg); - int nJson = sqlite3_value_bytes(pArg); - if( zJson==0 ) return 1; - if( sqlite3_value_subtype(pArg)==JSON_SUBTYPE ){ - pParse->zJson = (char*)zJson; - pParse->nJson = nJson; - if( jsonConvertTextToBlob(pParse, ctx) ){ - sqlite3_result_error(ctx, "malformed JSON", -1); - sqlite3DbFree(pParse->db, pParse->aBlob); - memset(pParse, 0, sizeof(pParse[0])); - return 1; - } - }else{ - jsonBlobAppendNode(pParse, JSONB_TEXTRAW, nJson, zJson); - } - break; + if( j<=pRoot->n ){ + return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr); } - case SQLITE_FLOAT: { - double r = sqlite3_value_double(pArg); - if( NEVER(sqlite3IsNaN(r)) ){ - jsonBlobAppendNode(pParse, JSONB_NULL, 0, 0); - }else{ - int n = sqlite3_value_bytes(pArg); - const char *z = (const char*)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); - } + 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 ); } - break; - } - case SQLITE_INTEGER: { - int n = sqlite3_value_bytes(pArg); - const char *z = (const char*)sqlite3_value_text(pArg); - if( z==0 ) return 1; - jsonBlobAppendNode(pParse, JSONB_INT, n, z); - break; + return pNode; } - } - if( pParse->oom ){ - sqlite3_result_error_nomem(ctx); - return 1; }else{ - return 0; + *pzErr = zPath; } + return 0; } /* -** 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. +** Append content to pParse that will complete zPath. Return a pointer +** to the inserted node, or return NULL if the append fails. */ -static char *jsonBadPathError( - sqlite3_context *ctx, /* The function call containing the error */ - const char *zPath /* The path with the problem */ +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 */ ){ - char *zMsg = sqlite3_mprintf("bad JSON path: %Q", zPath); - if( ctx==0 ) return zMsg; - if( zMsg ){ - sqlite3_result_error(ctx, zMsg, -1); - sqlite3_free(zMsg); - }else{ - sqlite3_result_error_nomem(ctx); + *pApnd = 1; + if( zPath[0]==0 ){ + jsonParseAddNode(pParse, JSON_NULL, 0, 0); + return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1]; } - 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( - sqlite3_context *ctx, - int argc, - 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; inBlob, 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 ){ - sqlite3_result_error(ctx, "malformed JSON", -1); + if( zPath[0]=='.' ){ + jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); + }else if( strncmp(zPath,"[0]",3)==0 ){ + jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); }else{ - jsonBadPathError(ctx, zPath); + return 0; } - return; + if( pParse->oom ) return 0; + return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr); } /* -** 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. +** Return the text of a syntax error message on a JSON path. Space is +** obtained from sqlite3_malloc(). */ -static int jsonArgIsJsonb(sqlite3_value *pArg, JsonParse *p){ - u32 n, sz = 0; - p->aBlob = (u8*)sqlite3_value_blob(pArg); - p->nBlob = (u32)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; +static char *jsonPathSyntaxError(const char *zErr){ + return sqlite3_mprintf("JSON path error near '%q'", zErr); } /* -** 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. +** 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. ** -** 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. +** On an error, write an error message into pCtx and increment the +** pParse->nErr counter. ** -** If any errors are detected, an appropriate error messages is set -** using 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. +** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if +** nodes are appended. */ -static JsonParse *jsonParseFuncArg( - sqlite3_context *ctx, - sqlite3_value *pArg, - u32 flgs +static JsonNode *jsonLookup( + JsonParse *pParse, /* The JSON to search */ + const char *zPath, /* The path to search */ + int *pApnd, /* Append nodes to complete path if not NULL */ + sqlite3_context *pCtx /* Report errors here, if not NULL */ ){ - int eType; /* Datatype of pArg */ - JsonParse *p = 0; /* Value to be returned */ - JsonParse *pFromCache = 0; /* Value taken from cache */ - sqlite3 *db; /* The database connection */ + const char *zErr = 0; + JsonNode *pNode = 0; + char *zMsg; - assert( ctx!=0 ); - eType = 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 = sqlite3_context_db_handle(ctx); -rebuild_from_cache: - p = 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 = 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 - */ + if( zPath==0 ) return 0; + if( zPath[0]!='$' ){ + zErr = zPath; + goto lookup_err; } - p->zJson = (char*)sqlite3_value_text(pArg); - p->nJson = 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 = sqlite3ValueIsOfClass(pArg, sqlite3RCStrUnref); - int rc; - if( !isRCStr ){ - char *zNew = 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{ - 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; + zPath++; + pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr); + if( zErr==0 ) return pNode; -json_pfa_malformed: - if( flgs & JSON_KEEPERROR ){ - p->nErr = 1; - return p; +lookup_err: + pParse->nErr++; + assert( zErr!=0 && pCtx!=0 ); + zMsg = jsonPathSyntaxError(zErr); + if( zMsg ){ + sqlite3_result_error(pCtx, zMsg, -1); + sqlite3_free(zMsg); }else{ - jsonParseFree(p); - sqlite3_result_error(ctx, "malformed JSON", -1); - return 0; + sqlite3_result_error_nomem(pCtx); } - -json_pfa_oom: - jsonParseFree(pFromCache); - jsonParseFree(p); - sqlite3_result_error_nomem(ctx); return 0; } + /* -** 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. +** Report the wrong number of arguments for json_insert(), json_replace() +** or json_set(). */ -static void jsonReturnParse( - sqlite3_context *ctx, - JsonParse *p +static void jsonWrongNumArgs( + sqlite3_context *pCtx, + const char *zFuncName ){ - int flgs; - if( p->oom ){ - sqlite3_result_error_nomem(ctx); - return; - } - flgs = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); - if( flgs & JSON_BLOB ){ - if( p->nBlobAlloc>0 && !p->bReadOnly ){ - sqlite3_result_blob(ctx, p->aBlob, p->nBlob, SQLITE_DYNAMIC); - p->nBlobAlloc = 0; - }else{ - sqlite3_result_blob(ctx, p->aBlob, p->nBlob, SQLITE_TRANSIENT); + char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments", + zFuncName); + sqlite3_result_error(pCtx, zMsg, -1); + sqlite3_free(zMsg); +} + +/* +** Mark all NULL entries in the Object passed in as JNODE_REMOVE. +*/ +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; } - }else{ - JsonString s; - jsonStringInit(&s, ctx); - p->delta = 0; - jsonTranslateBlobToText(p, 0, &s); - jsonReturnString(&s, p, ctx); - sqlite3_result_subtype(ctx, JSON_SUBTYPE); } } + /**************************************************************************** ** SQL functions used for testing and debugging ****************************************************************************/ -#if SQLITE_DEBUG +#ifdef 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 */ - sqlite3_str *pOut /* Generate output into this sqlite3_str object */ -){ - while( iStartaBlob[iStart] & 0x0f; - u32 savedNBlob = pParse->nBlob; - 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 && xaBlob[iStart+i]); - } - if( n==0 ){ - 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; - } - } - } - sqlite3_str_appendall(pOut," <-- "); - switch( x ){ - case JSONB_NULL: sqlite3_str_appendall(pOut,"null"); break; - case JSONB_TRUE: sqlite3_str_appendall(pOut,"true"); break; - case JSONB_FALSE: sqlite3_str_appendall(pOut,"false"); break; - case JSONB_INT: sqlite3_str_appendall(pOut,"int"); break; - case JSONB_INT5: sqlite3_str_appendall(pOut,"int5"); break; - case JSONB_FLOAT: sqlite3_str_appendall(pOut,"float"); break; - case JSONB_FLOAT5: sqlite3_str_appendall(pOut,"float5"); break; - case JSONB_TEXT: sqlite3_str_appendall(pOut,"text"); break; - case JSONB_TEXTJ: sqlite3_str_appendall(pOut,"textj"); break; - case JSONB_TEXT5: sqlite3_str_appendall(pOut,"text5"); break; - case JSONB_TEXTRAW: sqlite3_str_appendall(pOut,"textraw"); break; - case JSONB_ARRAY: { - 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: { - sqlite3_str_appendf(pOut, "object, %u bytes\n", sz); - jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2, pOut); - showContent = 0; - break; - } - default: { - sqlite3_str_appendall(pOut, "ERROR: unknown node type\n"); - showContent = 0; - break; - } +** The json_parse(JSON) function returns a string which describes +** a parse of the JSON provided. Or it returns NULL if JSON is not +** well-formed. +*/ +static void jsonParseFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonString s; /* Output string - not real JSON */ + JsonParse x; /* The parse */ + u32 i; + + assert( argc==1 ); + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + jsonParseFindParents(&x); + jsonInit(&s, ctx); + for(i=0; iaBlob[j]; - if( c<0x20 || c>=0x7f ) c = '.'; - sqlite3_str_append(pOut, (char*)&c, 1); - } - sqlite3_str_append(pOut, "\"\n", 2); - } + 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 ); } - iStart += n + sz; + jsonAppendRaw(&s, "\n", 1); } + jsonParseReset(&x); + jsonResult(&s); } -static void jsonShowParse(JsonParse *pParse){ - 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); - } - sqlite3StrAccumInit(&out, 0, zBuf, sizeof(zBuf), 1000000); - jsonDebugPrintBlob(pParse, 0, pParse->nBlob, 0, &out); - printf("%s", sqlite3_str_value(&out)); - sqlite3_str_reset(&out); -} -#endif /* SQLITE_DEBUG */ -#ifdef SQLITE_DEBUG /* -** 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. +** The json_test1(JSON) function return true (1) if the input is JSON +** text generated by another json function. It returns (0) if the input +** is not known to be JSON. */ -static void jsonParseFunc( +static void jsonTest1Func( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ - JsonParse *p; /* The parse */ - sqlite3_str out; - - assert( argc>=1 ); - 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); - sqlite3_result_text64(ctx,out.zText,out.nChar,SQLITE_TRANSIENT,SQLITE_UTF8); - }else{ - jsonShowParse(p); - } - jsonParseFree(p); - sqlite3_str_reset(&out); + UNUSED_PARAMETER(argc); + sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE); } #endif /* SQLITE_DEBUG */ @@ -208557,7 +198681,7 @@ static void jsonParseFunc( ****************************************************************************/ /* -** 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. @@ -208570,9 +198694,9 @@ static void jsonQuoteFunc( JsonString jx; UNUSED_PARAMETER(argc); - jsonStringInit(&jx, ctx); - jsonAppendSqlValue(&jx, argv[0]); - jsonReturnString(&jx, 0, 0); + jsonInit(&jx, ctx); + jsonAppendValue(&jx, argv[0]); + jsonResult(&jx); sqlite3_result_subtype(ctx, JSON_SUBTYPE); } @@ -208589,17 +198713,18 @@ static void jsonArrayFunc( int i; JsonString jx; - jsonStringInit(&jx, ctx); + jsonInit(&jx, ctx); jsonAppendChar(&jx, '['); for(i=0; inNode ); if( argc==2 ){ const char *zPath = (const char*)sqlite3_value_text(argv[1]); - 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{ - sqlite3_result_error(ctx, "malformed JSON", -1); - } - eErr = 1; - i = 0; - } + pNode = jsonLookup(p, zPath, 0, ctx); }else{ - i = 0; + pNode = p->aNode; } - if( (p->aBlob[i] & 0x0f)==JSONB_ARRAY ){ - cnt = jsonbArrayCount(p, i); + if( pNode==0 ){ + return; + } + if( pNode->eType==JSON_ARRAY ){ + assert( (pNode->jnFlags & JNODE_APPEND)==0 ); + for(i=1; i<=pNode->n; n++){ + i += jsonNodeSize(&pNode[i]); + } } - if( !eErr ) sqlite3_result_int64(ctx, cnt); - jsonParseFree(p); + sqlite3_result_int64(ctx, n); } -/* True if the string is all alphanumerics and underscores */ -static int jsonAllAlphanum(const char *z, int n){ - int i; - for(i=0; i2 ){ - jsonAppendChar(&jx, '['); - } - for(i=1; i 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( 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); + zPath = (const char*)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( 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); }else{ - jsonAppendRawNZ(&jx, ".\"", 2); - jsonAppendRaw(&jx, zPath, nPath); - jsonAppendRawNZ(&jx, "\"", 1); + pNode = jsonLookup(p, zPath, 0, ctx); } - jsonStringTerminate(&jx); - j = jsonLookupStep(p, 0, jx.zBuf, 0); - jsonStringReset(&jx); - }else{ - jsonBadPathError(ctx, zPath); - goto json_extract_error; - } - if( jnBlob ){ - if( argc==2 ){ + if( pNode ){ if( flags & JSON_JSON ){ - jsonStringInit(&jx, ctx); - jsonTranslateBlobToText(p, j, &jx); - jsonReturnString(&jx, 0, 0); - jsonStringReset(&jx); - assert( (flags & JSON_BLOB)==0 ); - sqlite3_result_subtype(ctx, JSON_SUBTYPE); + jsonReturnJson(pNode, ctx, 0); }else{ - jsonReturnFromBlob(p, j, ctx, 0); - if( (flags & (JSON_SQL|JSON_BLOB))==0 - && (p->aBlob[j]&0x0f)>=JSONB_ARRAY - ){ - sqlite3_result_subtype(ctx, JSON_SUBTYPE); - } + jsonReturn(pNode, ctx, 0); + sqlite3_result_subtype(ctx, 0); } - }else{ - jsonAppendSeparator(&jx); - jsonTranslateBlobToText(p, j, &jx); } - }else if( j==JSON_LOOKUP_NOTFOUND ){ - if( argc==2 ){ - goto json_extract_error; /* Return NULL if not found */ + }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; inErr ) break; + jsonAppendSeparator(&jx); + if( pNode ){ + jsonRenderNode(pNode, &jx, 0); }else{ - jsonAppendSeparator(&jx); - jsonAppendRawNZ(&jx, "null", 4); + jsonAppendRaw(&jx, "null", 4); } - }else if( j==JSON_LOOKUP_ERROR ){ - sqlite3_result_error(ctx, "malformed JSON", -1); - goto json_extract_error; - }else{ - jsonBadPathError(ctx, zPath); - goto json_extract_error; } - } - if( argc>2 ){ - jsonAppendChar(&jx, ']'); - jsonReturnString(&jx, 0, 0); - if( (flags & JSON_BLOB)==0 ){ + if( i==argc ){ + jsonAppendChar(&jx, ']'); + jsonResult(&jx); sqlite3_result_subtype(ctx, JSON_SUBTYPE); } + jsonReset(&jx); } -json_extract_error: - jsonStringReset(&jx); - jsonParseFree(p); - return; } -/* -** 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 && iTargetnBlob ); - assert( iPatch>=0 && iPatchnBlob ); - 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( iPCursoraBlob[iPCursor] & 0x0f; - if( ePLabelJSONB_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( iTCursoraBlob[iTCursor] & 0x0f; - if( eTLabelJSONB_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( iTCursoroom) ) 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; +/* 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( iTargetnNode ); + pTarget = &pParse->aNode[iTarget]; + assert( (pPatch->jnFlags & JNODE_APPEND)==0 ); + if( pTarget->eType!=JSON_OBJECT ){ + jsonRemoveAllNulls(pPatch); + return pPatch; + } + iRoot = iTarget; + for(i=1; in; 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; jn; 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; } } + 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]; + } } - if( pTarget->delta ) jsonAfterEditSizeAdjust(pTarget, iTarget); - return pTarget->oom ? JSON_MERGE_OOM : JSON_MERGE_OK; + return pTarget; } - /* ** Implementation of the json_mergepatch(JSON1,JSON2) function. Return a JSON ** object that is the result of running the RFC 7396 MergePatch() algorithm @@ -208990,27 +198962,25 @@ static void jsonPatchFunc( int argc, sqlite3_value **argv ){ - JsonParse *pTarget; /* The TARGET */ - JsonParse *pPatch; /* The PATCH */ - int rc; /* Result code */ + JsonParse x; /* The JSON that is being patched */ + JsonParse y; /* The patch */ + JsonNode *pResult; /* The result of the merge */ UNUSED_PARAMETER(argc); - 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 ){ - sqlite3_result_error_nomem(ctx); - }else{ - sqlite3_result_error(ctx, "malformed JSON", -1); - } - jsonParseFree(pPatch); + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + if( jsonParse(&y, ctx, (const char*)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{ + sqlite3_result_error_nomem(ctx); } - jsonParseFree(pTarget); + jsonParseReset(&x); + jsonParseReset(&y); } @@ -209034,23 +199004,23 @@ static void jsonObjectFunc( "of arguments", -1); return; } - jsonStringInit(&jx, ctx); + jsonInit(&jx, ctx); jsonAppendChar(&jx, '{'); for(i=0; i1 ? JSON_EDITABLE : 0); - if( p==0 ) return; - for(i=1; ieEdit = 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{ - sqlite3_result_error(ctx, "malformed JSON", -1); - } - goto json_remove_done; - } + if( zPath==0 ) goto remove_done; + pNode = jsonLookup(&x, zPath, 0, ctx); + if( x.nErr ) goto remove_done; + if( pNode ) pNode->jnFlags |= JNODE_REMOVE; } - jsonReturnParse(ctx, p); - jsonParseFree(p); - return; - -json_remove_patherror: - jsonBadPathError(ctx, zPath); - -json_remove_done: - jsonParseFree(p); - return; + if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){ + jsonReturnJson(x.aNode, ctx, 0); + } +remove_done: + jsonParseReset(&x); } /* @@ -209123,12 +199069,38 @@ static void jsonReplaceFunc( int argc, sqlite3_value **argv ){ + JsonParse x; /* The parse */ + JsonNode *pNode; + const char *zPath; + u32 i; + if( argc<1 ) return; if( (argc&1)==0 ) { jsonWrongNumArgs(ctx, "replace"); return; } - jsonInsertIntoBlob(ctx, argc, argv, JEDIT_REPL); + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + assert( x.nNode ); + for(i=1; i<(u32)argc; i+=2){ + zPath = (const char*)sqlite3_value_text(argv[i]); + pNode = jsonLookup(&x, zPath, 0, ctx); + if( x.nErr ) goto replace_err; + if( pNode ){ + 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 ); + sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]); + }else{ + jsonReturnJson(x.aNode, ctx, argv); + } +replace_err: + jsonParseReset(&x); } @@ -209149,16 +199121,45 @@ static void jsonSetFunc( int argc, sqlite3_value **argv ){ - - int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); - int bIsSet = (flags&JSON_ISSET)!=0; + JsonParse x; /* The parse */ + JsonNode *pNode; + const char *zPath; + u32 i; + int bApnd; + int bIsSet = sqlite3_user_data(ctx)!=0; if( argc<1 ) return; if( (argc&1)==0 ) { jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert"); return; } - jsonInsertIntoBlob(ctx, argc, argv, bIsSet ? JEDIT_SET : JEDIT_INS); + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + assert( x.nNode ); + for(i=1; i<(u32)argc; i+=2){ + zPath = (const char*)sqlite3_value_text(argv[i]); + bApnd = 0; + pNode = jsonLookup(&x, zPath, &bApnd, ctx); + if( x.oom ){ + sqlite3_result_error_nomem(ctx); + goto jsonSetDone; + }else if( x.nErr ){ + goto jsonSetDone; + }else if( pNode && (bApnd || bIsSet) ){ + 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 ); + sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]); + }else{ + jsonReturnJson(x.aNode, ctx, argv); + } +jsonSetDone: + jsonParseReset(&x); } /* @@ -209174,127 +199175,27 @@ static void jsonTypeFunc( sqlite3_value **argv ){ JsonParse *p; /* The parse */ - const char *zPath = 0; - u32 i; + const char *zPath; + JsonNode *pNode; - p = jsonParseFuncArg(ctx, argv[0], 0); + p = jsonParseCached(ctx, argv, ctx); if( p==0 ) return; if( argc==2 ){ zPath = (const char*)sqlite3_value_text(argv[1]); - 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{ - sqlite3_result_error(ctx, "malformed JSON", -1); - } - goto json_type_done; - } + pNode = jsonLookup(p, zPath, 0, ctx); }else{ - i = 0; + pNode = p->aNode; } - 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( - sqlite3_context *ctx, - int argc, - 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*)sqlite3_value_text(argv[1]))==0 ){ - x.zIndent = " "; - x.szIndent = 4; - }else{ - x.szIndent = (u32)strlen(x.zIndent); + if( pNode ){ + sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC); } - jsonTranslateBlobToPrettyText(&x, 0); - jsonReturnString(&s, 0, 0); - jsonParseFree(x.pParse); } /* ** json_valid(JSON) -** 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. +** +** Return 1 if JSON is a well-formed JSON string according to RFC-7159. +** Return 0 otherwise. */ static void jsonValidFunc( sqlite3_context *ctx, @@ -209302,128 +199203,12 @@ static void jsonValidFunc( sqlite3_value **argv ){ JsonParse *p; /* The parse */ - u8 flags = 1; - u8 res = 0; - if( argc==2 ){ - i64 f = sqlite3_value_int64(argv[1]); - if( f<1 || f>15 ){ - sqlite3_result_error(ctx, "FLAGS parameter to json_valid() must be" - " between 1 and 15", -1); - return; - } - flags = f & 0x0f; - } - switch( sqlite3_value_type(argv[0]) ){ - case SQLITE_NULL: { -#ifdef SQLITE_LEGACY_JSON_VALID - /* Incorrect legacy behavior was to return FALSE for a NULL input */ - 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*)sqlite3_value_blob(argv[0]); - px.nBlob = 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 ){ - sqlite3_result_error_nomem(ctx); - }else if( p->nErr ){ - /* no-op */ - }else if( (flags & 0x02)!=0 || p->hasNonstd==0 ){ - res = 1; - } - jsonParseFree(p); - }else{ - sqlite3_result_error_nomem(ctx); - } - break; - } - } - 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( - sqlite3_context *ctx, - int argc, - 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 = sqlite3_context_db_handle(ctx); - if( jsonFuncArgMightBeBinary(argv[0]) ){ - s.aBlob = (u8*)sqlite3_value_blob(argv[0]); - s.nBlob = sqlite3_value_bytes(argv[0]); - iErrPos = (i64)jsonbValidityCheck(&s, 0, s.nBlob, 1); - }else{ - s.zJson = (char*)sqlite3_value_text(argv[0]); - if( s.zJson==0 ) return; /* NULL input or OOM */ - s.nJson = 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; kzBuf==0 ){ - jsonStringInit(pStr, ctx); + jsonInit(pStr, ctx); jsonAppendChar(pStr, '['); }else if( pStr->nUsed>1 ){ jsonAppendChar(pStr, ','); } pStr->pCtx = ctx; - jsonAppendSqlValue(pStr, argv[0]); + jsonAppendValue(pStr, argv[0]); } } static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){ JsonString *pStr; pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); if( pStr ){ - int flags; pStr->pCtx = ctx; jsonAppendChar(pStr, ']'); - flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); - if( pStr->eErr ){ - jsonReturnString(pStr, 0, 0); - return; - }else if( flags & JSON_BLOB ){ - jsonReturnStringAsBlob(pStr); - if( isFinal ){ - if( !pStr->bStatic ) sqlite3RCStrUnref(pStr->zBuf); - }else{ - jsonStringTrimOneChar(pStr); - } - return; + if( pStr->bErr ){ + if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); + assert( pStr->bStatic ); }else if( isFinal ){ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, - pStr->bStatic ? SQLITE_TRANSIENT : - sqlite3RCStrUnref); + pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); pStr->bStatic = 1; }else{ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); - jsonStringTrimOneChar(pStr); + pStr->nUsed--; } }else{ sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC); @@ -209514,7 +199288,7 @@ static void jsonGroupInverse( pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); #ifdef NEVER /* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will - ** always have been called to initialize it */ + ** always have been called to initalize it */ if( NEVER(!pStr) ) return; #endif z = pStr->zBuf; @@ -209558,46 +199332,34 @@ static void jsonObjectStep( pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); if( pStr ){ if( pStr->zBuf==0 ){ - jsonStringInit(pStr, ctx); + jsonInit(pStr, ctx); jsonAppendChar(pStr, '{'); }else if( pStr->nUsed>1 ){ jsonAppendChar(pStr, ','); } pStr->pCtx = ctx; z = (const char*)sqlite3_value_text(argv[0]); - n = sqlite3Strlen30(z); + n = (u32)sqlite3_value_bytes(argv[0]); jsonAppendString(pStr, z, n); jsonAppendChar(pStr, ':'); - jsonAppendSqlValue(pStr, argv[1]); + jsonAppendValue(pStr, argv[1]); } } static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){ JsonString *pStr; pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); if( pStr ){ - int flags; jsonAppendChar(pStr, '}'); - pStr->pCtx = ctx; - flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); - if( pStr->eErr ){ - jsonReturnString(pStr, 0, 0); - return; - }else if( flags & JSON_BLOB ){ - jsonReturnStringAsBlob(pStr); - if( isFinal ){ - if( !pStr->bStatic ) sqlite3RCStrUnref(pStr->zBuf); - }else{ - jsonStringTrimOneChar(pStr); - } - return; + if( pStr->bErr ){ + if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); + assert( pStr->bStatic ); }else if( isFinal ){ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, - pStr->bStatic ? SQLITE_TRANSIENT : - sqlite3RCStrUnref); + pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); pStr->bStatic = 1; }else{ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); - jsonStringTrimOneChar(pStr); + pStr->nUsed--; } }else{ sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC); @@ -209617,37 +199379,19 @@ static void jsonObjectFinal(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 { sqlite3_vtab_cursor base; /* Base class - must be first */ u32 iRowid; /* The rowid */ - u32 i; /* Index in sParse.aBlob[] of current row */ + u32 iBegin; /* The first node of the scan */ + u32 i; /* Index in sParse.aNode[] of current row */ u32 iEnd; /* EOF when i equals or exceeds this value */ - u32 nRoot; /* Size of the root path in bytes */ - u8 eType; /* Type of the container for element i */ + u8 eType; /* Type of top-level element */ u8 bRecursive; /* True for json_tree(). False for json_each() */ - u32 nParent; /* Current nesting depth */ - u32 nParentAlloc; /* Space allocated for aParent[] */ - JsonParent *aParent; /* Parent elements of i */ - sqlite3 *db; /* Database connection */ - JsonString path; /* Current path */ + char *zJson; /* Input JSON */ + char *zRoot; /* Path by which to filter zJson */ JsonParse sParse; /* Parse of the input JSON */ }; -typedef struct JsonEachConnection JsonEachConnection; -struct JsonEachConnection { - sqlite3_vtab base; /* Base class - must be first */ - sqlite3 *db; /* Database connection */ -}; - /* Constructor for the json_each virtual table */ static int jsonEachConnect( @@ -209657,7 +199401,7 @@ static int jsonEachConnect( sqlite3_vtab **ppVtab, char **pzErr ){ - JsonEachConnection *pNew; + sqlite3_vtab *pNew; int rc; /* Column numbers */ @@ -209683,32 +199427,28 @@ static int jsonEachConnect( "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path," "json HIDDEN,root HIDDEN)"); if( rc==SQLITE_OK ){ - pNew = (JsonEachConnection*)sqlite3DbMallocZero(db, sizeof(*pNew)); - *ppVtab = (sqlite3_vtab*)pNew; + pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(*pNew)); sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); - pNew->db = db; } return rc; } /* destructor for json_each virtual table */ static int jsonEachDisconnect(sqlite3_vtab *pVtab){ - JsonEachConnection *p = (JsonEachConnection*)pVtab; - sqlite3DbFree(p->db, pVtab); + sqlite3_free(pVtab); return SQLITE_OK; } /* constructor for a JsonEachCursor object for json_each(). */ static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ - JsonEachConnection *pVtab = (JsonEachConnection*)p; JsonEachCursor *pCur; UNUSED_PARAMETER(p); - pCur = sqlite3DbMallocZero(pVtab->db, sizeof(*pCur)); + pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; - pCur->db = pVtab->db; - jsonStringZero(&pCur->path); + memset(pCur, 0, sizeof(*pCur)); *ppCursor = &pCur->base; return SQLITE_OK; } @@ -209726,24 +199466,22 @@ static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ /* Reset a JsonEachCursor back to its original state. Free any memory ** held. */ static void jsonEachCursorReset(JsonEachCursor *p){ + sqlite3_free(p->zJson); + sqlite3_free(p->zRoot); jsonParseReset(&p->sParse); - jsonStringReset(&p->path); - 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(sqlite3_vtab_cursor *cur){ JsonEachCursor *p = (JsonEachCursor*)cur; jsonEachCursorReset(p); - - sqlite3DbFree(p->db, cur); + sqlite3_free(cur); return SQLITE_OK; } @@ -209754,233 +199492,198 @@ static int jsonEachEof(sqlite3_vtab_cursor *cur){ return p->i >= p->iEnd; } -/* -** 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 || !sqlite3Isalpha(z[0]) ){ - needQuote = 1; - }else{ - for(i=0; ipath,".\"%.*s\"", sz, z); - }else{ - jsonPrintf(sz+2,&p->path,".%.*s", sz, z); - } - } -} - /* Advance the cursor to the next element for json_tree() */ static int jsonEachNext(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 = 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; + if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++; + p->i++; + p->iRowid++; + if( p->iiEnd ){ + 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++; + } } } }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++; + 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; + } + } } - p->iRowid++; - return rc; + return SQLITE_OK; } -/* Length of the path for rowid==0 in bRecursive mode. +/* Append an object label to the JSON Path being constructed +** in pStr. */ -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; - } +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 && sqlite3Isalpha(z[1]) ){ + for(jj=2; jjsParse.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); + } } /* Return the value of a column */ static int jsonEachColumn( sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ - int iColumn /* Which column to return */ + int i /* Which column to return */ ){ JsonEachCursor *p = (JsonEachCursor*)cur; - switch( iColumn ){ + JsonNode *pThis = &p->sParse.aNode[p->i]; + switch( i ){ case JEACH_KEY: { - 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; - sqlite3Atoi64(&p->path.zBuf[j+1], &x, n-1, SQLITE_UTF8); - sqlite3_result_int64(ctx, x); - }else if( p->path.zBuf[j+1]=='"' ){ - sqlite3_result_text(ctx, &p->path.zBuf[j+2], n-3, SQLITE_TRANSIENT); + 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; }else{ - sqlite3_result_text(ctx, &p->path.zBuf[j+1], n-1, SQLITE_TRANSIENT); + iKey = p->iRowid; } - break; - } - if( p->eType==JSONB_OBJECT ){ - jsonReturnFromBlob(&p->sParse, p->i, ctx, 1); - }else{ - assert( p->eType==JSONB_ARRAY ); - sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iKey); + sqlite3_result_int64(ctx, (sqlite3_int64)iKey); } break; } case JEACH_VALUE: { - u32 i = jsonSkipLabel(p); - jsonReturnFromBlob(&p->sParse, i, ctx, 1); - if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY ){ - sqlite3_result_subtype(ctx, JSON_SUBTYPE); - } + if( pThis->jnFlags & JNODE_LABEL ) pThis++; + jsonReturn(pThis, ctx, 0); break; } case JEACH_TYPE: { - u32 i = jsonSkipLabel(p); - u8 eType = p->sParse.aBlob[i] & 0x0f; - sqlite3_result_text(ctx, jsonbType[eType], -1, SQLITE_STATIC); + if( pThis->jnFlags & JNODE_LABEL ) pThis++; + sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC); break; } case JEACH_ATOM: { - u32 i = jsonSkipLabel(p); - if( (p->sParse.aBlob[i] & 0x0f)sParse, i, ctx, 1); - } + if( pThis->jnFlags & JNODE_LABEL ) pThis++; + if( pThis->eType>=JSON_ARRAY ) break; + jsonReturn(pThis, ctx, 0); break; } case JEACH_ID: { - sqlite3_result_int64(ctx, (sqlite3_int64)p->i); + sqlite3_result_int64(ctx, + (sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0)); break; } case JEACH_PARENT: { - if( p->nParent>0 && p->bRecursive ){ - sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iHead); + if( p->i>p->iBegin && p->bRecursive ){ + sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]); } break; } case JEACH_FULLKEY: { - u64 nBase = p->path.nUsed; - if( p->nParent ) jsonAppendPathName(p); - sqlite3_result_text64(ctx, p->path.zBuf, p->path.nUsed, - SQLITE_TRANSIENT, SQLITE_UTF8); - p->path.nUsed = nBase; + 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); break; } case JEACH_PATH: { - u32 n = jsonEachPathLength(p); - sqlite3_result_text64(ctx, p->path.zBuf, n, - SQLITE_TRANSIENT, SQLITE_UTF8); - break; + 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 } default: { - sqlite3_result_text(ctx, p->path.zBuf, p->nRoot, SQLITE_STATIC); + const char *zRoot = p->zRoot; + if( zRoot==0 ) zRoot = "$"; + sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC); break; } case JEACH_JSON: { - if( p->sParse.zJson==0 ){ - sqlite3_result_blob(ctx, p->sParse.aBlob, p->sParse.nBlob, - SQLITE_TRANSIENT); - }else{ - sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_TRANSIENT); - } + assert( i==JEACH_JSON ); + sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC); break; } } @@ -210030,13 +199733,6 @@ 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 */ @@ -210071,97 +199767,78 @@ static int jsonEachFilter( int argc, sqlite3_value **argv ){ JsonEachCursor *p = (JsonEachCursor*)cur; + const char *z; const char *zRoot = 0; - u32 i, n, sz; + sqlite3_int64 n; UNUSED_PARAMETER(idxStr); UNUSED_PARAMETER(argc); jsonEachCursorReset(p); if( idxNum==0 ) return SQLITE_OK; - memset(&p->sParse, 0, sizeof(p->sParse)); - p->sParse.nJPRef = 1; - p->sParse.db = p->db; - if( jsonFuncArgMightBeBinary(argv[0]) ){ - p->sParse.nBlob = sqlite3_value_bytes(argv[0]); - p->sParse.aBlob = (u8*)sqlite3_value_blob(argv[0]); - }else{ - p->sParse.zJson = (char*)sqlite3_value_text(argv[0]); - p->sParse.nJson = sqlite3_value_bytes(argv[0]); - if( p->sParse.zJson==0 ){ - p->i = p->iEnd = 0; - return SQLITE_OK; + z = (const char*)sqlite3_value_text(argv[0]); + if( z==0 ) return SQLITE_OK; + n = sqlite3_value_bytes(argv[0]); + p->zJson = sqlite3_malloc64( n+1 ); + if( p->zJson==0 ) return SQLITE_NOMEM; + memcpy(p->zJson, z, (size_t)n+1); + if( jsonParse(&p->sParse, 0, p->zJson) ){ + int rc = SQLITE_NOMEM; + if( p->sParse.oom==0 ){ + sqlite3_free(cur->pVtab->zErrMsg); + cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON"); + if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR; } - if( jsonConvertTextToBlob(&p->sParse, 0) ){ - if( p->sParse.oom ){ - return SQLITE_NOMEM; + jsonEachCursorReset(p); + return rc; + }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){ + jsonEachCursorReset(p); + return SQLITE_NOMEM; + }else{ + JsonNode *pNode = 0; + if( idxNum==3 ){ + const char *zErr = 0; + zRoot = (const char*)sqlite3_value_text(argv[1]); + if( zRoot==0 ) return SQLITE_OK; + n = sqlite3_value_bytes(argv[1]); + p->zRoot = sqlite3_malloc64( n+1 ); + if( p->zRoot==0 ) return SQLITE_NOMEM; + memcpy(p->zRoot, zRoot, (size_t)n+1); + if( zRoot[0]!='$' ){ + zErr = zRoot; + }else{ + pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr); } - goto json_each_malformed_input; - } - } - if( idxNum==3 ){ - zRoot = (const char*)sqlite3_value_text(argv[1]); - if( zRoot==0 ) return SQLITE_OK; - if( zRoot[0]!='$' ){ - sqlite3_free(cur->pVtab->zErrMsg); - cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot); - jsonEachCursorReset(p); - return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; - } - p->nRoot = 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; - } + if( zErr ){ sqlite3_free(cur->pVtab->zErrMsg); - cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot); + cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr); jsonEachCursorReset(p); return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; + }else if( pNode==0 ){ + return SQLITE_OK; } - if( p->sParse.iLabel ){ - p->i = p->sParse.iLabel; - p->eType = JSONB_OBJECT; + }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--; + } }else{ - 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 = 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; + p->i++; + } + }else{ + p->iEnd = p->i+1; + } } return SQLITE_OK; - -json_each_malformed_input: - sqlite3_free(cur->pVtab->zErrMsg); - cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON"); - jsonEachCursorReset(p); - return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; } /* The methods of the json_each virtual table */ @@ -210189,8 +199866,7 @@ static sqlite3_module jsonEachModule = { 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - 0, /* xShadowName */ - 0 /* xIntegrity */ + 0 /* xShadowName */ }; /* The methods of the json_tree virtual table. */ @@ -210218,8 +199894,7 @@ static sqlite3_module jsonTreeModule = { 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - 0, /* xShadowName */ - 0 /* xIntegrity */ + 0 /* xShadowName */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ #endif /* !defined(SQLITE_OMIT_JSON) */ @@ -210230,59 +199905,33 @@ static sqlite3_module jsonTreeModule = { SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void){ #ifndef SQLITE_OMIT_JSON static FuncDef aJsonFunc[] = { - /* sqlite3_result_subtype() ----, ,--- 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), + 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), #if SQLITE_DEBUG - JFUNCTION(json_parse, 1,1,0, 0,0,0, jsonParseFunc), + JFUNCTION(json_parse, 1, 0, jsonParseFunc), + JFUNCTION(json_test1, 1, 0, jsonTest1Func), #endif WAGGREGATE(json_group_array, 1, 0, 0, jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse, - 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), + SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS), WAGGREGATE(json_group_object, 2, 0, 0, jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse, - 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) + SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS) }; sqlite3InsertBuiltinFuncs(aJsonFunc, ArraySize(aJsonFunc)); #endif @@ -210409,11 +200058,6 @@ 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 */ /* #include */ /* #include */ @@ -210479,7 +200123,6 @@ 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 */ @@ -210492,6 +200135,7 @@ 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 */ sqlite3_blob *pNodeBlob; @@ -210788,23 +200432,17 @@ struct RtreeMatchArg { ** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined ** at run-time. */ -#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 +#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 #endif @@ -210825,7 +200463,7 @@ static int readInt16(u8 *p){ return (p[0]<<8) + p[1]; } static void readCoord(u8 *p, RtreeCoord *pCoord){ - assert( FOUR_BYTE_ALIGNED(p) ); + assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */ #if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 pCoord->u = _byteswap_ulong(*(u32*)p); #elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 @@ -210879,7 +200517,7 @@ static void writeInt16(u8 *p, int i){ } static int writeCoord(u8 *p, RtreeCoord *pCoord){ u32 i; - assert( FOUR_BYTE_ALIGNED(p) ); + assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */ assert( sizeof(RtreeCoord)==4 ); assert( sizeof(u32)==4 ); #if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 @@ -211007,9 +200645,11 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){ ** Clear the Rtree.pNodeBlob object */ static void nodeBlobReset(Rtree *pRtree){ - sqlite3_blob *pBlob = pRtree->pNodeBlob; - pRtree->pNodeBlob = 0; - sqlite3_blob_close(pBlob); + if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){ + sqlite3_blob *pBlob = pRtree->pNodeBlob; + pRtree->pNodeBlob = 0; + sqlite3_blob_close(pBlob); + } } /* @@ -211028,7 +200668,7 @@ static int nodeAcquire( ** increase its reference count and return it. */ if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){ - if( pParent && ALWAYS(pParent!=pNode->pParent) ){ + if( pParent && pParent!=pNode->pParent ){ RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } @@ -211048,11 +200688,14 @@ static int nodeAcquire( } } if( pRtree->pNodeBlob==0 ){ - rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, pRtree->zNodeName, - "data", iNode, 0, + char *zTab = sqlite3_mprintf("%s_node", pRtree->zName); + if( zTab==0 ) return SQLITE_NOMEM; + rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, zTab, "data", iNode, 0, &pRtree->pNodeBlob); + sqlite3_free(zTab); } if( rc ){ + nodeBlobReset(pRtree); *ppNode = 0; /* If unable to open an sqlite3_blob on the desired row, that can only ** be because the shadow tables hold erroneous data. */ @@ -211112,7 +200755,6 @@ static int nodeAcquire( } *ppNode = pNode; }else{ - nodeBlobReset(pRtree); if( pNode ){ pRtree->nNodeRef--; sqlite3_free(pNode); @@ -211257,7 +200899,6 @@ static void nodeGetCoord( int iCoord, /* Which coordinate to extract */ RtreeCoord *pCoord /* OUT: Space to write result to */ ){ - assert( iCellzData[12 + pRtree->nBytesPerCell*iCell + 4*iCoord], pCoord); } @@ -211447,9 +201088,7 @@ static int rtreeClose(sqlite3_vtab_cursor *cur){ sqlite3_finalize(pCsr->pReadAux); sqlite3_free(pCsr); pRtree->nCursor--; - if( pRtree->nCursor==0 && pRtree->inWrTrans==0 ){ - nodeBlobReset(pRtree); - } + nodeBlobReset(pRtree); return SQLITE_OK; } @@ -211606,7 +201245,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( FOUR_BYTE_ALIGNED(pCellData) ); + assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */ switch( p->op ){ case RTREE_TRUE: return; /* Always satisfied */ case RTREE_FALSE: break; /* Never satisfied */ @@ -211659,7 +201298,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( FOUR_BYTE_ALIGNED(pCellData) ); + assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */ RTREE_DECODE_COORD(eInt, pCellData, xN); switch( p->op ){ case RTREE_TRUE: return; /* Always satisfied */ @@ -212034,11 +201673,7 @@ static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){ int rc = SQLITE_OK; RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); if( rc==SQLITE_OK && ALWAYS(p) ){ - if( p->iCell>=NCELL(pNode) ){ - rc = SQLITE_ABORT; - }else{ - *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell); - } + *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell); } return rc; } @@ -212056,7 +201691,6 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ if( rc ) return rc; if( NEVER(p==0) ) return SQLITE_OK; - if( p->iCell>=NCELL(pNode) ) return SQLITE_ABORT; if( i==0 ){ sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell)); }else if( i<=pRtree->nDim2 ){ @@ -212154,8 +201788,6 @@ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){ return SQLITE_OK; } -SQLITE_PRIVATE int sqlite3IntFloatCompare(i64,double); - /* ** Rtree virtual table module xFilter method. */ @@ -212185,8 +201817,7 @@ static int rtreeFilter( i64 iNode = 0; int eType = sqlite3_value_numeric_type(argv[0]); if( eType==SQLITE_INTEGER - || (eType==SQLITE_FLOAT - && 0==sqlite3IntFloatCompare(iRowid,sqlite3_value_double(argv[0]))) + || (eType==SQLITE_FLOAT && sqlite3_value_double(argv[0])==iRowid) ){ rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode); }else{ @@ -212237,20 +201868,7 @@ static int rtreeFilter( p->pInfo->nCoord = pRtree->nDim2; p->pInfo->anQueue = pCsr->anQueue; p->pInfo->mxLevel = pRtree->iDepth + 1; - }else if( eType==SQLITE_INTEGER ){ - sqlite3_int64 iVal = sqlite3_value_int64(argv[ii]); -#ifdef SQLITE_RTREE_INT_ONLY - p->u.rValue = iVal; -#else - p->u.rValue = (double)iVal; - if( iVal>=((sqlite3_int64)1)<<48 - || iVal<=-(((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 ){ + }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ #ifdef SQLITE_RTREE_INT_ONLY p->u.rValue = sqlite3_value_int64(argv[ii]); #else @@ -212381,12 +201999,11 @@ static int rtreeBestIndex(sqlite3_vtab *tab, 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; doOmit = 0; break; - case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; doOmit = 0; break; + case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break; + case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break; case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break; - case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; doOmit = 0; break; + case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break; case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break; case SQLITE_INDEX_CONSTRAINT_MATCH: op = RTREE_MATCH; break; default: op = 0; break; @@ -212395,19 +202012,15 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ zIdxStr[iIdx++] = op; zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0'); pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2); - pIdxInfo->aConstraintUsage[ii].omit = doOmit; + pIdxInfo->aConstraintUsage[ii].omit = 1; } } } pIdxInfo->idxNum = 2; pIdxInfo->needToFreeIdxStr = 1; - if( iIdx>0 ){ - pIdxInfo->idxStr = sqlite3_malloc( iIdx+1 ); - if( pIdxInfo->idxStr==0 ){ - return SQLITE_NOMEM; - } - memcpy(pIdxInfo->idxStr, zIdxStr, iIdx+1); + if( iIdx>0 && 0==(pIdxInfo->idxStr = sqlite3_mprintf("%s", zIdxStr)) ){ + return SQLITE_NOMEM; } nRow = pRtree->nRowEst >> (iIdx/2); @@ -212486,22 +202099,31 @@ static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){ */ static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){ int ii; - if( pRtree->eCoordType==RTREE_COORD_INT32 ){ - for(ii=0; iinDim2; ii+=2){ - RtreeCoord *a1 = &p1->aCoord[ii]; - RtreeCoord *a2 = &p2->aCoord[ii]; - if( a2[0].ia1[1].i ) return 0; - } - }else{ - for(ii=0; iinDim2; ii+=2){ - RtreeCoord *a1 = &p1->aCoord[ii]; - RtreeCoord *a2 = &p2->aCoord[ii]; - if( a2[0].fa1[1].f ) return 0; + int isInt = (pRtree->eCoordType==RTREE_COORD_INT32); + for(ii=0; iinDim2; ii+=2){ + RtreeCoord *a1 = &p1->aCoord[ii]; + RtreeCoord *a2 = &p2->aCoord[ii]; + if( (!isInt && (a2[0].fa1[1].f)) + || ( isInt && (a2[0].ia1[1].i)) + ){ + 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, @@ -212548,52 +202170,38 @@ static int ChooseLeaf( for(ii=0; rc==SQLITE_OK && ii<(pRtree->iDepth-iHeight); ii++){ int iCell; sqlite3_int64 iBest = 0; - int bFound = 0; + RtreeDValue fMinGrowth = RTREE_ZERO; RtreeDValue fMinArea = RTREE_ZERO; + int nCell = NCELL(pNode); + RtreeCell cell; RtreeNode *pChild = 0; - /* 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. + 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. */ for(iCell=0; iCell1 ){ + 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( iLeftnDim; iDim++){ + aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2]); + aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2+1]); + } + } + for(iDim=0; iDimnDim; iDim++){ + aCenterCoord[iDim] = (aCenterCoord[iDim]/(nCell*(RtreeDValue)2)); + } + + for(ii=0; iinDim; 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 && iiiNode 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; + } + } + } + + 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). @@ -213170,7 +202950,12 @@ static int rtreeInsertCell( } } if( nodeInsertCell(pRtree, pNode, pCell) ){ - rc = SplitNode(pRtree, pNode, pCell, iHeight); + if( iHeight<=pRtree->iReinsertHeight || pNode->iNode==1){ + rc = SplitNode(pRtree, pNode, pCell, iHeight); + }else{ + pRtree->iReinsertHeight = iHeight; + rc = Reinsert(pRtree, pNode, pCell, iHeight); + } }else{ rc = AdjustTree(pRtree, pNode, pCell); if( ALWAYS(rc==SQLITE_OK) ){ @@ -213513,6 +203298,7 @@ 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 ){ @@ -213542,7 +203328,7 @@ constraint: static int rtreeBeginTransaction(sqlite3_vtab *pVtab){ Rtree *pRtree = (Rtree *)pVtab; assert( pRtree->inWrTrans==0 ); - pRtree->inWrTrans = 1; + pRtree->inWrTrans++; return SQLITE_OK; } @@ -213556,9 +203342,6 @@ static int rtreeEndTransaction(sqlite3_vtab *pVtab){ nodeBlobReset(pRtree); return SQLITE_OK; } -static int rtreeRollback(sqlite3_vtab *pVtab){ - return rtreeEndTransaction(pVtab); -} /* ** The xRename method for rtree module virtual tables. @@ -213656,11 +203439,8 @@ static int rtreeShadowName(const char *zName){ return 0; } -/* Forward declaration */ -static int rtreeIntegrity(sqlite3_vtab*, const char*, const char*, int, char**); - static sqlite3_module rtreeModule = { - 4, /* iVersion */ + 3, /* iVersion */ rtreeCreate, /* xCreate - create a table */ rtreeConnect, /* xConnect - connect to an existing table */ rtreeBestIndex, /* xBestIndex - Determine search strategy */ @@ -213677,14 +203457,13 @@ static sqlite3_module rtreeModule = { rtreeBeginTransaction, /* xBegin - begin transaction */ rtreeEndTransaction, /* xSync - sync transaction */ rtreeEndTransaction, /* xCommit - commit transaction */ - rtreeRollback, /* xRollback - rollback transaction */ + rtreeEndTransaction, /* xRollback - rollback transaction */ 0, /* xFindFunction - function overloading */ rtreeRename, /* xRename - rename the table */ rtreeSavepoint, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - rtreeShadowName, /* xShadowName */ - rtreeIntegrity /* xIntegrity */ + rtreeShadowName /* xShadowName */ }; static int rtreeSqlInit( @@ -213777,7 +203556,7 @@ static int rtreeSqlInit( } sqlite3_free(zSql); } - if( pRtree->nAux && rc!=SQLITE_NOMEM ){ + if( pRtree->nAux ){ pRtree->zReadAuxSql = sqlite3_mprintf( "SELECT * FROM \"%w\".\"%w_rowid\" WHERE rowid=?1", zDb, zPrefix); @@ -213940,27 +203719,22 @@ static int rtreeInit( } sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); - sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); - /* Allocate the sqlite3_vtab structure */ nDb = (int)strlen(argv[1]); nName = (int)strlen(argv[2]); - pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName*2+8); + pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2); if( !pRtree ){ return SQLITE_NOMEM; } - memset(pRtree, 0, sizeof(Rtree)+nDb+nName*2+8); + memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2); 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 @@ -214457,6 +204231,7 @@ static int rtreeCheckTable( ){ RtreeCheck check; /* Common context for various routines */ 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 */ @@ -214465,14 +204240,24 @@ 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( sqlite3_get_autocommit(db) ){ + check.rc = sqlite3_exec(db, "BEGIN", 0, 0, 0); + bEnd = 1; + } + /* Find the number of auxiliary columns */ - pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab); - if( pStmt ){ - nAux = sqlite3_column_count(pStmt) - 2; - sqlite3_finalize(pStmt); - }else - if( check.rc!=SQLITE_NOMEM ){ - check.rc = SQLITE_OK; + if( check.rc==SQLITE_OK ){ + pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab); + if( pStmt ){ + nAux = sqlite3_column_count(pStmt) - 2; + sqlite3_finalize(pStmt); + }else + if( check.rc!=SQLITE_NOMEM ){ + check.rc = SQLITE_OK; + } } /* Find number of dimensions in the rtree table. */ @@ -214503,35 +204288,15 @@ static int rtreeCheckTable( sqlite3_finalize(check.aCheckMapping[0]); sqlite3_finalize(check.aCheckMapping[1]); + /* If one was opened, close the transaction */ + if( bEnd ){ + int rc = 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( - 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 = sqlite3_mprintf("In RTree %s.%s:\n%z", - pRtree->zDb, pRtree->zName, *pzErr); - if( (*pzErr)==0 ) rc = SQLITE_NOMEM; - } - return rc; -} - /* ** Usage: ** @@ -214905,7 +204670,7 @@ static GeoPoly *geopolyFuncParam( int nByte; testcase( pCtx==0 ); if( sqlite3_value_type(pVal)==SQLITE_BLOB - && (nByte = sqlite3_value_bytes(pVal))>=(int)(4+6*sizeof(GeoCoord)) + && (nByte = sqlite3_value_bytes(pVal))>=(4+6*sizeof(GeoCoord)) ){ const unsigned char *a = sqlite3_value_blob(pVal); int nVertex; @@ -214963,7 +204728,6 @@ static void geopolyBlobFunc( sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); - (void)argc; if( p ){ sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); @@ -214983,7 +204747,6 @@ static void geopolyJsonFunc( sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); - (void)argc; if( p ){ sqlite3 *db = sqlite3_context_db_handle(context); sqlite3_str *x = sqlite3_str_new(db); @@ -215065,7 +204828,6 @@ static void geopolyXformFunc( double F = sqlite3_value_double(argv[6]); GeoCoord x1, y1, x0, y0; int ii; - (void)argc; if( p ){ for(ii=0; iinVertex; ii++){ x0 = GeoX(p,ii); @@ -215116,7 +204878,6 @@ static void geopolyAreaFunc( sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); - (void)argc; if( p ){ sqlite3_result_double(context, geopolyArea(p)); sqlite3_free(p); @@ -215142,7 +204903,6 @@ static void geopolyCcwFunc( sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); - (void)argc; if( p ){ if( geopolyArea(p)<0.0 ){ int ii, jj; @@ -215197,7 +204957,6 @@ static void geopolyRegularFunc( int n = sqlite3_value_int(argv[3]); int i; GeoPoly *p; - (void)argc; if( n<3 || r<=0.0 ) return; if( n>1000 ) n = 1000; @@ -215307,7 +205066,6 @@ static void geopolyBBoxFunc( sqlite3_value **argv ){ GeoPoly *p = geopolyBBox(context, argv[0], 0, 0); - (void)argc; if( p ){ sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); @@ -215335,7 +205093,6 @@ 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; @@ -215424,8 +205181,6 @@ static void geopolyContainsPointFunc( int v = 0; int cnt = 0; int ii; - (void)argc; - if( p1==0 ) return; for(ii=0; iinVertex-1; ii++){ v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii), @@ -215465,7 +205220,6 @@ 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 ){ @@ -215796,7 +205550,6 @@ 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 ){ @@ -215817,12 +205570,8 @@ static void geopolyDebugFunc( int argc, sqlite3_value **argv ){ - (void)context; - (void)argc; #ifdef GEOPOLY_ENABLE_DEBUG geo_debug = sqlite3_value_int(argv[0]); -#else - (void)argv; #endif } @@ -215850,31 +205599,26 @@ static int geopolyInit( sqlite3_str *pSql; char *zSql; int ii; - (void)pAux; sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); - sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); /* Allocate the sqlite3_vtab structure */ nDb = strlen(argv[1]); nName = strlen(argv[2]); - pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName*2+8); + pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2); if( !pRtree ){ return SQLITE_NOMEM; } - memset(pRtree, 0, sizeof(Rtree)+nDb+nName*2+8); + memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2); 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 @@ -215971,7 +205715,6 @@ static int geopolyFilter( RtreeNode *pRoot = 0; int rc = SQLITE_OK; int iCell = 0; - (void)idxStr; rtreeReference(pRtree); @@ -216098,7 +205841,6 @@ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int iRowidTerm = -1; int iFuncTerm = -1; int idxNum = 0; - (void)tab; for(ii=0; iinConstraint; ii++){ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; @@ -216288,6 +206030,7 @@ 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 ){ @@ -216344,8 +206087,6 @@ static int geopolyFindFunction( void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg ){ - (void)pVtab; - (void)nArg; if( sqlite3_stricmp(zName, "geopoly_overlap")==0 ){ *pxFunc = geopolyOverlapFunc; *ppArg = 0; @@ -216384,8 +206125,7 @@ static sqlite3_module geopolyModule = { rtreeSavepoint, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - rtreeShadowName, /* xShadowName */ - rtreeIntegrity /* xIntegrity */ + rtreeShadowName /* xShadowName */ }; static int sqlite3_geopoly_init(sqlite3 *db){ @@ -216416,7 +206156,7 @@ static int sqlite3_geopoly_init(sqlite3 *db){ } aAgg[] = { { geopolyBBoxStep, geopolyBBoxFinal, "geopoly_group_bbox" }, }; - unsigned int i; + int i; for(i=0; i=sizeof(aStrength)/sizeof(aStrength[0]) ){ - sqlite3_str *pStr = sqlite3_str_new(sqlite3_context_db_handle(p)); - sqlite3_str_appendf(pStr, - "unknown collation strength \"%s\" - should be one of:", - zOption); - for(i=0; i naming scheme. +** tables or view named using the data_ naming scheme. ** ** Instead of the plain data_ naming scheme, RBU database tables ** may also be named data_, where is any sequence @@ -217683,7 +207390,7 @@ SQLITE_PRIVATE void 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 table's implicit primary +** named "rbu_rowid". This column is mapped to the tables implicit primary ** key column - "rowid". Virtual tables for which the "rowid" column does ** not function like a primary key value cannot be updated using RBU. For ** example, if the target db contains either of the following: @@ -218317,7 +208024,6 @@ typedef unsigned int u32; typedef unsigned short u16; typedef unsigned char u8; typedef sqlite3_int64 i64; -typedef sqlite3_uint64 u64; #endif /* @@ -219004,7 +208710,6 @@ static int rbuObjIterNext(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*)sqlite3_column_text(pIter->pTblIter, 0); pIter->zDataTbl = (const char*)sqlite3_column_text(pIter->pTblIter,1); @@ -221099,7 +210804,7 @@ static i64 rbuShmChecksum(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)(((u64)ptr[10] << 32) + ptr[11]); + iRet = ((i64)ptr[10] << 32) + ptr[11]; } } return iRet; @@ -221151,11 +210856,11 @@ static void rbuSetupCheckpoint(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_NOTICE + ** * Attempting to xSync() the database file causes an SQLITE_INTERNAL ** error. ** ** As a result, unless an error (i.e. OOM or SQLITE_BUSY) occurs, the - ** checkpoint below fails with SQLITE_NOTICE, and leaves the aFrame[] + ** checkpoint below fails with SQLITE_INTERNAL, and leaves the aFrame[] ** array populated with a set of (frame -> page) mappings. Because the ** WRITER, CHECKPOINT and READ0 locks are still held, it is safe to copy ** data from the wal file into the database file according to the @@ -221165,7 +210870,7 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){ int rc2; p->eStage = RBU_STAGE_CAPTURE; rc2 = sqlite3_exec(p->dbMain, "PRAGMA main.wal_checkpoint=restart", 0, 0,0); - if( rc2!=SQLITE_NOTICE ) p->rc = rc2; + if( rc2!=SQLITE_INTERNAL ) p->rc = rc2; } if( p->rc==SQLITE_OK && p->nFrame>0 ){ @@ -221211,7 +210916,7 @@ static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){ if( pRbu->mLock!=mReq ){ pRbu->rc = SQLITE_BUSY; - return SQLITE_NOTICE_RBU; + return SQLITE_INTERNAL; } pRbu->pgsz = iAmt; @@ -221261,11 +210966,6 @@ static void rbuCheckpointFrame(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 @@ -221274,20 +210974,9 @@ static void rbuCheckpointFrame(sqlite3rbu *p, RbuFrame *pFrame){ static int rbuLockDatabase(sqlite3 *db){ int rc = SQLITE_OK; sqlite3_file *fd = 0; + sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd); - sqlite3_file_control(db, "main", RBU_ZIPVFS_CTRL_FILE_POINTER, &fd); - if( fd ){ - 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); - } - sqlite3_file_control(db, "main", RBU_ZIPVFS_CTRL_FILE_POINTER, &fd); - }else{ - sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd); - } - - if( rc==SQLITE_OK && fd->pMethods ){ + if( fd->pMethods ){ rc = fd->pMethods->xLock(fd, SQLITE_LOCK_SHARED); if( rc==SQLITE_OK ){ rc = fd->pMethods->xLock(fd, SQLITE_LOCK_EXCLUSIVE); @@ -221966,8 +211655,7 @@ static void rbuSetupOal(sqlite3rbu *p, RbuState *pState){ static void rbuDeleteOalFile(sqlite3rbu *p){ char *zOal = rbuMPrintf(p, "%s-oal", p->zTarget); if( zOal ){ - sqlite3_vfs *pVfs = 0; - sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_VFS_POINTER, &pVfs); + sqlite3_vfs *pVfs = sqlite3_vfs_find(0); assert( pVfs && p->rc==SQLITE_OK && p->zErrmsg==0 ); pVfs->xDelete(pVfs, zOal, 0); sqlite3_free(zOal); @@ -222615,7 +212303,7 @@ SQLITE_API void sqlite3rbu_rename_handler( ** 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_NOTICE errors. +** file fail with SQLITE_INTERNAL errors. */ static void rbuUnlockShm(rbu_file *p){ @@ -222724,12 +212412,9 @@ static int rbuVfsClose(sqlite3_file *pFile){ sqlite3_free(p->zDel); if( p->openFlags & SQLITE_OPEN_MAIN_DB ){ - const sqlite3_io_methods *pMeth = p->pReal->pMethods; rbuMainlistRemove(p); rbuUnlockShm(p); - if( pMeth->iVersion>1 && pMeth->xShmUnmap ){ - pMeth->xShmUnmap(p->pReal, 0); - } + p->pReal->pMethods->xShmUnmap(p->pReal, 0); } else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){ rbuUpdateTempSize(p, 0); @@ -222897,7 +212582,7 @@ static int rbuVfsSync(sqlite3_file *pFile, int flags){ rbu_file *p = (rbu_file *)pFile; if( p->pRbu && p->pRbu->eStage==RBU_STAGE_CAPTURE ){ if( p->openFlags & SQLITE_OPEN_MAIN_DB ){ - return SQLITE_NOTICE_RBU; + return SQLITE_INTERNAL; } return SQLITE_OK; } @@ -223188,25 +212873,6 @@ static int rbuVfsOpen( rbuVfsShmUnmap, /* xShmUnmap */ 0, 0 /* xFetch, xUnfetch */ }; - static 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; sqlite3_vfs *pRealVfs = pRbuVfs->pRealVfs; rbu_file *pFd = (rbu_file *)pFile; @@ -223261,15 +212927,10 @@ static int rbuVfsOpen( rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, oflags, pOutFlags); } if( pFd->pReal->pMethods ){ - const sqlite3_io_methods *pMeth = pFd->pReal->pMethods; /* The xOpen() operation has succeeded. Set the sqlite3_file.pMethods ** pointer and, if the file is a main database file, link it into the ** mutex protected linked list of all such files. */ - if( pMeth->iVersion<2 || pMeth->xShmLock==0 ){ - pFile->pMethods = &rbuvfs_io_methods1; - }else{ - pFile->pMethods = &rbuvfs_io_methods; - } + pFile->pMethods = &rbuvfs_io_methods; if( flags & SQLITE_OPEN_MAIN_DB ){ rbuMainlistAdd(pFd); } @@ -223702,7 +213363,6 @@ static int statConnect( StatTable *pTab = 0; int rc = SQLITE_OK; int iDb; - (void)pAux; if( argc>=4 ){ Token nm; @@ -223756,7 +213416,6 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ 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 @@ -224282,8 +213941,6 @@ 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); sqlite3_finalize(pCsr->pStmt); @@ -224367,16 +214024,16 @@ static int statColumn( } break; case 4: /* ncell */ - sqlite3_result_int64(ctx, pCsr->nCell); + sqlite3_result_int(ctx, pCsr->nCell); break; case 5: /* payload */ - sqlite3_result_int64(ctx, pCsr->nPayload); + sqlite3_result_int(ctx, pCsr->nPayload); break; case 6: /* unused */ - sqlite3_result_int64(ctx, pCsr->nUnused); + sqlite3_result_int(ctx, pCsr->nUnused); break; case 7: /* mx_payload */ - sqlite3_result_int64(ctx, pCsr->nMxPayload); + sqlite3_result_int(ctx, pCsr->nMxPayload); break; case 8: /* pgoffset */ if( !pCsr->isAgg ){ @@ -224384,7 +214041,7 @@ static int statColumn( } break; case 9: /* pgsize */ - sqlite3_result_int64(ctx, pCsr->szPage); + sqlite3_result_int(ctx, pCsr->szPage); break; case 10: { /* schema */ sqlite3 *db = sqlite3_context_db_handle(ctx); @@ -224434,8 +214091,7 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - 0, /* xShadowName */ - 0 /* xIntegrity */ + 0 /* xShadowName */ }; return sqlite3_create_module(db, "dbstat", &dbstat_module, 0); } @@ -224519,13 +214175,8 @@ static int dbpageConnect( ){ DbpageTable *pTab = 0; int rc = SQLITE_OK; - (void)pAux; - (void)argc; - (void)argv; - (void)pzErr; sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY); - sqlite3_vtab_config(db, SQLITE_VTAB_USES_ALL_SCHEMAS); rc = sqlite3_declare_vtab(db, "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)"); if( rc==SQLITE_OK ){ @@ -224562,7 +214213,6 @@ static int dbpageDisconnect(sqlite3_vtab *pVtab){ static int dbpageBestIndex(sqlite3_vtab *tab, 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 @@ -224609,6 +214259,7 @@ static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ ){ pIdxInfo->orderByConsumed = 1; } + sqlite3VtabUsesAllSchemas(pIdxInfo); return SQLITE_OK; } @@ -224677,8 +214328,6 @@ static int dbpageFilter( sqlite3 *db = pTab->db; Btree *pBt; - (void)idxStr; - /* Default setting is no rows of result */ pCsr->pgno = 1; pCsr->mxPgno = 0; @@ -224693,7 +214342,7 @@ static int dbpageFilter( pCsr->iDb = 0; } pBt = db->aDb[pCsr->iDb].pBt; - if( NEVER(pBt==0) ) return SQLITE_OK; + if( pBt==0 ) return SQLITE_OK; pCsr->pPager = sqlite3BtreePager(pBt); pCsr->szPage = sqlite3BtreeGetPageSize(pBt); pCsr->mxPgno = sqlite3BtreeLastPage(pBt); @@ -224774,7 +214423,6 @@ static int dbpageUpdate( Pager *pPager; int szPage; - (void)pRowid; if( pTab->db->flags & SQLITE_Defensive ){ zErr = "read-only"; goto update_fail; @@ -224784,20 +214432,18 @@ static int dbpageUpdate( goto update_fail; } pgno = sqlite3_value_int(argv[0]); - if( sqlite3_value_type(argv[0])==SQLITE_NULL - || (Pgno)sqlite3_value_int(argv[1])!=pgno - ){ + if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){ zErr = "cannot insert"; goto update_fail; } zSchema = (const char*)sqlite3_value_text(argv[4]); - iDb = ALWAYS(zSchema) ? sqlite3FindDbName(pTab->db, zSchema) : -1; - if( NEVER(iDb<0) ){ + iDb = zSchema ? sqlite3FindDbName(pTab->db, zSchema) : -1; + 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>sqlite3BtreeLastPage(pBt)) ){ + if( pgno<1 || pBt==0 || pgno>sqlite3BtreeLastPage(pBt) ){ zErr = "bad page number"; goto update_fail; } @@ -224836,11 +214482,12 @@ static int dbpageBegin(sqlite3_vtab *pVtab){ DbpageTable *pTab = (DbpageTable *)pVtab; sqlite3 *db = pTab->db; int i; - for(i=0; inDb; i++){ + int rc = SQLITE_OK; + for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; - if( pBt ) (void)sqlite3BtreeBeginTrans(pBt, 1, 0); + if( pBt ) rc = sqlite3BtreeBeginTrans(pBt, 1, 0); } - return SQLITE_OK; + return rc; } @@ -224872,8 +214519,7 @@ SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ - 0, /* xShadowName */ - 0 /* xIntegrity */ + 0 /* xShadowName */ }; return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0); } @@ -224910,8 +214556,6 @@ typedef struct SessionInput SessionInput; # endif #endif -#define SESSIONS_ROWID "_rowid_" - static int sessions_strm_chunk_size = SESSIONS_STRM_CHUNK_SIZE; typedef struct SessionHook SessionHook; @@ -224933,7 +214577,6 @@ struct 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); @@ -225004,32 +214647,17 @@ struct 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 sqlite3changegroup_xxx() APIs, not by -** regular 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 */ - sqlite3_stmt *pDfltStmt; }; /* @@ -225198,7 +214826,6 @@ 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 */ @@ -225224,7 +214851,7 @@ static int sessionVarintLen(int iVal){ ** Read a varint value from aBuf[] into *piVal. Return the number of ** bytes read. */ -static int sessionVarintGet(const u8 *aBuf, int *piVal){ +static int sessionVarintGet(u8 *aBuf, int *piVal){ return getVarint32(aBuf, *piVal); } @@ -225418,7 +215045,6 @@ static unsigned int sessionHashAppendType(unsigned int h, int eType){ */ static int sessionPreupdateHash( 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 */ @@ -225427,53 +215053,48 @@ static int sessionPreupdateHash( unsigned int h = 0; /* Hash value to return */ int i; /* Used to iterate through columns */ - 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; inCol; i++){ - if( pTab->abPK[i] ){ - int rc; - int eType; - sqlite3_value *pVal; + assert( *pbNullPK==0 ); + assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) ); + for(i=0; inCol; i++){ + if( pTab->abPK[i] ){ + int rc; + int eType; + sqlite3_value *pVal; - if( bNew ){ - rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal); + if( bNew ){ + rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal); + }else{ + rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal); + } + if( rc!=SQLITE_OK ) return rc; + + eType = sqlite3_value_type(pVal); + h = sessionHashAppendType(h, eType); + if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ + i64 iVal; + if( eType==SQLITE_INTEGER ){ + iVal = sqlite3_value_int64(pVal); }else{ - rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal); + double rVal = sqlite3_value_double(pVal); + assert( sizeof(iVal)==8 && sizeof(rVal)==8 ); + memcpy(&iVal, &rVal, 8); } - if( rc!=SQLITE_OK ) return rc; - - eType = sqlite3_value_type(pVal); - h = sessionHashAppendType(h, eType); - if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ - i64 iVal; - if( eType==SQLITE_INTEGER ){ - iVal = sqlite3_value_int64(pVal); - }else{ - double rVal = sqlite3_value_double(pVal); - assert( sizeof(iVal)==8 && sizeof(rVal)==8 ); - memcpy(&iVal, &rVal, 8); - } - h = sessionHashAppendI64(h, iVal); - }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ - const u8 *z; - int n; - if( eType==SQLITE_TEXT ){ - z = (const u8 *)sqlite3_value_text(pVal); - }else{ - z = (const u8 *)sqlite3_value_blob(pVal); - } - n = sqlite3_value_bytes(pVal); - if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM; - h = sessionHashAppendBlob(h, n, z); + h = sessionHashAppendI64(h, iVal); + }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ + const u8 *z; + int n; + if( eType==SQLITE_TEXT ){ + z = (const u8 *)sqlite3_value_text(pVal); }else{ - assert( eType==SQLITE_NULL ); - assert( pTab->bStat1==0 || i!=1 ); - *pbNullPK = 1; + z = (const u8 *)sqlite3_value_blob(pVal); } + n = sqlite3_value_bytes(pVal); + if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM; + h = sessionHashAppendBlob(h, n, z); + }else{ + assert( eType==SQLITE_NULL ); + assert( pTab->bStat1==0 || i!=1 ); + *pbNullPK = 1; } } } @@ -225487,11 +215108,9 @@ static int sessionPreupdateHash( ** Return the number of bytes of space occupied by the value (including ** the type byte). */ -static int sessionSerialLen(const u8 *a){ - int e; +static int sessionSerialLen(u8 *a){ + int e = *a; 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; @@ -225758,7 +215377,6 @@ static int sessionMergeUpdate( */ static int sessionPreupdateEqual( 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 */ @@ -225766,11 +215384,6 @@ 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; iColnCol; iCol++){ if( !pTab->abPK[iCol] ){ @@ -225793,7 +215406,6 @@ static int sessionPreupdateEqual( rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal); } assert( rc==SQLITE_OK ); - (void)rc; /* Suppress warning about unused variable */ if( sqlite3_value_type(pVal)!=eType ) return 0; /* A SessionChange object never has a NULL value in a PK column */ @@ -225896,14 +215508,13 @@ static int sessionGrowHash( ** ** For example, if the table is declared as: ** -** CREATE TABLE tbl1(w, x DEFAULT 'abc', y, z, PRIMARY KEY(w, z)); +** CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z)); ** -** Then the five output variables are populated as follows: +** Then the four 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 @@ -225917,9 +215528,7 @@ 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 */ - 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 */ + u8 **pabPK /* OUT: Array of booleans - true for PK col */ ){ char *zPragma; sqlite3_stmt *pStmt; @@ -225930,18 +215539,10 @@ 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 = sqlite3Strlen30(zThis); if( nThis==12 && 0==sqlite3_stricmp("sqlite_stat1", zThis) ){ rc = sqlite3_table_column_metadata(db, zDb, zThis, 0, 0, 0, 0, 0, 0); @@ -225955,47 +215556,50 @@ static int sessionTableInfo( }else if( rc==SQLITE_ERROR ){ zPragma = sqlite3_mprintf(""); }else{ + *pazCol = 0; + *pabPK = 0; + *pnCol = 0; + if( pzTab ) *pzTab = 0; return rc; } }else{ zPragma = 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 = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0); 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==sqlite3_step(pStmt) ){ - nByte += sqlite3_column_bytes(pStmt, 1); /* name */ - nByte += sqlite3_column_bytes(pStmt, 4); /* dflt_value */ + nByte += sqlite3_column_bytes(pStmt, 1); nDbCol++; - if( sqlite3_column_int(pStmt, 5) ) bRowid = 0; /* pk */ } - if( nDbCol==0 ) bRowid = 0; - nDbCol += bRowid; - nByte += strlen(SESSIONS_ROWID); rc = sqlite3_reset(pStmt); if( rc==SQLITE_OK ){ - nByte += nDbCol * (sizeof(const char *)*2 + sizeof(u8) + 1 + 1); + nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1); pAlloc = sessionMalloc64(pSession, nByte); if( pAlloc==0 ){ rc = SQLITE_NOMEM; - }else{ - memset(pAlloc, 0, nByte); } } if( rc==SQLITE_OK ){ azCol = (char **)pAlloc; - azDflt = (char**)&azCol[nDbCol]; - pAlloc = (u8 *)&azDflt[nDbCol]; + pAlloc = (u8 *)&azCol[nDbCol]; abPK = (u8 *)pAlloc; pAlloc = &abPK[nDbCol]; if( pzTab ){ @@ -226005,57 +215609,43 @@ 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==sqlite3_step(pStmt) ){ int nName = sqlite3_column_bytes(pStmt, 1); - int nDflt = sqlite3_column_bytes(pStmt, 4); const unsigned char *zName = sqlite3_column_text(pStmt, 1); - const unsigned char *zDflt = 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] = sqlite3_column_int(pStmt, 5); i++; } rc = sqlite3_reset(pStmt); + } /* If successful, populate the output variables. Otherwise, zero them and ** free any allocation made. An error code will be returned in this case. */ if( rc==SQLITE_OK ){ - *pazCol = (const char**)azCol; - if( pazDflt ) *pazDflt = (const char**)azDflt; + *pazCol = (const char **)azCol; *pabPK = abPK; *pnCol = nDbCol; }else{ + *pazCol = 0; + *pabPK = 0; + *pnCol = 0; + if( pzTab ) *pzTab = 0; sessionFree(pSession, azCol); } - if( pbRowid ) *pbRowid = bRowid; sqlite3_finalize(pStmt); return rc; } /* -** 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. +** This function is only called from within a pre-update handler for a +** write to table pTab, part of session pSession. If this is the first +** write to this table, initalize the SessionTable.nCol, azCol[] and +** abPK[] arrays accordingly. ** ** If an error occurs, an error code is stored in sqlite3_session.rc and ** non-zero returned. Or, if no error occurs but the table has no primary @@ -226063,22 +215653,14 @@ static int sessionTableInfo( ** indicate that updates on this table should be ignored. SessionTable.abPK ** is set to NULL in this case. */ -static int sessionInitTable( - sqlite3_session *pSession, /* Optional session handle */ - SessionTable *pTab, /* Table object to initialize */ - sqlite3 *db, /* Database handle to read schema from */ - const char *zDb /* Name of db - "main", "temp" etc. */ -){ - int rc = SQLITE_OK; - +static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){ if( pTab->nCol==0 ){ u8 *abPK; assert( pTab->azCol==0 || pTab->abPK==0 ); - rc = sessionTableInfo(pSession, db, zDb, - pTab->zName, &pTab->nCol, 0, &pTab->azCol, &pTab->azDflt, &abPK, - ((pSession==0 || pSession->bImplicitPK) ? &pTab->bRowid : 0) + pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb, + pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK ); - if( rc==SQLITE_OK ){ + if( pSession->rc==SQLITE_OK ){ int i; for(i=0; inCol; i++){ if( abPK[i] ){ @@ -226090,321 +215672,14 @@ static int sessionInitTable( pTab->bStat1 = 1; } - if( pSession && pSession->bEnableSize ){ + if( pSession->bEnableSize ){ pSession->nMaxChangesetSize += ( 1 + sessionVarintLen(pTab->nCol) + pTab->nCol + strlen(pTab->zName)+1 ); } } } - - if( pSession ){ - pSession->rc = rc; - return (rc || pTab->abPK==0); - } - return rc; -} - -/* -** Re-initialize table object pTab. -*/ -static int sessionReinitTable(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; iinCol ){ - 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); - } - } - } - - 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( - 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 */ - sqlite3_stmt *pDflt /* SELECT */ -){ - SessionChange *pOld = *pp; - - while( pOld->nRecordFieldnRecordField; - int eType = 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 = 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 = sqlite3_column_int64(pDflt, iField); - sessionPutI64(&pNew->aRecord[pNew->nRecord], iVal); - pNew->nRecord += 8; - break; - } - - case SQLITE_FLOAT: { - double rVal = 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 = sqlite3_column_bytes(pDflt, iField); - const char *z = (const char*)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 = sqlite3_column_bytes(pDflt, iField); - const u8 *z = (const u8*)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 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( nNewSESSION_MAX_BUFFER_SZ ){ - nNew = SESSION_MAX_BUFFER_SZ; - if( nNewaBuf, 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 = 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 = sqlite3_vmprintf(zFmt, ap); - if( zApp==0 ){ - *pRc = SQLITE_NOMEM; - }else{ - sessionAppendStr(p, zApp, pRc); - } - va_end(ap); - 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( - sqlite3 *db, /* Database handle */ - SessionTable *pTab, /* Table to prepare statement for */ - 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; iinCol; ii++){ - const char *zDflt = pTab->azDflt[ii] ? pTab->azDflt[ii] : "NULL"; - sessionAppendPrintf(&sql, &rc, "%s%s", zSep, zDflt); - zSep = ", "; - } - if( rc==SQLITE_OK ){ - rc = sqlite3_prepare_v2(db, (const char*)sql.aBuf, -1, ppStmt, 0); - } - 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(sqlite3_session *pSession, SessionTable *pTab){ - sqlite3_stmt *pStmt = 0; - int rc = pSession->rc; - - rc = sessionPrepareDfltStmt(pSession->db, pTab, &pStmt); - if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ - int ii = 0; - SessionChange **pp = 0; - for(ii=0; iinChange; 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 = sqlite3_finalize(pStmt); - if( pSession->rc==SQLITE_OK ) pSession->rc = rc; - return pSession->rc; + return (pSession->rc || pTab->abPK==0); } /* @@ -226455,7 +215730,6 @@ 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; iinCol; ii++){ @@ -226472,16 +215746,12 @@ static int sessionUpdateMaxSize( }else{ int ii; u8 *pCsr = pC->aRecord; - if( pTab->bRowid ){ - nNew += 9 + 1; - pCsr += 9; - } - for(ii=pTab->bRowid; iinCol; ii++){ + for(ii=0; iinCol; ii++){ int bChanged = 1; int nOld = 0; int eType; sqlite3_value *p = 0; - pSession->hook.xNew(pSession->hook.pCtx, ii-pTab->bRowid, &p); + pSession->hook.xNew(pSession->hook.pCtx, ii, &p); if( p==0 ){ return SQLITE_NOMEM; } @@ -226560,29 +215830,22 @@ static int sessionUpdateMaxSize( */ static void sessionPreupdateOneChange( int op, /* One of SQLITE_UPDATE, INSERT, DELETE */ - i64 iRowid, 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, pSession->db, pSession->zDb) ) return; + if( sessionInitTable(pSession, pTab) ) return; /* Check the number of columns in this xPreUpdate call matches the ** number of columns in the table. */ - nExpect = pSession->hook.xCount(pSession->hook.pCtx); - if( (pTab->nCol-pTab->bRowid)nCol-pTab->bRowid)!=nExpect ){ + if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){ pSession->rc = SQLITE_SCHEMA; return; } @@ -226615,16 +215878,14 @@ 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, iRowid, pTab, op==SQLITE_INSERT, &iHash, &bNull - ); + rc = sessionPreupdateHash(pSession, pTab, op==SQLITE_INSERT, &iHash, &bNull); if( rc!=SQLITE_OK ) goto error_out; if( bNull==0 ){ /* Search the hash table for an existing record for this row. */ SessionChange *pC; for(pC=pTab->apChange[iHash]; pC; pC=pC->pNext){ - if( sessionPreupdateEqual(pSession, iRowid, pTab, pC, op) ) break; + if( sessionPreupdateEqual(pSession, pTab, pC, op) ) break; } if( pC==0 ){ @@ -226639,7 +215900,7 @@ static void sessionPreupdateOneChange( /* Figure out how large an allocation is required */ nByte = sizeof(SessionChange); - for(i=0; i<(pTab->nCol-pTab->bRowid); i++){ + for(i=0; inCol; i++){ sqlite3_value *p = 0; if( op!=SQLITE_INSERT ){ TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p); @@ -226654,12 +215915,9 @@ 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; @@ -226673,12 +215931,7 @@ 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; - if( pTab->bRowid ){ - pC->aRecord[0] = SQLITE_INTEGER; - sessionPutI64(&pC->aRecord[1], iRowid); - nByte = 9; - } - for(i=0; i<(pTab->nCol-pTab->bRowid); i++){ + for(i=0; inCol; i++){ sqlite3_value *p = 0; if( op!=SQLITE_INSERT ){ pSession->hook.xOld(pSession->hook.pCtx, i, &p); @@ -226692,7 +215945,6 @@ 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]; @@ -226778,8 +216030,6 @@ static void xPreUpdate( int nDb = sqlite3Strlen30(zDb); assert( sqlite3_mutex_held(db->mutex) ); - (void)iKey1; - (void)iKey2; for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){ SessionTable *pTab; @@ -226794,10 +216044,9 @@ static void xPreUpdate( pSession->rc = sessionFindTable(pSession, zName, &pTab); if( pTab ){ assert( pSession->rc==SQLITE_OK ); - assert( op==SQLITE_UPDATE || iKey1==iKey2 ); - sessionPreupdateOneChange(op, iKey1, pSession, pTab); + sessionPreupdateOneChange(op, pSession, pTab); if( op==SQLITE_UPDATE ){ - sessionPreupdateOneChange(SQLITE_INSERT, iKey2, pSession, pTab); + sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab); } } } @@ -226836,7 +216085,6 @@ static void sessionPreupdateHooks( typedef struct SessionDiffCtx SessionDiffCtx; struct SessionDiffCtx { sqlite3_stmt *pStmt; - int bRowid; int nOldOff; }; @@ -226845,20 +216093,19 @@ struct SessionDiffCtx { */ static int sessionDiffOld(void *pCtx, int iVal, sqlite3_value **ppVal){ SessionDiffCtx *p = (SessionDiffCtx*)pCtx; - *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff+p->bRowid); + *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff); return SQLITE_OK; } static int sessionDiffNew(void *pCtx, int iVal, sqlite3_value **ppVal){ SessionDiffCtx *p = (SessionDiffCtx*)pCtx; - *ppVal = sqlite3_column_value(p->pStmt, iVal+p->bRowid); + *ppVal = sqlite3_column_value(p->pStmt, iVal); return SQLITE_OK; } static int sessionDiffCount(void *pCtx){ SessionDiffCtx *p = (SessionDiffCtx*)pCtx; - return (p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt)) - p->bRowid; + return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt); } static int sessionDiffDepth(void *pCtx){ - (void)pCtx; return 0; } @@ -226932,18 +216179,17 @@ 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 = sqlite3_mprintf( - "SELECT %s FROM \"%w\".\"%w\" WHERE NOT EXISTS (" + "SELECT * FROM \"%w\".\"%w\" WHERE NOT EXISTS (" " SELECT 1 FROM \"%w\".\"%w\" WHERE %s" ")", - zSel, zDb1, zTbl, zDb2, zTbl, zExpr + zDb1, zTbl, zDb2, zTbl, zExpr ); return zRet; } @@ -226957,9 +216203,7 @@ static int sessionDiffFindNew( char *zExpr ){ int rc = SQLITE_OK; - char *zStmt = sessionSelectFindNew( - zDb1, zDb2, pTab->bRowid, pTab->zName, zExpr - ); + char *zStmt = sessionSelectFindNew(pTab->nCol, zDb1, zDb2, pTab->zName,zExpr); if( zStmt==0 ){ rc = SQLITE_NOMEM; @@ -226970,10 +216214,8 @@ static int sessionDiffFindNew( SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx; pDiffCtx->pStmt = pStmt; pDiffCtx->nOldOff = 0; - pDiffCtx->bRowid = pTab->bRowid; while( SQLITE_ROW==sqlite3_step(pStmt) ){ - i64 iRowid = (pTab->bRowid ? sqlite3_column_int64(pStmt, 0) : 0); - sessionPreupdateOneChange(op, iRowid, pSession, pTab); + sessionPreupdateOneChange(op, pSession, pTab); } rc = sqlite3_finalize(pStmt); } @@ -226983,27 +216225,6 @@ 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; iinCol; ii++){ - zRet = sqlite3_mprintf("%z%s\"%w\".\"%w\".\"%w\"", - zRet, (zRet ? ", " : ""), zDb, pTab->zName, pTab->azCol[ii] - ); - if( !zRet ) break; - } - return zRet; -} - static int sessionDiffFindModified( sqlite3_session *pSession, SessionTable *pTab, @@ -227018,13 +216239,11 @@ static int sessionDiffFindModified( if( zExpr2==0 ){ rc = SQLITE_NOMEM; }else{ - char *z1 = sessionAllCols(pSession->zDb, pTab); - char *z2 = sessionAllCols(zFrom, pTab); char *zStmt = sqlite3_mprintf( - "SELECT %s,%s FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)", - z1, z2, pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2 + "SELECT * FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)", + pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2 ); - if( zStmt==0 || z1==0 || z2==0 ){ + if( zStmt==0 ){ rc = SQLITE_NOMEM; }else{ sqlite3_stmt *pStmt; @@ -227035,15 +216254,12 @@ static int sessionDiffFindModified( pDiffCtx->pStmt = pStmt; pDiffCtx->nOldOff = pTab->nCol; while( SQLITE_ROW==sqlite3_step(pStmt) ){ - i64 iRowid = (pTab->bRowid ? sqlite3_column_int64(pStmt, 0) : 0); - sessionPreupdateOneChange(SQLITE_UPDATE, iRowid, pSession, pTab); + sessionPreupdateOneChange(SQLITE_UPDATE, pSession, pTab); } rc = sqlite3_finalize(pStmt); } + sqlite3_free(zStmt); } - sqlite3_free(zStmt); - sqlite3_free(z1); - sqlite3_free(z2); } return rc; @@ -227072,7 +216288,7 @@ SQLITE_API int 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, pSession->db, pSession->zDb) ){ + if( sessionInitTable(pSession, pTo) ){ rc = pSession->rc; goto diff_out; } @@ -227082,12 +216298,9 @@ SQLITE_API int 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, 0, &abPK, - pSession->bImplicitPK ? &bRowid : 0 - ); + rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK); if( rc==SQLITE_OK ){ if( pTo->nCol!=nCol ){ bMismatch = 1; @@ -227200,7 +216413,6 @@ static void sessionDeleteTable(sqlite3_session *pSession, SessionTable *pList){ sessionFree(pSession, p); } } - sqlite3_finalize(pTab->pDfltStmt); sessionFree(pSession, (char*)pTab->azCol); /* cast works around VC++ bug */ sessionFree(pSession, pTab->apChange); sessionFree(pSession, pTab); @@ -227233,7 +216445,9 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession){ ** associated hash-tables. */ sessionDeleteTable(pSession, pSession->pTable); - /* Free the session object. */ + /* Assert that all allocations have been freed and then free the + ** session object itself. */ + assert( pSession->nMalloc==0 ); sqlite3_free(pSession); } @@ -227304,6 +216518,48 @@ SQLITE_API int sqlite3session_attach( return rc; } +/* +** Ensure that there is room in the buffer to append nByte bytes of data. +** If not, use sqlite3_realloc() to grow the buffer so that there is. +** +** If successful, return zero. Otherwise, if an OOM condition is encountered, +** set *pRc to SQLITE_NOMEM and return non-zero. +*/ +static int sessionBufferGrow(SessionBuffer *p, 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( nNewSESSION_MAX_BUFFER_SZ ){ + nNew = SESSION_MAX_BUFFER_SZ; + if( nNewaBuf, 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. @@ -227372,6 +216628,26 @@ 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 = 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 @@ -227404,7 +216680,7 @@ static void sessionAppendIdent( const char *zStr, /* String to quote, escape and append */ int *pRc /* IN/OUT: Error code */ ){ - int nStr = sqlite3Strlen30(zStr)*2 + 2 + 2; + int nStr = sqlite3Strlen30(zStr)*2 + 2 + 1; if( 0==sessionBufferGrow(p, nStr, pRc) ){ char *zOut = (char *)&p->aBuf[p->nBuf]; const char *zIn = zStr; @@ -227415,7 +216691,6 @@ static void sessionAppendIdent( } *zOut++ = '"'; p->nBuf = (int)((u8 *)zOut - p->aBuf); - p->aBuf[p->nBuf] = 0x00; } } @@ -227551,7 +216826,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 module is + /* Add a field to the old.* record. This is omitted if this modules is ** currently generating a patchset. */ if( bPatchset==0 ){ if( bChanged || abPK[i] ){ @@ -227640,20 +216915,12 @@ 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, pk2,...) IS (?1, ?2,...) -** -** where is: -** -** 1 AND (?A OR ?1 IS ) AND ... -** -** for each non-pk . +** SELECT * FROM zDb.zTab WHERE pk1 = ? AND pk2 = ? AND ... */ static int sessionSelectStmt( 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 */ @@ -227661,50 +216928,8 @@ 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==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; ipTable; 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 */ 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 = sessionReinitTable(pSession, pTab); - if( rc==SQLITE_OK && pTab->nCol!=nOldCol ){ - rc = sessionUpdateChanges(pSession, pTab); + rc = sessionTableInfo(0, db, pSession->zDb, zName, &nCol, 0,&azCol,&abPK); + if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){ + rc = SQLITE_SCHEMA; } /* Write a table header */ @@ -227897,9 +217121,8 @@ static int sessionGenerateChangeset( /* Build and compile a statement to execute: */ if( rc==SQLITE_OK ){ - rc = sessionSelectStmt(db, 0, pSession->zDb, - zName, pTab->bRowid, pTab->nCol, pTab->azCol, pTab->abPK, &pSel - ); + rc = sessionSelectStmt( + db, pSession->zDb, zName, nCol, azCol, abPK, &pSel); } nNoop = buf.nBuf; @@ -227907,22 +217130,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, pTab->nCol, pTab->abPK, p); + rc = sessionSelectBind(pSel, nCol, abPK, p); if( rc!=SQLITE_OK ) continue; if( sqlite3_step(pSel)==SQLITE_ROW ){ if( p->op==SQLITE_INSERT ){ int iCol; sessionAppendByte(&buf, SQLITE_INSERT, &rc); sessionAppendByte(&buf, p->bIndirect, &rc); - for(iCol=0; iColnCol; iCol++){ + for(iCol=0; iColabPK!=0 ); - rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, pTab->abPK); + assert( abPK!=0 ); /* Because sessionSelectStmt() returned ok */ + rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, abPK); } }else if( p->op!=SQLITE_INSERT ){ - rc = sessionAppendDelete(&buf, bPatchset, p, pTab->nCol,pTab->abPK); + rc = sessionAppendDelete(&buf, bPatchset, p, nCol, abPK); } if( rc==SQLITE_OK ){ rc = sqlite3_reset(pSel); @@ -227947,6 +217170,7 @@ static int sessionGenerateChangeset( if( buf.nBuf==nNoop ){ buf.nBuf = nRewind; } + sqlite3_free((char*)azCol); /* cast works around VC++ bug */ } } @@ -227981,7 +217205,7 @@ SQLITE_API int 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 ); @@ -228099,19 +217323,6 @@ SQLITE_API int sqlite3session_object_config(sqlite3_session *pSession, int op, v 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; } @@ -228370,19 +217581,15 @@ static int sessionReadRecord( } } if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ - if( (pIn->nData-pIn->iNext)<8 ){ - rc = SQLITE_CORRUPT_BKPT; + sqlite3_int64 v = sessionGetI64(aVal); + if( eType==SQLITE_INTEGER ){ + sqlite3VdbeMemSetInt64(apOut[i], v); }else{ - sqlite3_int64 v = sessionGetI64(aVal); - if( eType==SQLITE_INTEGER ){ - sqlite3VdbeMemSetInt64(apOut[i], v); - }else{ - double d; - memcpy(&d, &v, 8); - sqlite3VdbeMemSetDouble(apOut[i], d); - } - pIn->iNext += 8; + double d; + memcpy(&d, &v, 8); + sqlite3VdbeMemSetDouble(apOut[i], d); } + pIn->iNext += 8; } } } @@ -228570,14 +217777,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; @@ -229104,8 +218311,6 @@ 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. */ @@ -229356,10 +218561,8 @@ static int sessionSelectRow( const char *zTab, /* Table name */ SessionApplyCtx *p /* Session changeset-apply context */ ){ - /* TODO */ - return sessionSelectStmt(db, p->bIgnoreNoop, - "main", zTab, p->bRowid, p->nCol, p->azCol, p->abPK, &p->pSelect - ); + return sessionSelectStmt( + db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect); } /* @@ -229517,34 +218720,22 @@ static int sessionBindRow( ** UPDATE, bind values from the old.* record. */ static int sessionSeekToRow( + sqlite3 *db, /* Database handle */ sqlite3_changeset_iter *pIter, /* Changeset iterator */ - SessionApplyCtx *p + u8 *abPK, /* Primary key flags array */ + sqlite3_stmt *pSelect /* SELECT statement from sessionSelectRow() */ ){ - 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 */ - sqlite3_clear_bindings(pSelect); sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0); rc = sessionBindRow(pIter, op==SQLITE_INSERT ? sqlite3changeset_new : sqlite3changeset_old, - nCol, p->abPK, pSelect + nCol, abPK, pSelect ); - if( op!=SQLITE_DELETE && p->bIgnoreNoop ){ - int ii; - for(ii=0; rc==SQLITE_OK && iiabPK[ii]==0 ){ - sqlite3_value *pVal = 0; - sqlite3changeset_new(pIter, ii, &pVal); - sqlite3_bind_int(pSelect, ii+1+nCol, (pVal==0)); - if( pVal ) rc = sessionBindValue(pSelect, ii+1, pVal); - } - } - } - if( rc==SQLITE_OK ){ rc = sqlite3_step(pSelect); if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect); @@ -229659,22 +218850,16 @@ static int sessionConflictHandler( /* Bind the new.* PRIMARY KEY values to the SELECT statement. */ if( pbReplace ){ - rc = sessionSeekToRow(pIter, p); + rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect); }else{ rc = SQLITE_OK; } if( rc==SQLITE_ROW ){ /* There exists another row with the new.* primary key. */ - if( p->bIgnoreNoop - && sqlite3_column_int(p->pSelect, sqlite3_column_count(p->pSelect)-1) - ){ - res = SQLITE_CHANGESET_OMIT; - }else{ - pIter->pConflict = p->pSelect; - res = xConflict(pCtx, eType, pIter); - pIter->pConflict = 0; - } + pIter->pConflict = p->pSelect; + res = xConflict(pCtx, eType, pIter); + pIter->pConflict = 0; rc = sqlite3_reset(p->pSelect); }else if( rc==SQLITE_OK ){ if( p->bDeferConstraints && eType==SQLITE_CHANGESET_CONFLICT ){ @@ -229782,7 +218967,7 @@ static int sessionApplyOneOp( sqlite3_step(p->pDelete); rc = sqlite3_reset(p->pDelete); - if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 && p->bIgnoreNoop==0 ){ + if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){ rc = sessionConflictHandler( SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry ); @@ -229839,7 +219024,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); + rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect); if( rc==SQLITE_ROW ){ rc = SQLITE_CONSTRAINT; sqlite3_reset(p->pSelect); @@ -230016,7 +219201,6 @@ static int sessionChangesetApply( memset(&sApply, 0, sizeof(sApply)); sApply.bRebase = (ppRebase && pnRebase); sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); - sApply.bIgnoreNoop = !!(flags & SQLITE_CHANGESETAPPLY_IGNORENOOP); sqlite3_mutex_enter(sqlite3_db_mutex(db)); if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){ rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0); @@ -230054,7 +219238,6 @@ 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 @@ -230074,8 +219257,8 @@ static int sessionChangesetApply( int i; sqlite3changeset_pk(pIter, &abPK, 0); - rc = sessionTableInfo(0, db, "main", zNew, - &sApply.nCol, &zTab, &sApply.azCol, 0, &sApply.abPK, &sApply.bRowid + rc = sessionTableInfo(0, + db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK ); if( rc!=SQLITE_OK ) break; for(i=0; iflags & 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; } @@ -230312,10 +219482,6 @@ struct sqlite3_changegroup { int rc; /* Error code */ int bPatch; /* True to accumulate patchsets */ SessionTable *pList; /* List of tables in current patch */ - SessionBuffer rec; - - sqlite3 *db; /* Configured by changegroup_schema() */ - char *zDb; /* Configured by changegroup_schema() */ }; /* @@ -230336,7 +219502,6 @@ static int sessionChangeMerge( ){ SessionChange *pNew = 0; int rc = SQLITE_OK; - assert( aRec!=0 ); if( !pExist ){ pNew = (SessionChange *)sqlite3_malloc64(sizeof(SessionChange) + nRec); @@ -230503,236 +219668,84 @@ static int sessionChangeMerge( } /* -** 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. +** Add all changes in the changeset traversed by the iterator passed as +** the first argument to the changegroup hash tables. */ -static int sessionChangesetCheckCompat( - SessionTable *pTab, - int nCol, - u8 *abPK -){ - if( pTab->azCol && nColnCol ){ - int ii; - for(ii=0; iinCol; 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)); -} - -static int sessionChangesetExtendRecord( - sqlite3_changegroup *pGrp, - SessionTable *pTab, - int nCol, - int op, - const u8 *aRec, - int nRec, - SessionBuffer *pOut +static int sessionChangesetToHash( + sqlite3_changeset_iter *pIter, /* Iterator to read from */ + 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; - int ii = 0; - - assert( pTab->azCol ); - assert( nColnCol ); + SessionTable *pTab = 0; - 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); + 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; } - for(ii=nCol; rc==SQLITE_OK && iinCol; ii++){ - int eType = 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 = sqlite3_column_int64(pTab->pDfltStmt, ii); - }else{ - double rVal = 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; - } - case SQLITE_BLOB: - case SQLITE_TEXT: { - int n = sqlite3_column_bytes(pTab->pDfltStmt, ii); - sessionAppendVarint(pOut, n, &rc); - if( eType==SQLITE_TEXT ){ - const u8 *z = (const u8*)sqlite3_column_text(pTab->pDfltStmt, ii); - sessionAppendBlob(pOut, z, n, &rc); - }else{ - const u8 *z = (const u8*)sqlite3_column_blob(pTab->pDfltStmt, ii); - sessionAppendBlob(pOut, z, n, &rc); - } - break; - } + sqlite3changeset_op(pIter, &zNew, &nCol, &op, &bIndirect); + if( !pTab || sqlite3_stricmp(zNew, pTab->zName) ){ + /* Search the list for a matching table */ + int nNew = (int)strlen(zNew); + u8 *abPK; - default: - assert( eType==SQLITE_NULL ); - break; + sqlite3changeset_pk(pIter, &abPK, 0); + for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){ + if( 0==sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) 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; iinCol-nCol); ii++){ - sessionAppendByte(pOut, 0x00, &rc); - } - } - - 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( - sqlite3_changegroup *pGrp, - const char *zTab, - 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; - sqlite3changeset_pk(pIter, &abPK, &nCol); - - /* Search the list for an existing table */ - for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){ - if( 0==sqlite3_strnicmp(pTab->zName, zTab, nTab+1) ) break; - } - - /* If one was not found above, create a new table now */ - if( !pTab ){ - SessionTable **ppNew; - - pTab = 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( !pTab ){ + SessionTable **ppTab; - if( pGrp->db ){ - pTab->nCol = 0; - rc = sessionInitTable(0, pTab, pGrp->db, pGrp->zDb); - if( rc ){ - assert( pTab->azCol==0 ); - sqlite3_free(pTab); - return rc; + pTab = sqlite3_malloc64(sizeof(SessionTable) + nCol + nNew+1); + if( !pTab ){ + rc = SQLITE_NOMEM; + break; + } + memset(pTab, 0, sizeof(SessionTable)); + pTab->nCol = nCol; + pTab->abPK = (u8*)&pTab[1]; + memcpy(pTab->abPK, abPK, nCol); + pTab->zName = (char*)&pTab->abPK[nCol]; + memcpy(pTab->zName, zNew, nNew+1); + + /* The new object must be linked on to the end of the list, not + ** simply added to the start of it. This is to ensure that the + ** tables within the output of sqlite3changegroup_output() are in + ** the right order. */ + for(ppTab=&pGrp->pList; *ppTab; ppTab=&(*ppTab)->pNext); + *ppTab = pTab; + }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){ + rc = SQLITE_SCHEMA; + break; } } - /* The new object must be linked on to the end of the list, not - ** simply added to the start of it. This is to ensure that the - ** tables within the output of sqlite3changegroup_output() are in - ** the right order. */ - for(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( - sqlite3_changegroup *pGrp, - 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; - sqlite3changeset_op(pIter, &zTab, &nCol, &op, &bIndirect); - rc = sessionChangesetFindTable(pGrp, zTab, pIter, &pTab); - } - - if( rc==SQLITE_OK && nColnCol ){ - 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. */ + if( sessionGrowHash(0, pIter->bPatchset, pTab) ){ + rc = SQLITE_NOMEM; + break; + } iHash = sessionChangeHash( pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange ); + + /* Search for existing entry. If found, remove it from the hash table. + ** Code below may link it back in. + */ for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){ int bPkOnly1 = 0; int bPkOnly2 = 0; @@ -230747,39 +219760,16 @@ static int sessionOneChangeToHash( break; } } - } - if( rc==SQLITE_OK ){ rc = sessionChangeMerge(pTab, bRebase, pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange ); - } - 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( - sqlite3_changeset_iter *pIter, /* Iterator to read from */ - 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 ) break; + if( pChange ){ + pChange->pNext = pTab->apChange[iHash]; + pTab->apChange[iHash] = pChange; + pTab->nEntry++; + } } if( rc==SQLITE_OK ) rc = pIter->rc; @@ -230868,31 +219858,6 @@ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp){ return rc; } -/* -** Provide a database schema to the changegroup object. -*/ -SQLITE_API int sqlite3changegroup_schema( - sqlite3_changegroup *pGrp, - sqlite3 *db, - const char *zDb -){ - int rc = SQLITE_OK; - - if( pGrp->pList || pGrp->db ){ - /* Cannot add a schema after one or more calls to sqlite3changegroup_add(), - ** or after sqlite3changegroup_schema() has already been called. */ - rc = SQLITE_MISUSE; - }else{ - pGrp->zDb = 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. @@ -230909,23 +219874,6 @@ SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup *pGrp, int nData, void return rc; } -/* -** Add a single change to a changeset-group. -*/ -SQLITE_API int sqlite3changegroup_add_change( - sqlite3_changegroup *pGrp, - 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. @@ -230973,9 +219921,7 @@ SQLITE_API int sqlite3changegroup_output_strm( */ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){ if( pGrp ){ - sqlite3_free(pGrp->zDb); sessionDeleteTable(0, pGrp->pList); - sqlite3_free(pGrp->rec.aBuf); sqlite3_free(pGrp); } } @@ -231377,7 +220323,6 @@ SQLITE_API int sqlite3rebaser_rebase_strm( SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p){ if( p ){ sessionDeleteTable(0, p->grp.pList); - sqlite3_free(p->grp.rec.aBuf); sqlite3_free(p); } } @@ -231475,8 +220420,8 @@ struct Fts5PhraseIter { ** EXTENSION API FUNCTIONS ** ** xUserData(pFts): -** Return a copy of the pUserData pointer passed to the xCreateFunction() -** API when the extension function was registered. +** Return a copy of the context pointer the extension function was +** registered with. ** ** xColumnTotalSize(pFts, iCol, pnToken): ** If parameter iCol is less than zero, set output variable *pnToken @@ -231508,11 +220453,8 @@ struct Fts5PhraseIter { ** created with the "columnsize=0" option. ** ** xColumnText: -** 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 +** 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 @@ -231522,10 +220464,8 @@ struct Fts5PhraseIter { ** Returns the number of phrases in the current query expression. ** ** xPhraseSize: -** 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. +** 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 @@ -231541,13 +220481,12 @@ 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(). If iIdx is less than zero or greater than -** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned. +** output by xInstCount(). ** -** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol +** Usually, output parameter *piPhrase is set to the phrase number, *piCol ** to the column in which it occurs and *piOff the token offset of the -** first token of the phrase. SQLITE_OK is returned if successful, or an -** error code (i.e. SQLITE_NOMEM) if an error occurs. +** first token of the phrase. Returns SQLITE_OK if successful, or an error +** code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. @@ -231573,10 +220512,6 @@ 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. @@ -231691,39 +220626,6 @@ 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 */ @@ -231761,13 +220663,6 @@ 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*); }; /* @@ -231962,8 +220857,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 (3)) or query -** text (method (2)), not both. Doing so will not cause any errors, but is +** provide synonyms when tokenizing document text (method (2)) or query +** text (method (3)), not both. Doing so will not cause any errors, but is ** inefficient. */ typedef struct Fts5Tokenizer Fts5Tokenizer; @@ -232011,7 +220906,7 @@ struct fts5_api { int (*xCreateTokenizer)( fts5_api *pApi, const char *zName, - void *pUserData, + void *pContext, fts5_tokenizer *pTokenizer, void (*xDestroy)(void*) ); @@ -232020,7 +220915,7 @@ struct fts5_api { int (*xFindTokenizer)( fts5_api *pApi, const char *zName, - void **ppUserData, + void **ppContext, fts5_tokenizer *pTokenizer ); @@ -232028,7 +220923,7 @@ struct fts5_api { int (*xCreateFunction)( fts5_api *pApi, const char *zName, - void *pUserData, + void *pContext, fts5_extension_function xFunction, void (*xDestroy)(void*) ); @@ -232200,10 +221095,6 @@ 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: @@ -232238,11 +221129,9 @@ 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; @@ -232251,7 +221140,6 @@ 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 */ @@ -232260,8 +221148,6 @@ 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 sqlite3_vtab.base.zErrmsg. Often NULL. */ char **pzErrmsg; @@ -232271,11 +221157,8 @@ struct Fts5Config { #endif }; -/* 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 +/* Current expected value of %_config table 'version' field */ +#define FTS5_CURRENT_VERSION 4 #define FTS5_CONTENT_NORMAL 0 #define FTS5_CONTENT_NONE 1 @@ -232431,19 +221314,16 @@ 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_SKIPHASH 0x0040 -#define FTS5INDEX_QUERY_NOTOKENDATA 0x0080 -#define FTS5INDEX_QUERY_SCANONETERM 0x0100 +#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010 +#define FTS5INDEX_QUERY_NOOUTPUT 0x0020 /* ** Create/destroy an Fts5Index object. @@ -232512,10 +221392,6 @@ static void *sqlite3Fts5StructureRef(Fts5Index*); static void sqlite3Fts5StructureRelease(void*); static int sqlite3Fts5StructureTest(Fts5Index*, void*); -/* -** Used by xInstToken(): -*/ -static int sqlite3Fts5IterToken(Fts5IndexIter*, i64, int, int, const char**, int*); /* ** Insert or remove data to or from the index. Each time a document is @@ -232590,16 +221466,6 @@ static int sqlite3Fts5IndexReset(Fts5Index *p); static int sqlite3Fts5IndexLoadConfig(Fts5Index *p); -static int sqlite3Fts5IndexGetOrigin(Fts5Index *p, i64 *piOrigin); -static int sqlite3Fts5IndexContentlessDelete(Fts5Index *p, i64 iOrigin, i64 iRowid); - -static void sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter*); - -/* Used to populate hash tables for xInstToken in detail=none/column mode. */ -static int sqlite3Fts5IndexIterWriteTokendata( - Fts5IndexIter*, const char*, int, i64 iRowid, int iCol, int iOff -); - /* ** End of interface to code in fts5_index.c. **************************************************************************/ @@ -232612,7 +221478,7 @@ static int sqlite3Fts5GetVarintLen(u32 iVal); static u8 sqlite3Fts5GetVarint(const unsigned char*, u64*); static int sqlite3Fts5PutVarint(unsigned char *p, u64 v); -#define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&(b)) +#define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&b) #define fts5GetVarint sqlite3Fts5GetVarint #define fts5FastGetVarint32(a, iOff, nVal) { \ @@ -232684,11 +221550,6 @@ static int sqlite3Fts5HashWrite( */ static void sqlite3Fts5HashClear(Fts5Hash*); -/* -** Return true if the hash is empty, false otherwise. -*/ -static int sqlite3Fts5HashIsEmpty(Fts5Hash*); - static int sqlite3Fts5HashQuery( Fts5Hash*, /* Hash table to query */ int nPre, @@ -232705,13 +221566,11 @@ static void sqlite3Fts5HashScanNext(Fts5Hash*); static int sqlite3Fts5HashScanEof(Fts5Hash*); static void 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. **************************************************************************/ @@ -232832,10 +221691,6 @@ static int sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**); static int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *); -static int sqlite3Fts5ExprQueryToken(Fts5Expr*, int, int, const char**, int*); -static int sqlite3Fts5ExprInstToken(Fts5Expr*, i64, int, int, int, int, const char**, int*); -static void 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 @@ -232959,8 +221814,7 @@ static void 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 ** @@ -233072,9 +221926,6 @@ static void sqlite3Fts5UnicodeAscii(u8*, u8*); ** sqlite3Fts5ParserARG_STORE Code to store %extra_argument into fts5yypParser ** sqlite3Fts5ParserARG_FETCH Code to extract %extra_argument from fts5yypParser ** sqlite3Fts5ParserCTX_* As 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. @@ -233088,8 +221939,6 @@ static void 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 @@ -233116,9 +221965,6 @@ typedef union { #define sqlite3Fts5ParserARG_PARAM ,pParse #define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse=fts5yypParser->pParse; #define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse=pParse; -#define fts5YYREALLOC realloc -#define fts5YYFREE free -#define fts5YYDYNSTACK 0 #define sqlite3Fts5ParserCTX_SDECL #define sqlite3Fts5ParserCTX_PDECL #define sqlite3Fts5ParserCTX_PARAM @@ -233136,8 +221982,6 @@ 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]))) @@ -233153,22 +221997,6 @@ 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 @@ -233329,9 +222157,14 @@ struct fts5yyParser { #endif sqlite3Fts5ParserARG_SDECL /* A place to hold %extra_argument */ sqlite3Fts5ParserCTX_SDECL /* A place to hold %extra_context */ - fts5yyStackEntry *fts5yystackEnd; /* Last entry in the stack */ - fts5yyStackEntry *fts5yystack; /* The parser stack */ - fts5yyStackEntry fts5yystk0[fts5YYSTACKDEPTH]; /* Initial stack space */ +#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 }; typedef struct fts5yyParser fts5yyParser; @@ -233438,45 +222271,37 @@ static const char *const fts5yyRuleName[] = { #endif /* NDEBUG */ -#if fts5YYGROWABLESTACK +#if fts5YYSTACKDEPTH<=0 /* ** 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 = 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])); + 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; }else{ - pNew = fts5YYREALLOC(p->fts5yystack, newSize*sizeof(pNew[0])); - if( pNew==0 ) return 1; + pNew = realloc(p->fts5yystack, newSize*sizeof(pNew[0])); } - p->fts5yystack = pNew; - p->fts5yytos = &p->fts5yystack[idx]; + if( pNew ){ + p->fts5yystack = pNew; + p->fts5yytos = &p->fts5yystack[idx]; #ifndef NDEBUG - if( fts5yyTraceFILE ){ - fprintf(fts5yyTraceFILE,"%sStack grows from %d to %d entries.\n", - fts5yyTracePrompt, oldSize, newSize); - } + if( fts5yyTraceFILE ){ + fprintf(fts5yyTraceFILE,"%sStack grows from %d to %d entries.\n", + fts5yyTracePrompt, p->fts5yystksz, newSize); + } #endif - p->fts5yystackEnd = &p->fts5yystack[newSize-1]; - return 0; + p->fts5yystksz = newSize; + } + return pNew==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 @@ -233496,14 +222321,24 @@ static void sqlite3Fts5ParserInit(void *fts5yypRawParser sqlite3Fts5ParserCTX_PD #ifdef fts5YYTRACKMAXSTACKDEPTH fts5yypParser->fts5yyhwm = 0; #endif - fts5yypParser->fts5yystack = fts5yypParser->fts5yystk0; - fts5yypParser->fts5yystackEnd = &fts5yypParser->fts5yystack[fts5YYSTACKDEPTH-1]; +#if fts5YYSTACKDEPTH<=0 + fts5yypParser->fts5yytos = NULL; + fts5yypParser->fts5yystack = NULL; + fts5yypParser->fts5yystksz = 0; + if( fts5yyGrowStack(fts5yypParser) ){ + fts5yypParser->fts5yystack = &fts5yypParser->fts5yystk0; + fts5yypParser->fts5yystksz = 1; + } +#endif #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 sqlite3Fts5Parser_ENGINEALWAYSONSTACK @@ -233617,26 +222452,9 @@ static void fts5yy_pop_parser_stack(fts5yyParser *pParser){ */ static void sqlite3Fts5ParserFinalize(void *p){ fts5yyParser *pParser = (fts5yyParser*)p; - - /* 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); + while( pParser->fts5yytos>pParser->fts5yystack ) fts5yy_pop_parser_stack(pParser); +#if fts5YYSTACKDEPTH<=0 + if( pParser->fts5yystack!=&pParser->fts5yystk0 ) free(pParser->fts5yystack); #endif } @@ -233863,19 +222681,25 @@ static void fts5yy_shift( assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack) ); } #endif - fts5yytos = fts5yypParser->fts5yytos; - if( fts5yytos>fts5yypParser->fts5yystackEnd ){ +#if fts5YYSTACKDEPTH>0 + if( fts5yypParser->fts5yytos>fts5yypParser->fts5yystackEnd ){ + fts5yypParser->fts5yytos--; + fts5yyStackOverflow(fts5yypParser); + return; + } +#else + if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz] ){ 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; @@ -234312,12 +223136,19 @@ static void 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 sqlite3Fts5ParserCTX_PARAM); }else if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){ @@ -234573,19 +223404,15 @@ static int fts5CInstIterInit( */ typedef struct HighlightContext HighlightContext; struct HighlightContext { - /* Constant parameters to fts5HighlightCb() */ + CInstIter iter; /* Coalesced Instance Iterator */ + int iPos; /* Current token offset in zIn[] */ int iRangeStart; /* First token to include */ int iRangeEnd; /* If non-zero, last token to include */ const char *zOpen; /* Opening highlight */ const char *zClose; /* Closing highlight */ const char *zIn; /* Input text */ int nIn; /* Size of input text in bytes */ - - /* 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 */ + int iOff; /* Current offset within zIn[] */ char *zOut; /* Output value */ }; @@ -234618,8 +223445,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 byte offset of token */ - int iEndOff /* End byte offset of token */ + int iStartOff, /* Start offset of token */ + int iEndOff /* End offset of token */ ){ HighlightContext *p = (HighlightContext*)pContext; int rc = SQLITE_OK; @@ -234630,60 +223457,35 @@ static int fts5HighlightCb( if( tflags & FTS5_TOKEN_COLOCATED ) return SQLITE_OK; iPos = p->iPos++; - if( p->iRangeEnd>=0 ){ + if( p->iRangeEnd>0 ){ if( iPosiRangeStart || iPos>p->iRangeEnd ) return SQLITE_OK; if( p->iRangeStart && iPos==p->iRangeStart ) p->iOff = iStartOff; } - /* 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 ){ + if( iPos==p->iter.iStart ){ 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->bOpen==0 ){ - assert( p->iRangeEnd>=0 ); + if( p->iRangeEnd && p->iter.iStartiRangeStart ){ 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( 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; - } + 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 && iPositer.iEnd ){ + fts5HighlightAppend(&rc, p, p->zClose, -1); + } } return rc; @@ -234713,12 +223515,9 @@ static void fts5HighlightFunction( memset(&ctx, 0, sizeof(HighlightContext)); ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]); ctx.zClose = (const char*)sqlite3_value_text(apVal[2]); - ctx.iRangeEnd = -1; rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn); - if( rc==SQLITE_RANGE ){ - sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC); - rc = SQLITE_OK; - }else if( ctx.zIn ){ + + if( ctx.zIn ){ if( rc==SQLITE_OK ){ rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter); } @@ -234726,9 +223525,6 @@ 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 ){ @@ -234904,7 +223700,6 @@ static void fts5SnippetFunction( iCol = sqlite3_value_int(apVal[0]); ctx.zOpen = fts5ValueToText(apVal[1]); ctx.zClose = fts5ValueToText(apVal[2]); - ctx.iRangeEnd = -1; zEllips = fts5ValueToText(apVal[3]); nToken = sqlite3_value_int(apVal[4]); @@ -235007,9 +223802,6 @@ 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{ @@ -235285,7 +224077,6 @@ static void sqlite3Fts5BufferAppendBlob( ){ if( nData ){ if( fts5BufferGrow(pRc, pBuf, nData) ) return; - assert( pBuf->p!=0 ); memcpy(&pBuf->p[pBuf->n], pData, nData); pBuf->n += nData; } @@ -235387,7 +224178,6 @@ static int sqlite3Fts5PoslistNext64( i64 *piOff /* IN/OUT: Current offset */ ){ int i = *pi; - assert( a!=0 || i==0 ); if( i>=n ){ /* EOF */ *piOff = -1; @@ -235395,7 +224185,6 @@ static int sqlite3Fts5PoslistNext64( }else{ i64 iOff = *piOff; u32 iVal; - assert( a!=0 ); fts5FastGetVarint32(a, i, iVal); if( iVal<=1 ){ if( iVal==0 ){ @@ -235651,8 +224440,6 @@ static void 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) @@ -235983,16 +224770,6 @@ static int fts5ConfigParseSpecial( return rc; } - if( sqlite3_strnicmp("contentless_delete", zCmd, nCmd)==0 ){ - if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){ - *pzErr = sqlite3_mprintf("malformed contentless_delete=... directive"); - rc = SQLITE_ERROR; - }else{ - pConfig->bContentlessDelete = (zArg[0]=='1'); - } - return rc; - } - if( sqlite3_strnicmp("content_rowid", zCmd, nCmd)==0 ){ if( pConfig->zContentRowid ){ *pzErr = sqlite3_mprintf("multiple content_rowid=... directives"); @@ -236027,16 +224804,6 @@ static int fts5ConfigParseSpecial( return rc; } - if( sqlite3_strnicmp("tokendata", zCmd, nCmd)==0 ){ - if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){ - *pzErr = sqlite3_mprintf("malformed tokendata=... directive"); - rc = SQLITE_ERROR; - }else{ - pConfig->bTokendata = (zArg[0]=='1'); - } - return rc; - } - *pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd); return SQLITE_ERROR; } @@ -236201,7 +224968,6 @@ static int sqlite3Fts5ConfigParse( rc = SQLITE_ERROR; } - assert( (pRet->abUnindexed && pRet->azCol) || rc!=SQLITE_OK ); for(i=3; rc==SQLITE_OK && ibContentlessDelete - && pRet->eContent!=FTS5_CONTENT_NONE - ){ - *pzErr = 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 = 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. */ @@ -236563,18 +225307,6 @@ static int sqlite3Fts5ConfigSetValue( } } - else if( 0==sqlite3_stricmp(zKey, "deletemerge") ){ - int nVal = -1; - if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ - nVal = 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==sqlite3_stricmp(zKey, "rank") ){ const char *zIn = (const char*)sqlite3_value_text(pVal); char *zRank; @@ -236589,18 +225321,6 @@ static int sqlite3Fts5ConfigSetValue( rc = SQLITE_OK; *pbBadkey = 1; } - } - - else if( 0==sqlite3_stricmp(zKey, "secure-delete") ){ - int bVal = -1; - if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ - bVal = sqlite3_value_int(pVal); - } - if( bVal<0 ){ - *pbBadkey = 1; - }else{ - pConfig->bSecureDelete = (bVal ? 1 : 0); - } }else{ *pbBadkey = 1; } @@ -236623,7 +225343,6 @@ static int 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 = sqlite3Fts5Mprintf(&rc, zSelect, pConfig->zDb, pConfig->zName); if( zSql ){ @@ -236646,20 +225365,15 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){ rc = sqlite3_finalize(p); } - if( rc==SQLITE_OK - && iVersion!=FTS5_CURRENT_VERSION - && iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE - ){ + if( rc==SQLITE_OK && iVersion!=FTS5_CURRENT_VERSION ){ rc = SQLITE_ERROR; if( pConfig->pzErrmsg ){ assert( 0==*pConfig->pzErrmsg ); - *pConfig->pzErrmsg = sqlite3_mprintf("invalid fts5 file format " - "(found %d, expected %d or %d) - run 'rebuild'", - iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE + *pConfig->pzErrmsg = sqlite3_mprintf( + "invalid fts5 file format (found %d, expected %d) - run 'rebuild'", + iVersion, FTS5_CURRENT_VERSION ); } - }else{ - pConfig->iVersion = iVersion; } if( rc==SQLITE_OK ){ @@ -236687,10 +225401,6 @@ static int 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. */ @@ -236731,17 +225441,11 @@ 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); @@ -236770,9 +225474,7 @@ struct Fts5ExprNode { struct Fts5ExprTerm { u8 bPrefix; /* True for a prefix term */ u8 bFirst; /* True if token must be first in column */ - char *pTerm; /* Term data */ - int nQueryTerm; /* Effective size of term in bytes */ - int nFullTerm; /* Size of term in bytes incl. tokendata */ + char *zTerm; /* nul-terminated term */ Fts5IndexIter *pIter; /* Iterator for this term */ Fts5ExprTerm *pSynonym; /* Pointer to first in list of synonyms */ }; @@ -236813,31 +225515,6 @@ 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; iinChild; 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 sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){ va_list ap; va_start(ap, zFmt); @@ -236952,8 +225629,6 @@ static int sqlite3Fts5ExprNew( }while( sParse.rc==SQLITE_OK && t!=FTS5_EOF ); 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( iColnCol && sParse.pExpr && sParse.rc==SQLITE_OK ){ @@ -236994,27 +225669,10 @@ static int sqlite3Fts5ExprNew( } sqlite3_free(sParse.apPhrase); - if( 0==*pzErr ){ - *pzErr = sParse.zErr; - }else{ - sqlite3_free(sParse.zErr); - } + *pzErr = 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=3 ){ + if( i-iFirst>=3 ){ int jj; zExpr[iOut++] = '"'; for(jj=iFirst; jjnPhrase + p2->nPhrase; @@ -237145,7 +225802,7 @@ static int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){ } sqlite3_free(p2->apExprPhrase); sqlite3_free(p2); - }else if( p2 ){ + }else{ *pp1 = p2; } @@ -237643,7 +226300,7 @@ static int fts5ExprNearInitAll( p->pIter = 0; } rc = sqlite3Fts5IndexQuery( - pExpr->pIndex, p->pTerm, p->nQueryTerm, + pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm), (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) | (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0), pNear->pColset, @@ -238280,7 +226937,7 @@ static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){ Fts5ExprTerm *pSyn; Fts5ExprTerm *pNext; Fts5ExprTerm *pTerm = &pPhrase->aTerm[i]; - sqlite3_free(pTerm->pTerm); + sqlite3_free(pTerm->zTerm); sqlite3Fts5IterClose(pTerm->pIter); for(pSyn=pTerm->pSynonym; pSyn; pSyn=pNext){ pNext = pSyn->pSynonym; @@ -238378,7 +227035,6 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset( typedef struct TokenCtx TokenCtx; struct TokenCtx { Fts5ExprPhrase *pPhrase; - Fts5Config *pConfig; int rc; }; @@ -238412,12 +227068,8 @@ static int fts5ParseTokenize( rc = SQLITE_NOMEM; }else{ memset(pSyn, 0, (size_t)nByte); - 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->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer); + memcpy(pSyn->zTerm, pToken, nToken); pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym; pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn; } @@ -238442,11 +227094,7 @@ static int fts5ParseTokenize( if( rc==SQLITE_OK ){ pTerm = &pPhrase->aTerm[pPhrase->nTerm++]; memset(pTerm, 0, sizeof(Fts5ExprTerm)); - pTerm->pTerm = sqlite3Fts5Strndup(&rc, pToken, nToken); - pTerm->nFullTerm = pTerm->nQueryTerm = nToken; - if( pCtx->pConfig->bTokendata && rc==SQLITE_OK ){ - pTerm->nQueryTerm = (int)strlen(pTerm->pTerm); - } + pTerm->zTerm = sqlite3Fts5Strndup(&rc, pToken, nToken); } } @@ -238513,7 +227161,6 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm( memset(&sCtx, 0, sizeof(TokenCtx)); sCtx.pPhrase = pAppend; - sCtx.pConfig = pConfig; rc = fts5ParseStringFromToken(pToken, &z); if( rc==SQLITE_OK ){ @@ -238561,15 +227208,12 @@ static int sqlite3Fts5ExprClonePhrase( Fts5Expr **ppNew ){ int rc = SQLITE_OK; /* Return code */ - Fts5ExprPhrase *pOrig = 0; /* The phrase extracted from pExpr */ + Fts5ExprPhrase *pOrig; /* The phrase extracted from pExpr */ Fts5Expr *pNew = 0; /* Expression to return via *ppNew */ - 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*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr)); - } + TokenCtx sCtx = {0,0}; /* Context object for fts5ParseTokenize */ + + pOrig = pExpr->apExprPhrase[iPhrase]; + pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr)); if( rc==SQLITE_OK ){ pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase*)); @@ -238582,7 +227226,7 @@ static int sqlite3Fts5ExprClonePhrase( pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)); } - if( rc==SQLITE_OK && ALWAYS(pOrig!=0) ){ + if( rc==SQLITE_OK ){ Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset; if( pColsetOrig ){ sqlite3_int64 nByte; @@ -238596,27 +227240,26 @@ static int sqlite3Fts5ExprClonePhrase( } } - 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 && inTerm; 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; - } + if( pOrig->nTerm ){ + int i; /* Used to iterate through phrase terms */ + for(i=0; rc==SQLITE_OK && inTerm; 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; } - }else{ - /* This happens when parsing a token or quoted phrase that contains - ** no token characters at all. (e.g ... MATCH '""'). */ - sCtx.pPhrase = 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 = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase)); } if( rc==SQLITE_OK && ALWAYS(sCtx.pPhrase) ){ @@ -238933,7 +227576,6 @@ 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); @@ -238942,9 +227584,6 @@ static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){ }else{ p->apChild[p->nChild++] = pSub; } - for( ; iinChild; ii++){ - p->iHeight = MAX(p->iHeight, p->apChild[ii]->iHeight + 1); - } } /* @@ -238975,7 +227614,6 @@ static Fts5ExprNode *fts5ParsePhraseToAnd( if( pRet ){ pRet->eType = FTS5_AND; pRet->nChild = nTerm; - pRet->iHeight = 1; fts5ExprAssignXNext(pRet); pParse->nPhrase--; for(ii=0; iiapPhrase[0]->aTerm[ii]; - Fts5ExprTerm *pTo = &pPhrase->aTerm[0]; pParse->apPhrase[pParse->nPhrase++] = pPhrase; pPhrase->nTerm = 1; - pTo->pTerm = sqlite3Fts5Strndup(&pParse->rc, p->pTerm, p->nFullTerm); - pTo->nQueryTerm = p->nQueryTerm; - pTo->nFullTerm = p->nFullTerm; + pPhrase->aTerm[0].zTerm = sqlite3Fts5Strndup( + &pParse->rc, pNear->apPhrase[0]->aTerm[ii].zTerm, -1 + ); pRet->apChild[ii] = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, sqlite3Fts5ParseNearset(pParse, 0, pPhrase) ); @@ -239083,14 +227719,6 @@ static Fts5ExprNode *sqlite3Fts5ParseNode( }else{ fts5ExprAddChildren(pRet, pLeft); fts5ExprAddChildren(pRet, pRight); - if( pRet->iHeight>SQLITE_FTS5_MAX_EXPR_DEPTH ){ - sqlite3Fts5ParseError(pParse, - "fts5 expression tree is too large (maximum depth %d)", - SQLITE_FTS5_MAX_EXPR_DEPTH - ); - sqlite3_free(pRet); - pRet = 0; - } } } } @@ -239126,7 +227754,6 @@ static Fts5ExprNode *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 ){ @@ -239170,7 +227797,7 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd( return pRet; } -#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) +#ifdef SQLITE_TEST static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){ sqlite3_int64 nByte = 0; Fts5ExprTerm *p; @@ -239178,17 +227805,16 @@ static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){ /* Determine the maximum amount of space required. */ for(p=pTerm; p; p=p->pSynonym){ - nByte += pTerm->nQueryTerm * 2 + 3 + 2; + nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2; } zQuoted = sqlite3_malloc64(nByte); if( zQuoted ){ int i = 0; for(p=pTerm; p; p=p->pSynonym){ - char *zIn = p->pTerm; - char *zEnd = &zIn[p->nQueryTerm]; + char *zIn = p->zTerm; zQuoted[i++] = '"'; - while( zInnTerm; iTerm++){ - Fts5ExprTerm *p = &pPhrase->aTerm[iTerm]; - zRet = fts5PrintfAppend(zRet, "%s%.*s", iTerm==0?"":" ", - p->nQueryTerm, p->pTerm - ); + char *zTerm = pPhrase->aTerm[iTerm].zTerm; + zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm); if( pPhrase->aTerm[iTerm].bPrefix ){ zRet = fts5PrintfAppend(zRet, "*"); } @@ -239279,8 +227903,6 @@ static char *fts5ExprPrintTcl( if( zRet==0 ) return 0; } - }else if( pExpr->eType==0 ){ - zRet = sqlite3_mprintf("{}"); }else{ char const *zOp = 0; int i; @@ -239542,14 +228164,14 @@ static void fts5ExprFold( sqlite3_result_int(pCtx, sqlite3Fts5UnicodeFold(iCode, bRemoveDiacritics)); } } -#endif /* if SQLITE_TEST || SQLITE_FTS5_DEBUG */ +#endif /* ifdef SQLITE_TEST */ /* ** This is called during initialization to register the fts5_expr() scalar ** UDF with the SQLite handle passed as the only argument. */ static int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){ -#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) +#ifdef SQLITE_TEST struct Fts5ExprFunc { const char *z; void (*x)(sqlite3_context*,int,sqlite3_value**); @@ -239670,17 +228292,6 @@ 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; iipExpr; int i; - int nQuery = nToken; - i64 iRowid = pExpr->pRoot->iRowid; UNUSED_PARAM2(iUnused1, iUnused2); - if( nQuery>FTS5_MAX_TOKEN_SIZE ) nQuery = FTS5_MAX_TOKEN_SIZE; - if( pExpr->pConfig->bTokendata ){ - nQuery = fts5QueryTerm(pToken, nQuery); - } + if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE; if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++; for(i=0; inPhrase; i++){ - Fts5ExprTerm *pT; + Fts5ExprTerm *pTerm; if( p->aPopulator[i].bOk==0 ) continue; - for(pT=&pExpr->apExprPhrase[i]->aTerm[0]; pT; pT=pT->pSynonym){ - if( (pT->nQueryTerm==nQuery || (pT->nQueryTermbPrefix)) - && memcmp(pT->pTerm, pToken, pT->nQueryTerm)==0 + for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){ + int nTerm = (int)strlen(pTerm->zTerm); + if( (nTerm==nToken || (nTermbPrefix)) + && memcmp(pTerm->zTerm, pToken, nTerm)==0 ){ int rc = 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 = sqlite3Fts5IndexIterWriteTokendata( - pT->pIter, pToken, nToken, iRowid, iCol, iTokOff - ); - } if( rc ) return rc; break; } @@ -239854,83 +228454,6 @@ static int sqlite3Fts5ExprPhraseCollist( return rc; } -/* -** Does the work of the fts5_api.xQueryToken() API method. -*/ -static int 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 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 = 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 sqlite3Fts5ExprClearTokens(Fts5Expr *pExpr){ - int ii; - for(ii=0; iinPhrase; ii++){ - Fts5ExprTerm *pT; - for(pT=&pExpr->apExprPhrase[ii]->aTerm[0]; pT; pT=pT->pSynonym){ - sqlite3Fts5IndexIterClearTokendata(pT->pIter); - } - } -} - /* ** 2014 August 11 ** @@ -239969,15 +228492,10 @@ struct Fts5Hash { /* ** Each entry in the hash table is represented by an object of the -** 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. +** 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. ** ** The data that follows the key is in a similar, but not identical format ** to the doclist data stored in the database. It is: @@ -240112,7 +228630,8 @@ static int fts5HashResize(Fts5Hash *pHash){ unsigned int iHash; Fts5HashEntry *p = apOld[i]; apOld[i] = p->pHashNext; - iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p), p->nKey); + iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p), + (int)strlen(fts5EntryKey(p))); p->pHashNext = apNew[iHash]; apNew[iHash] = p; } @@ -240196,7 +228715,7 @@ static int sqlite3Fts5HashWrite( for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ char *zKey = fts5EntryKey(p); if( zKey[0]==bByte - && p->nKey==nToken+1 + && p->nKey==nToken && memcmp(&zKey[1], pToken, nToken)==0 ){ break; @@ -240226,9 +228745,9 @@ static int sqlite3Fts5HashWrite( zKey[0] = bByte; memcpy(&zKey[1], pToken, nToken); assert( iHash==fts5HashKey(pHash->nSlot, (u8*)zKey, nToken+1) ); - p->nKey = nToken+1; + p->nKey = nToken; zKey[nToken+1] = '\0'; - p->nData = nToken+1 + sizeof(Fts5HashEntry); + p->nData = nToken+1 + 1 + sizeof(Fts5HashEntry); p->pHashNext = pHash->aSlot[iHash]; pHash->aSlot[iHash] = p; pHash->nEntry++; @@ -240345,17 +228864,12 @@ static Fts5HashEntry *fts5HashEntryMerge( *ppOut = p1; p1 = 0; }else{ + int i = 0; char *zKey1 = fts5EntryKey(p1); char *zKey2 = fts5EntryKey(p2); - int nMin = MIN(p1->nKey, p2->nKey); + while( zKey1[i]==zKey2[i] ) i++; - int cmp = memcmp(zKey1, zKey2, nMin); - if( cmp==0 ){ - cmp = p1->nKey - p2->nKey; - } - assert( cmp!=0 ); - - if( cmp>0 ){ + if( ((u8)zKey1[i])>((u8)zKey2[i]) ){ /* p2 is smaller */ *ppOut = p2; ppOut = &p2->pScanNext; @@ -240374,8 +228888,10 @@ static Fts5HashEntry *fts5HashEntryMerge( } /* -** Link all tokens from hash table iHash into a list in sorted order. The -** tokens are not removed from the hash table. +** Extract all tokens from hash table iHash and link them into a list +** in sorted order. The hash table is cleared before returning. It is +** the responsibility of the caller to free the elements of the returned +** list. */ static int fts5HashEntrySort( Fts5Hash *pHash, @@ -240397,7 +228913,7 @@ static int fts5HashEntrySort( Fts5HashEntry *pIter; for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){ if( pTerm==0 - || (pIter->nKey>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm)) + || (pIter->nKey+1>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm)) ){ Fts5HashEntry *pEntry = pIter; pEntry->pScanNext = 0; @@ -240415,6 +228931,7 @@ static int fts5HashEntrySort( pList = fts5HashEntryMerge(pList, ap[i]); } + pHash->nEntry = 0; sqlite3_free(ap); *ppSorted = pList; return SQLITE_OK; @@ -240436,11 +228953,12 @@ static int sqlite3Fts5HashQuery( for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ zKey = fts5EntryKey(p); - if( nTerm==p->nKey && memcmp(zKey, pTerm, nTerm)==0 ) break; + assert( p->nKey+1==(int)strlen(zKey) ); + if( nTerm==p->nKey+1 && memcmp(zKey, pTerm, nTerm)==0 ) break; } if( p ){ - int nHashPre = sizeof(Fts5HashEntry) + nTerm; + int nHashPre = sizeof(Fts5HashEntry) + nTerm + 1; int nList = p->nData - nHashPre; u8 *pRet = (u8*)(*ppOut = sqlite3_malloc64(nPre + nList + 10)); if( pRet ){ @@ -240467,28 +228985,6 @@ static int sqlite3Fts5HashScanInit( return fts5HashEntrySort(p, pTerm, nTerm, &p->pScan); } -#ifdef SQLITE_DEBUG -static int fts5HashCount(Fts5Hash *pHash){ - int nEntry = 0; - int ii; - for(ii=0; iinSlot; 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 sqlite3Fts5HashIsEmpty(Fts5Hash *pHash){ - assert( pHash->nEntry==fts5HashCount(pHash) ); - return pHash->nEntry==0; -} - static void sqlite3Fts5HashScanNext(Fts5Hash *p){ assert( !sqlite3Fts5HashScanEof(p) ); p->pScan = p->pScan->pScanNext; @@ -240501,22 +228997,19 @@ static int sqlite3Fts5HashScanEof(Fts5Hash *p){ static void 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 = p->nKey; + int nTerm = (int)strlen(zKey); fts5HashAddPoslistSize(pHash, p, 0); *pzTerm = zKey; - *pnTerm = nTerm; - *ppDoclist = (const u8*)&zKey[nTerm]; - *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm); + *ppDoclist = (const u8*)&zKey[nTerm+1]; + *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1); }else{ *pzTerm = 0; - *pnTerm = 0; *ppDoclist = 0; *pnDoclist = 0; } @@ -240578,26 +229071,6 @@ static void 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: ** @@ -240605,7 +229078,7 @@ static void sqlite3Fts5HashScanEntry( ** ** CREATE TABLE %_data(id INTEGER PRIMARY KEY, block BLOB); ** -** , contains the following 6 types of records. See the comments surrounding +** , contains the following 5 types of records. See the comments surrounding ** the FTS5_*_ROWID macros below for a description of how %_data rowids are ** assigned to each fo them. ** @@ -240614,12 +229087,12 @@ static void 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 structure record is a V2 record, the configuration cookie is -** followed by the following 4 bytes: [0xFF 0x00 0x00 0x01]. +** 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. ** -** Next, the record continues with three varints: +** Immediately following the configuration cookie, the record begins with +** three varints: ** ** + number of levels, ** + total number of segments on all levels, @@ -240634,12 +229107,6 @@ static void 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. @@ -240755,38 +229222,6 @@ static void 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 */ /* @@ -240820,7 +229255,6 @@ static void 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 sqlite3Fts5Corrupt() { return SQLITE_CORRUPT_VTAB; } @@ -240847,9 +229281,6 @@ 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 */ @@ -240859,12 +229290,6 @@ 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 */ @@ -240879,12 +229304,9 @@ 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. */ sqlite3_blob *pReader; /* RO incr-blob open on %_data table */ @@ -240893,11 +229315,8 @@ struct Fts5Index { sqlite3_stmt *pIdxWriter; /* "INSERT ... %_idx VALUES(?,?,?,?)" */ sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=?" */ sqlite3_stmt *pIdxSelect; - sqlite3_stmt *pIdxNextSelect; int nRead; /* Total number of blocks read */ - sqlite3_stmt *pDeleteFromIdx; - sqlite3_stmt *pDataVersion; i64 iStructVersion; /* data_version when pStruct read */ Fts5Structure *pStruct; /* Current db structure (or NULL) */ @@ -240917,23 +229336,11 @@ 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 */ @@ -240943,7 +229350,6 @@ 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 */ @@ -241003,6 +229409,9 @@ 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. @@ -241032,13 +229441,6 @@ 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 */ @@ -241047,7 +229449,6 @@ 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*); @@ -241074,15 +229475,6 @@ struct Fts5SegIter { u8 bDel; /* True if the delete flag is set */ }; -/* -** 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. @@ -241127,16 +229519,9 @@ struct Fts5TombstoneArray { ** poslist: ** Used by 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 */ @@ -241154,6 +229539,7 @@ 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. @@ -241192,60 +229578,6 @@ static u16 fts5GetU16(const u8 *aIn){ return ((u16)aIn[0] << 8) + aIn[1]; } -/* -** 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. ** @@ -241473,17 +229805,10 @@ static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){ /* ** Remove all records associated with segment iSegid. */ -static void fts5DataRemoveSegment(Fts5Index *p, Fts5StructureSegment *pSeg){ - int iSegid = pSeg->iSegid; +static void fts5DataRemoveSegment(Fts5Index *p, int iSegid){ i64 iFirst = FTS5_SEGMENT_ROWID(iSegid, 0); i64 iLast = FTS5_SEGMENT_ROWID(iSegid+1, 0)-1; fts5DataDelete(p, iFirst, iLast); - - if( 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, sqlite3_mprintf( @@ -241594,19 +229919,11 @@ static int fts5StructureDecode( int nSegment = 0; 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 = 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); @@ -241653,18 +229970,9 @@ 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->pgnoLastpgnoFirst ){ rc = FTS5_CORRUPT; break; @@ -241675,9 +229983,6 @@ static int fts5StructureDecode( } } if( nSegment!=0 && rc==SQLITE_OK ) rc = FTS5_CORRUPT; - if( bStructureV2 ){ - pRet->nOriginCntr = nOriginCntr+1; - } if( rc!=SQLITE_OK ){ fts5StructureRelease(pRet); @@ -241695,7 +230000,6 @@ 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; @@ -241890,7 +230194,6 @@ 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)); @@ -241899,12 +230202,9 @@ static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){ iCookie = p->pConfig->iCookie; if( iCookie<0 ) iCookie = 0; - if( 0==sqlite3Fts5BufferSize(&p->rc, &buf, nHdr) ){ + if( 0==sqlite3Fts5BufferSize(&p->rc, &buf, 4+9+9+9) ){ 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); @@ -241918,17 +230218,9 @@ static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){ assert( pLvl->nMerge<=pLvl->nSeg ); for(iSeg=0; iSegnSeg; iSeg++){ - 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); - } + fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].iSegid); + fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoFirst); + fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoLast); } } @@ -242071,9 +230363,9 @@ static int fts5DlidxLvlNext(Fts5DlidxLvl *pLvl){ } if( iOffnn ){ - u64 iVal; + i64 iVal; pLvl->iLeafPgno += (iOff - pLvl->iOff) + 1; - iOff += fts5GetVarint(&pData->p[iOff], &iVal); + iOff += fts5GetVarint(&pData->p[iOff], (u64*)&iVal); pLvl->iRowid += iVal; pLvl->iOff = iOff; }else{ @@ -242166,25 +230458,42 @@ static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){ pLvl->bEof = 1; }else{ u8 *a = pLvl->pData->p; - - pLvl->iOff = 0; - fts5DlidxLvlNext(pLvl); - while( 1 ){ - int nZero = 0; - int ii = pLvl->iOff; - u64 delta = 0; - - while( a[ii]==0 ){ - nZero++; - ii++; + 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); } - ii += sqlite3Fts5GetVarint(&a[ii], &delta); - - if( ii>=iOff ) break; - pLvl->iLeafPgno += nZero+1; - pLvl->iRowid += delta; - pLvl->iOff = ii; + if( bZero==0 ) nZero--; } + pLvl->iLeafPgno -= nZero; + pLvl->iOff = iOff - nZero; } return pLvl->bEof; @@ -242380,7 +230689,7 @@ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){ i64 iOff = pIter->iLeafOffset; ASSERT_SZLEAF_OK(pIter->pLeaf); - while( iOff>=pIter->pLeaf->szLeaf ){ + if( iOff>=pIter->pLeaf->szLeaf ){ fts5SegIterNextPage(p, pIter); if( pIter->pLeaf==0 ){ if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT; @@ -242451,25 +230760,6 @@ 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*)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 @@ -242498,12 +230788,10 @@ static void fts5SegIterInit( fts5SegIterSetNext(p, pIter); pIter->pSeg = pSeg; pIter->iLeafPgno = pSeg->pgnoFirst-1; - do { - fts5SegIterNextPage(p, pIter); - }while( p->rc==SQLITE_OK && pIter->pLeaf && pIter->pLeaf->nn==4 ); + fts5SegIterNextPage(p, pIter); } - if( p->rc==SQLITE_OK && pIter->pLeaf ){ + if( p->rc==SQLITE_OK ){ pIter->iLeafOffset = 4; assert( pIter->pLeaf!=0 ); assert_nc( pIter->pLeaf->nn>4 ); @@ -242511,7 +230799,6 @@ static void fts5SegIterInit( pIter->iPgidxOff = pIter->pLeaf->szLeaf+1; fts5SegIterLoadTerm(p, pIter, 0); fts5SegIterLoadNPos(p, pIter); - fts5SegIterAllocTombstone(p, pIter); } } @@ -242698,7 +230985,7 @@ static void fts5SegIterNext_None( iOff = pIter->iLeafOffset; /* Next entry is on the next page */ - while( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){ + if( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){ fts5SegIterNextPage(p, pIter); if( p->rc || pIter->pLeaf==0 ) return; pIter->iRowid = 0; @@ -242722,16 +231009,15 @@ static void fts5SegIterNext_None( }else{ const u8 *pList = 0; const char *zTerm = 0; - int nTerm = 0; int nList; sqlite3Fts5HashScanNext(p->pHash); - sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &nTerm, &pList, &nList); + sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList); if( pList==0 ) goto next_none_eof; pIter->pLeaf->p = (u8*)pList; pIter->pLeaf->nn = nList; pIter->pLeaf->szLeaf = nList; pIter->iEndofDoclist = nList; - sqlite3Fts5BufferSet(&p->rc,&pIter->term, nTerm, (u8*)zTerm); + sqlite3Fts5BufferSet(&p->rc,&pIter->term, (int)strlen(zTerm), (u8*)zTerm); pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid); } @@ -242797,12 +231083,11 @@ 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) ){ sqlite3Fts5HashScanNext(p->pHash); - sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &nTerm, &pList, &nList); + sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList); } if( pList==0 ){ fts5DataRelease(pIter->pLeaf); @@ -242812,7 +231097,8 @@ static void fts5SegIterNext( pIter->pLeaf->nn = nList; pIter->pLeaf->szLeaf = nList; pIter->iEndofDoclist = nList+1; - sqlite3Fts5BufferSet(&p->rc, &pIter->term, nTerm, (u8*)zTerm); + sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm), + (u8*)zTerm); pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid); *pbNewTerm = 1; } @@ -242892,7 +231178,7 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){ Fts5Data *pLast = 0; int pgnoLast = 0; - if( pDlidx && p->pConfig->iVersion==FTS5_CURRENT_VERSION ){ + if( pDlidx ){ int iSegid = pIter->pSeg->iSegid; pgnoLast = fts5DlidxIterPgno(pDlidx); pLast = fts5LeafRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast)); @@ -243198,7 +231484,7 @@ static void fts5SegIterSeekInit( fts5LeafSeek(p, bGe, pIter, pTerm, nTerm); } - if( p->rc==SQLITE_OK && (bGe==0 || (flags & FTS5INDEX_QUERY_SCANONETERM)) ){ + if( p->rc==SQLITE_OK && bGe==0 ){ pIter->flags |= FTS5_SEGITER_ONETERM; if( pIter->pLeaf ){ if( flags & FTS5INDEX_QUERY_DESC ){ @@ -243214,9 +231500,6 @@ static void fts5SegIterSeekInit( } fts5SegIterSetNext(p, pIter); - if( 0==(flags & FTS5INDEX_QUERY_SCANONETERM) ){ - fts5SegIterAllocTombstone(p, pIter); - } /* Either: ** @@ -243233,79 +231516,6 @@ static void fts5SegIterSeekInit( ); } - -/* -** SQL used by fts5SegIterNextInit() to find the page to open. -*/ -static sqlite3_stmt *fts5IdxNextStmt(Fts5Index *p){ - if( p->pIdxNextSelect==0 ){ - Fts5Config *pConfig = p->pConfig; - fts5IndexPrepareStmt(p, &p->pIdxNextSelect, 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; - sqlite3_stmt *pSel = 0; /* SELECT to find iPg */ - - pSel = fts5IdxNextStmt(p); - if( pSel ){ - assert( p->rc==SQLITE_OK ); - sqlite3_bind_int(pSel, 1, pSeg->iSegid); - sqlite3_bind_blob(pSel, 2, pTerm, nTerm, SQLITE_STATIC); - - if( sqlite3_step(pSel)==SQLITE_ROW ){ - i64 val = sqlite3_column_int64(pSel, 0); - iPg = (int)(val>>1); - bDlidx = (val & 0x0001); - } - p->rc = sqlite3_reset(pSel); - 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 @@ -243332,21 +231542,14 @@ static void fts5SegIterHashInit( const u8 *pList = 0; p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm); - sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &n, &pList, &nList); + sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList); + n = (z ? (int)strlen((const char*)z) : 0); if( pList ){ pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data)); if( pLeaf ){ pLeaf->p = (u8*)pList; } } - - /* The call to 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 = sqlite3Fts5HashQuery(p->pHash, sizeof(Fts5Data), (const char*)pTerm, nTerm, (void**)&pLeaf, &nList @@ -243377,37 +231580,6 @@ static void fts5SegIterHashInit( fts5SegIterSetNext(p, pIter); } -/* -** Array ap[] contains n elements. Release each of these elements using -** fts5DataRelease(). Then free the array itself using sqlite3_free(). -*/ -static void fts5IndexFreeArray(Fts5Data **ap, int n){ - if( ap ){ - int ii; - for(ii=0; iinRef--; - if( p->nRef<=0 ){ - int ii; - for(ii=0; iinTombstone; ii++){ - fts5DataRelease(p->apTombstone[ii]); - } - sqlite3_free(p); - } - } -} - /* ** Zero the iterator passed as the only argument. */ @@ -243415,7 +231587,6 @@ static void fts5SegIterClear(Fts5SegIter *pIter){ fts5BufferFree(&pIter->term); fts5DataRelease(pIter->pLeaf); fts5DataRelease(pIter->pNextLeaf); - fts5TombstoneArrayDelete(pIter->pTombArray); fts5DlidxIterFree(pIter->pDlidx); sqlite3_free(pIter->aRowidOffset); memset(pIter, 0, sizeof(Fts5SegIter)); @@ -243549,6 +231720,7 @@ 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; @@ -243567,8 +231739,7 @@ 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. Unless the db is -** a 'secure-delete' db, if it contains no rowids then this is also an error. +** It is an error if leaf iLeafPgno does not exist or contains no rowids. */ static void fts5SegIterGotoPage( Fts5Index *p, /* FTS5 backend object */ @@ -243583,23 +231754,21 @@ static void fts5SegIterGotoPage( fts5DataRelease(pIter->pNextLeaf); pIter->pNextLeaf = 0; pIter->iLeafPgno = iLeafPgno-1; + fts5SegIterNextPage(p, pIter); + assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno ); - while( p->rc==SQLITE_OK ){ + if( p->rc==SQLITE_OK && ALWAYS(pIter->pLeaf!=0) ){ int iOff; - fts5SegIterNextPage(p, pIter); - if( pIter->pLeaf==0 ) break; + u8 *a = pIter->pLeaf->p; + int n = pIter->pLeaf->szLeaf; + iOff = fts5LeafFirstRowidOff(pIter->pLeaf); - 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; + if( iOff<4 || iOff>=n ){ + p->rc = FTS5_CORRUPT; + }else{ + iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid); + pIter->iLeafOffset = iOff; + fts5SegIterLoadNPos(p, pIter); } } } @@ -243660,6 +231829,7 @@ static void fts5SegIterNextFrom( }while( p->rc==SQLITE_OK ); } + /* ** Free the iterator object passed as the second argument. */ @@ -243751,85 +231921,6 @@ static void fts5MultiIterSetEof(Fts5Iter *pIter){ pIter->iSwitchRowid = pSeg->iRowid; } -/* -** 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. ** @@ -243867,9 +231958,7 @@ static void fts5MultiIterNext( fts5AssertMultiIterSetup(p, pIter); assert( pSeg==&pIter->aSeg[pIter->aFirst[1].iFirst] && pSeg->pLeaf ); - if( (pIter->bSkipEmpty==0 || pSeg->nPos) - && 0==fts5MultiIterIsDeleted(pIter) - ){ + if( pIter->bSkipEmpty==0 || pSeg->nPos ){ pIter->xSetOutputs(pIter, pSeg); return; } @@ -243901,9 +231990,7 @@ static void fts5MultiIterNext2( } fts5AssertMultiIterSetup(p, pIter); - }while( (fts5MultiIterIsEmpty(p, pIter) || fts5MultiIterIsDeleted(pIter)) - && (p->rc==SQLITE_OK) - ); + }while( fts5MultiIterIsEmpty(p, pIter) ); } } @@ -243916,7 +232003,7 @@ static Fts5Iter *fts5MultiIterAlloc( int nSeg ){ Fts5Iter *pNew; - i64 nSlot; /* Power of two >= nSeg */ + int nSlot; /* Power of two >= nSeg */ for(nSlot=2; nSlotnSeg-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. @@ -244422,7 +232483,7 @@ static void fts5MultiIterNew( if( iLevel<0 ){ assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) ); nSeg = pStruct->nSegment; - nSeg += (p->pHash && 0==(flags & FTS5INDEX_QUERY_SKIPHASH)); + nSeg += (p->pHash ? 1 : 0); }else{ nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment); } @@ -244443,7 +232504,7 @@ static void fts5MultiIterNew( if( p->rc==SQLITE_OK ){ if( iLevel<0 ){ Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel]; - if( p->pHash && 0==(flags & FTS5INDEX_QUERY_SKIPHASH) ){ + if( p->pHash ){ /* Add a segment iterator for the current contents of the hash table. */ Fts5SegIter *pIter = &pNew->aSeg[iIter++]; fts5SegIterHashInit(p, pTerm, nTerm, flags, pIter); @@ -244468,12 +232529,29 @@ static void fts5MultiIterNew( assert( iIter==nSeg ); } - /* If the above was successful, each component iterator now points + /* If the above was successful, each component iterators now points ** to the first entry in its segment. In this case initialize the ** aFirst[] array. Or, if an error has occurred, free the iterator ** object and set the output variable to NULL. */ if( p->rc==SQLITE_OK ){ - fts5MultiIterFinishSetup(p, pNew); + for(iIter=pNew->nSeg-1; iIter>0; iIter--){ + int iEq; + if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){ + Fts5SegIter *pSeg = &pNew->aSeg[iEq]; + if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0); + fts5MultiIterAdvanced(p, pNew, iEq, iIter); + } + } + fts5MultiIterSetEof(pNew); + fts5AssertMultiIterSetup(p, pNew); + + if( pNew->bSkipEmpty && fts5MultiIterIsEmpty(p, pNew) ){ + fts5MultiIterNext(p, pNew, 0, 0); + }else if( pNew->base.bEof==0 ){ + Fts5SegIter *pSeg = &pNew->aSeg[pNew->aFirst[1].iFirst]; + pNew->xSetOutputs(pNew, pSeg); + } + }else{ fts5MultiIterFree(pNew); *ppOut = 0; @@ -244498,6 +232576,7 @@ 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; @@ -244644,10 +232723,7 @@ static void fts5IndexDiscardData(Fts5Index *p){ if( p->pHash ){ sqlite3Fts5HashClear(p->pHash); p->nPendingData = 0; - p->nPendingRow = 0; - p->flushRc = SQLITE_OK; } - p->nContentlessDelete = 0; } /* @@ -244861,7 +232937,7 @@ static void fts5WriteDlidxAppend( } if( pDlidx->bPrevValid ){ - iVal = (u64)iRowid - (u64)pDlidx->iPrev; + iVal = iRowid - pDlidx->iPrev; }else{ i64 iPgno = (i==0 ? pWriter->writer.pgno : pDlidx[-1].pgno); assert( pDlidx->buf.n==0 ); @@ -245048,7 +233124,7 @@ static void fts5WriteAppendPoslistData( const u8 *a = aData; int n = nData; - assert( p->pConfig->pgsz>0 || p->rc!=SQLITE_OK ); + assert( p->pConfig->pgsz>0 ); while( p->rc==SQLITE_OK && (pPage->buf.n + pPage->pgidx.n + n)>=p->pConfig->pgsz ){ @@ -245183,7 +233259,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); @@ -245284,12 +233360,6 @@ 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); @@ -245349,11 +233419,8 @@ static void fts5IndexMergeLevel( int i; /* Remove the redundant segments from the %_data table */ - assert( pSeg->nEntry==0 ); for(i=0; iaSeg[i]; - pSeg->nEntry += (pOld->nEntry - pOld->nEntryTombstone); - fts5DataRemoveSegment(p, pOld); + fts5DataRemoveSegment(p, pLvl->aSeg[i].iSegid); } /* Remove the redundant segments from the input level */ @@ -245379,43 +233446,6 @@ static void fts5IndexMergeLevel( if( pnRem ) *pnRem -= writer.nLeafWritten; } -/* -** 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; iinLevel; ii++){ - Fts5StructureLevel *pLvl = &pStruct->aLevel[ii]; - i64 nEntry = 0; - i64 nTomb = 0; - int iSeg; - for(iSeg=0; iSegnSeg; 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. ** @@ -245435,15 +233465,14 @@ 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. Or to -1 if - ** there is no level suitable to merge segments from. */ + /* Set iBestLvl to the level to read input segments from. */ assert( pStruct->nLevel>0 ); for(iLvl=0; iLvlnLevel; iLvl++){ Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl]; if( pLvl->nMerge ){ if( pLvl->nMerge>nBest ){ iBestLvl = iLvl; - nBest = nMin; + nBest = pLvl->nMerge; } break; } @@ -245452,18 +233481,22 @@ static int fts5IndexMerge( iBestLvl = iLvl; } } - if( nBestnLevel; iLvl++){ + assert( pStruct->aLevel[iLvl].nSeg==0 ); } +#endif - if( iBestLvl<0 ) break; + if( nBestaLevel[iBestLvl].nMerge==0 ){ + break; + } bRet = 1; fts5IndexMergeLevel(p, &pStruct, iBestLvl, &nRem); if( p->rc==SQLITE_OK && pStruct->aLevel[iBestLvl].nMerge==0 ){ fts5StructurePromote(p, iBestLvl+1, pStruct); } - - if( nMin==1 ) nMin = 2; } *ppStruct = pStruct; return bRet; @@ -245504,16 +233537,16 @@ static void fts5IndexCrisismerge( ){ const int nCrisis = p->pConfig->nCrisisMerge; Fts5Structure *pStruct = *ppStruct; - 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; + int iLvl = 0; + + assert( p->rc!=SQLITE_OK || pStruct->nLevel>0 ); + while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){ + fts5IndexMergeLevel(p, &pStruct, iLvl, 0); + assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) ); + fts5StructurePromote(p, iLvl+1, pStruct); + iLvl++; } + *ppStruct = pStruct; } static int fts5IndexReturn(Fts5Index *p){ @@ -245547,469 +233580,6 @@ static int fts5PoslistPrefix(const u8 *aBuf, int nMax){ return ret; } -/* -** 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, sqlite3_mprintf( - "DELETE FROM '%q'.'%q_idx' WHERE (segid, (pgno/2)) = (?1, ?2)", - p->pConfig->zDb, p->pConfig->zName - )); - } - if( p->rc==SQLITE_OK ){ - sqlite3_bind_int(p->pDeleteFromIdx, 1, iSegid); - sqlite3_bind_int(p->pDeleteFromIdx, 2, iPgno); - sqlite3_step(p->pDeleteFromIdx); - p->rc = 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->nnszLeaf || 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( iFirstrc = FTS5_CORRUPT; - break; - } - aIdx = sqlite3Fts5MallocZero(&p->rc, (pLeaf->nn-pLeaf->szLeaf)+2); - if( aIdx==0 ) break; - i2 = sqlite3Fts5PutVarint(aIdx, iFirst-nShift); - if( i1nn ){ - 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; - } - 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 = 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( iSOPiLeafOffset ){ - if( aPg[iSOP]==0x00 ) iSOP++; - if( aPg[iSOP]==0x00 ) iSOP++; - iStart = iSOP; - iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta); - } - - iNextOff = iSOP; - if( iNextOffiEndofDoclist && aPg[iNextOff]==0x00 ) iNextOff++; - if( iNextOffiEndofDoclist && aPg[iNextOff]==0x00 ) iNextOff++; - - }else{ - int nPos = 0; - iSOP += fts5GetVarint32(&aPg[iSOP], nPos); - while( iSOPiLeafOffset ){ - 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; iIdxbDel ){ - iOff += sqlite3Fts5PutVarint(&aPg[iOff], iDelta); - aPg[iOff++] = 0x01; - }else if( bLastInDoclist==0 ){ - if( iNextOff!=iPgIdx ){ - u64 iNextDelta = 0; - iNextOff += fts5GetVarint(&aPg[iNextOff], &iNextDelta); - iOff += 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(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 += sqlite3Fts5PutVarint(&aPg[iOff], nPrefix); - } - iOff += 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; iIdxiOff ? nShift : 0)); - nPg += 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); - } - 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( iThisrc==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. @@ -246026,197 +233596,143 @@ 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( 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 = sqlite3Fts5HashScanInit(pHash, 0, 0); - } - while( p->rc==SQLITE_OK && 0==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 */ + 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 */ - /* Get the term and doclist for this entry. */ - 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 ); - } + Fts5SegWriter writer; + fts5WriteInit(p, &writer, iSegid); - 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 && iOffrc!=SQLITE_OK || pDoclist[iOff]==0x01 ){ - iOff++; - continue; - } - } - } + pBuf = &writer.writer.buf; + pPgidx = &writer.writer.pgidx; - if( p->rc==SQLITE_OK && bTermWritten==0 ){ - fts5WriteAppendTerm(p, &writer, nTerm, (const u8*)zTerm); - bTermWritten = 1; - assert( p->rc!=SQLITE_OK || writer.bFirstRowidInPage==0 ); - } + /* 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( writer.bFirstRowidInPage ){ - fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */ - pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid); - writer.bFirstRowidInPage = 0; - fts5WriteDlidxAppend(p, &writer, iRowid); - }else{ - u64 iRowidDelta = (u64)iRowid - (u64)iPrev; - pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowidDelta); - } + /* Begin scanning through hash table entries. This loop runs once for each + ** term/doclist currently stored within the hash table. */ + if( p->rc==SQLITE_OK ){ + p->rc = sqlite3Fts5HashScanInit(pHash, 0, 0); + } + while( p->rc==SQLITE_OK && 0==sqlite3Fts5HashScanEof(pHash) ){ + const char *zTerm; /* Buffer containing term */ + const u8 *pDoclist; /* Pointer to doclist for this term */ + int nDoclist; /* Size of doclist in bytes */ + + /* Write the term for this entry to disk. */ + sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist); + fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm); + 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 && iOffp[0], (u16)pBuf->n); /* first rowid on page */ + pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid); + writer.bFirstRowidInPage = 0; + fts5WriteDlidxAppend(p, &writer, iRowid); if( p->rc!=SQLITE_OK ) break; - assert( pBuf->n<=pBuf->nSpace ); - iPrev = iRowid; + }else{ + pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta); + } + assert( pBuf->n<=pBuf->nSpace ); - if( eDetail==FTS5_DETAIL_NONE ){ + if( eDetail==FTS5_DETAIL_NONE ){ + if( iOffp[pBuf->n++] = 0; + iOff++; if( iOffp[pBuf->n++] = 0; iOff++; - if( iOffp[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{ - 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; + /* The entire poslist will not fit on this leaf. So it needs + ** to be broken into sections. The only qualification being + ** that each varint must be stored contiguously. */ + const u8 *pPoslist = &pDoclist[iOff]; + int iPos = 0; + while( p->rc==SQLITE_OK ){ + int nSpace = pgsz - pBuf->n - pPgidx->n; + int n = 0; + if( (nCopy - iPos)<=nSpace ){ + n = nCopy - iPos; + }else{ + n = fts5PoslistPrefix(&pPoslist[iPos], nSpace); } + assert( n>0 ); + fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n); + iPos += n; + if( (pBuf->n + pPgidx->n)>=pgsz ){ + fts5WriteFlushLeaf(p, &writer); + } + if( iPos>=nCopy ) break; } - iOff += nCopy; } + iOff += nCopy; } } - - /* TODO2: Doclist terminator written here. */ - /* pBuf->p[pBuf->n++] = '\0'; */ - assert( pBuf->n<=pBuf->nSpace ); - if( p->rc==SQLITE_OK ) sqlite3Fts5HashScanNext(pHash); } - fts5WriteFinish(p, &writer, &pgnoLast); - 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); - } + /* TODO2: Doclist terminator written here. */ + /* pBuf->p[pBuf->n++] = '\0'; */ + assert( pBuf->n<=pBuf->nSpace ); + if( p->rc==SQLITE_OK ) sqlite3Fts5HashScanNext(pHash); } + sqlite3Fts5HashClear(pHash); + fts5WriteFinish(p, &writer, &pgnoLast); + + /* Update the Fts5Structure. It is written back to the database by the + ** fts5StructureRelease() call below. */ + if( pStruct->nLevel==0 ){ + fts5StructureAddLevel(&p->rc, &pStruct); + } + fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0); + if( p->rc==SQLITE_OK ){ + pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ]; + pSeg->iSegid = iSegid; + pSeg->pgnoFirst = 1; + pSeg->pgnoLast = pgnoLast; + pStruct->nSegment++; + } + fts5StructurePromote(p, 0, pStruct); } - fts5IndexAutomerge(p, &pStruct, pgnoLast + p->nContentlessDelete); + fts5IndexAutomerge(p, &pStruct, pgnoLast); fts5IndexCrisismerge(p, &pStruct); fts5StructureWrite(p, pStruct); fts5StructureRelease(pStruct); @@ -246227,21 +233743,10 @@ static void fts5FlushOneHash(Fts5Index *p){ */ static void fts5IndexFlush(Fts5Index *p){ /* Unless it is empty, flush the hash table to disk */ - if( p->flushRc ){ - p->rc = p->flushRc; - return; - } - if( p->nPendingData || p->nContentlessDelete ){ + if( p->nPendingData ){ assert( p->pHash ); + p->nPendingData = 0; fts5FlushOneHash(p); - if( p->rc==SQLITE_OK ){ - sqlite3Fts5HashClear(p->pHash); - p->nPendingData = 0; - p->nPendingRow = 0; - p->nContentlessDelete = 0; - }else if( p->nPendingData || p->nContentlessDelete ){ - p->flushRc = p->rc; - } } } @@ -246257,22 +233762,17 @@ static Fts5Structure *fts5IndexOptimizeStruct( /* Figure out if this structure requires optimization. A structure does ** not require optimization if either: ** - ** 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. + ** + it consists of fewer than two segments, or + ** + all segments are on the same level, or + ** + all segments except one are currently inputs to a merge operation. ** - ** In the first case, 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. + ** In the first case, return NULL. In the second, increment the ref-count + ** on *pStruct and return a copy of the pointer to it. */ - if( nSeg==0 ) return 0; + if( nSeg<2 ) return 0; for(i=0; inLevel; i++){ int nThis = pStruct->aLevel[i].nSeg; - 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; - } + if( nThis==nSeg || (nThis==nSeg-1 && pStruct->aLevel[i].nMerge==nThis) ){ fts5StructureRef(pStruct); return pStruct; } @@ -246285,11 +233785,10 @@ static Fts5Structure *fts5IndexOptimizeStruct( if( pNew ){ Fts5StructureLevel *pLvl; nByte = nSeg * sizeof(Fts5StructureSegment); - pNew->nLevel = MIN(pStruct->nLevel+1, FTS5_MAX_LEVEL); + pNew->nLevel = pStruct->nLevel+1; pNew->nRef = 1; pNew->nWriteCounter = pStruct->nWriteCounter; - pNew->nOriginCntr = pStruct->nOriginCntr; - pLvl = &pNew->aLevel[pNew->nLevel-1]; + pLvl = &pNew->aLevel[pStruct->nLevel]; pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&p->rc, nByte); if( pLvl->aSeg ){ int iLvl, iSeg; @@ -246319,9 +233818,7 @@ static int 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 ){ @@ -246350,10 +233847,7 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){ ** INSERT command. */ static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){ - Fts5Structure *pStruct = 0; - - fts5IndexFlush(p); - pStruct = fts5StructureRead(p); + Fts5Structure *pStruct = fts5StructureRead(p); if( pStruct ){ int nMin = p->pConfig->nUsermerge; fts5StructureInvalidate(p); @@ -246361,7 +233855,7 @@ static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){ Fts5Structure *pNew = fts5IndexOptimizeStruct(p, pStruct); fts5StructureRelease(pStruct); pStruct = pNew; - nMin = 1; + nMin = 2; nMerge = nMerge*-1; } if( pStruct && pStruct->nLevel ){ @@ -246596,7 +234090,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<=(int)(sizeof(aMerger)/sizeof(aMerger[0])) ); + assert( nBuf+1<=sizeof(aMerger)/sizeof(aMerger[0]) ); memset(aMerger, 0, sizeof(PrefixMerger)*(nBuf+1)); pHead = &aMerger[nBuf]; fts5DoclistIterInit(p1, &pHead->iter); @@ -246727,7 +234221,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; @@ -246748,9 +234242,8 @@ static void fts5SetupPrefixIter( aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf); pStruct = fts5StructureRead(p); - assert( p->rc!=SQLITE_OK || (aBuf && pStruct) ); - if( p->rc==SQLITE_OK ){ + if( aBuf && pStruct ){ const int flags = FTS5INDEX_QUERY_SCAN | FTS5INDEX_QUERY_SKIPEMPTY | FTS5INDEX_QUERY_NOOUTPUT; @@ -246762,12 +234255,6 @@ 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; @@ -246791,7 +234278,6 @@ 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) @@ -246807,6 +234293,7 @@ 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; @@ -246845,7 +234332,7 @@ static void fts5SetupPrefixIter( } fts5MultiIterFree(p1); - pData = fts5IdxMalloc(p, sizeof(*pData)+doclist.n+FTS5_DATA_ZERO_PADDING); + pData = fts5IdxMalloc(p, sizeof(Fts5Data)+doclist.n+FTS5_DATA_ZERO_PADDING); if( pData ){ pData->p = (u8*)&pData[1]; pData->nn = pData->szLeaf = doclist.n; @@ -246882,9 +234369,6 @@ static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){ p->iWriteRowid = iRowid; p->bDelete = bDelete; - if( bDelete==0 ){ - p->nPendingRow++; - } return fts5IndexReturn(p); } @@ -246922,9 +234406,6 @@ static int 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); @@ -246988,9 +234469,7 @@ static int sqlite3Fts5IndexClose(Fts5Index *p){ sqlite3_finalize(p->pIdxWriter); sqlite3_finalize(p->pIdxDeleter); sqlite3_finalize(p->pIdxSelect); - sqlite3_finalize(p->pIdxNextSelect); sqlite3_finalize(p->pDataVersion); - sqlite3_finalize(p->pDeleteFromIdx); sqlite3Fts5HashFree(p->pHash); sqlite3_free(p->zDataTbl); sqlite3_free(p); @@ -247084,457 +234563,6 @@ static int sqlite3Fts5IndexWrite( return rc; } -/* -** 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*)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 ){ - 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; iinIter; ii++){ - fts5MultiIterFree(pSet->apIter[ii]); - } - sqlite3_free(pSet->aPoslistReader); - sqlite3_free(pSet->aMap); - 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*)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; iinIter; ii++){ - Fts5Iter *p = pT->apIter[ii]; - if( p->base.bEof==0 ){ - if( nHit==0 || p->base.iRowidbase.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*)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; iinIter; ii++){ - Fts5Iter *p = pT->apIter[ii]; - if( iRowid==p->base.iRowid ){ - pT->aPoslistToIter[nReader] = ii; - 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*)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; iiaPoslistReader[ii]; - if( pReader->bEof==0 ){ - if( pReader->iPosiPos; - iMin = ii; - } - } - } - - /* If all readers were at EOF, break out of the loop. */ - if( iMinPos==LARGEST_INT64 ) break; - - sqlite3Fts5PoslistSafeAppend(&pIter->poslist, &iPrev, iMinPos); - 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; iinIter; ii++){ - Fts5Iter *p = pT->apIter[ii]; - if( p->base.bEof==0 - && (p->base.iRowid==pIter->base.iRowid || (bFrom && p->base.iRowidbase.bEof==0 - && p->base.iRowidrc==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 ){ - sqlite3Fts5IterClose((Fts5IndexIter*)pNew); - break; - } - - pNewIter = &pNew->aSeg[0]; - pPrevIter = (pPrev ? &pPrev->aSeg[0] : 0); - for(iLvl=0; iLvlnLevel; 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; iinSeg; 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 ){ - 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; iinIter; ii++){ - Fts5Iter *pIter = pSet->apIter[ii]; - int iSeg; - for(iSeg=0; iSegnSeg; 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. @@ -247556,13 +234584,8 @@ static int sqlite3Fts5IndexQuery( if( 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 @@ -247588,10 +234611,7 @@ static int sqlite3Fts5IndexQuery( } } - if( bTokendata && iIdx==0 ){ - buf.p[0] = '0'; - pRet = fts5SetupTokendataIter(p, buf.p, nToken+1, pColset); - }else if( iIdx<=pConfig->nPrefix ){ + if( iIdx<=pConfig->nPrefix ){ /* Straight index lookup */ Fts5Structure *pStruct = fts5StructureRead(p); buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx); @@ -247638,11 +234658,7 @@ static int sqlite3Fts5IndexQuery( static int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){ Fts5Iter *pIter = (Fts5Iter*)pIndexIter; assert( pIter->pIndex->rc==SQLITE_OK ); - if( pIter->pTokenDataIter ){ - fts5TokendataIterNext(pIter, 0, 0); - }else{ - fts5MultiIterNext(pIter->pIndex, pIter, 0, 0); - } + fts5MultiIterNext(pIter->pIndex, pIter, 0, 0); return fts5IndexReturn(pIter->pIndex); } @@ -247675,11 +234691,7 @@ static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIndexIter){ */ static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){ Fts5Iter *pIter = (Fts5Iter*)pIndexIter; - if( pIter->pTokenDataIter ){ - fts5TokendataIterNext(pIter, 1, iMatch); - }else{ - fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch); - } + fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch); return fts5IndexReturn(pIter->pIndex); } @@ -247694,99 +234706,6 @@ static const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){ return (z ? &z[1] : 0); } -/* -** 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 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].iRowidiRowid ){ - i2 = iTest; - }else{ - if( aMap[iTest].iPosiPos ){ - 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 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 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; iinIter; ii++){ - Fts5Buffer *pTerm = &pT->apIter[ii]->aSeg[0].term; - if( nToken==pTerm->n-1 && memcmp(pToken, pTerm->p+1, nToken)==0 ) break; - } - if( iinIter ){ - fts5TokendataIterAppendMap(p, pT, ii, iRowid, (((i64)iCol)<<32) + iOff); - } - return fts5IndexReturn(p); -} - /* ** Close an iterator opened by an earlier call to sqlite3Fts5IndexQuery(). */ @@ -247794,7 +234713,6 @@ static void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){ if( pIndexIter ){ Fts5Iter *pIter = (Fts5Iter*)pIndexIter; Fts5Index *pIndex = pIter->pIndex; - fts5TokendataIterDelete(pIter->pTokenDataIter); fts5MultiIterFree(pIter); sqlite3Fts5IndexCloseReader(pIndex); } @@ -247878,347 +234796,6 @@ static int 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 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; iip[0] = szKey; - fts5PutU32(&apOut[ii]->p[4], 0); - } - - /* Loop through the current pages of the hash table. */ - for(ii=0; res==0 && iinPgTombstone; 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; iInp[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**)sqlite3Fts5MallocZero(&p->rc, sizeof(Fts5Data*) * nOut); - szPage = 8 + nSlot*szKey; - for(ii=0; iirc, - 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; iiiSegid, 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 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); -} /************************************************************************* ************************************************************************** @@ -248302,9 +234879,7 @@ static int fts5QueryCksum( int eDetail = p->pConfig->eDetail; u64 cksum = *pCksum; Fts5IndexIter *pIter = 0; - int rc = sqlite3Fts5IndexQuery( - p, z, n, (flags | FTS5INDEX_QUERY_NOTOKENDATA), 0, &pIter - ); + int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter); while( rc==SQLITE_OK && ALWAYS(pIter!=0) && 0==sqlite3Fts5IterEof(pIter) ){ i64 rowid = pIter->iRowid; @@ -248471,7 +235046,7 @@ static void fts5IndexIntegrityCheckEmpty( } static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){ - i64 iTermOff = 0; + int iTermOff = 0; int ii; Fts5Buffer buf1 = {0,0,0}; @@ -248480,7 +235055,7 @@ static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){ ii = pLeaf->szLeaf; while( iinn && p->rc==SQLITE_OK ){ int res; - i64 iOff; + int iOff; int nIncr; ii += fts5GetVarint32(&pLeaf->p[ii], nIncr); @@ -248525,7 +235100,6 @@ static void fts5IndexIntegrityCheckSegment( Fts5StructureSegment *pSeg /* Segment to check internal consistency */ ){ Fts5Config *pConfig = p->pConfig; - int bSecureDelete = (pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE); sqlite3_stmt *pStmt = 0; int rc2; int iIdxPrevLeaf = pSeg->pgnoFirst-1; @@ -248561,19 +235135,7 @@ 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 ){ - - 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; - } - + p->rc = FTS5_CORRUPT; }else{ int iOff; /* Offset of first term on leaf */ int iRowidOff; /* Offset of first rowid on leaf */ @@ -248637,12 +235199,9 @@ static void fts5IndexIntegrityCheckSegment( ASSERT_SZLEAF_OK(pLeaf); if( iRowidOff>=pLeaf->szLeaf ){ p->rc = FTS5_CORRUPT; - }else if( bSecureDelete==0 || iRowidOff>0 ){ - i64 iDlRowid = fts5DlidxIterRowid(pDlidx); + }else{ fts5GetVarint(&pLeaf->p[iRowidOff], (u64*)&iRowid); - if( iRowidrc = FTS5_CORRUPT; - } + if( iRowid!=fts5DlidxIterRowid(pDlidx) ) p->rc = FTS5_CORRUPT; } fts5DataRelease(pLeaf); } @@ -248772,14 +235331,13 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum ** function only. */ -#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) +#ifdef SQLITE_TEST /* ** 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 */ @@ -248795,16 +235353,13 @@ 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 || SQLITE_FTS5_DEBUG */ +#endif /* SQLITE_TEST */ -#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) +#ifdef SQLITE_TEST static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){ - int iSegid, iHeight, iPgno, bDlidx, bTomb; /* Rowid compenents */ - fts5DecodeRowid(iKey, &bTomb, &iSegid, &bDlidx, &iHeight, &iPgno); + int iSegid, iHeight, iPgno, bDlidx; /* Rowid compenents */ + fts5DecodeRowid(iKey, &iSegid, &bDlidx, &iHeight, &iPgno); if( iSegid==0 ){ if( iKey==FTS5_AVERAGES_ROWID ){ @@ -248814,16 +235369,14 @@ static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){ } } else{ - sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{%s%ssegid=%d h=%d pgno=%d}", - bDlidx ? "dlidx " : "", - bTomb ? "tombstone " : "", - iSegid, iHeight, iPgno + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{%ssegid=%d h=%d pgno=%d}", + bDlidx ? "dlidx " : "", iSegid, iHeight, iPgno ); } } -#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */ +#endif /* SQLITE_TEST */ -#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) +#ifdef SQLITE_TEST static void fts5DebugStructure( int *pRc, /* IN/OUT: error code */ Fts5Buffer *pBuf, @@ -248838,22 +235391,16 @@ static void fts5DebugStructure( ); for(iSeg=0; iSegnSeg; iSeg++){ Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg]; - sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d", + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d}", pSeg->iSegid, pSeg->pgnoFirst, pSeg->pgnoLast ); - if( pSeg->iOrigin1>0 ){ - sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " origin=%lld..%lld", - pSeg->iOrigin1, pSeg->iOrigin2 - ); - } - sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "}"); } sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "}"); } } -#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */ +#endif /* SQLITE_TEST */ -#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) +#ifdef SQLITE_TEST /* ** This is part of the fts5_decode() debugging aid. ** @@ -248878,9 +235425,9 @@ static void fts5DecodeStructure( fts5DebugStructure(pRc, pBuf, p); fts5StructureRelease(p); } -#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */ +#endif /* SQLITE_TEST */ -#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) +#ifdef SQLITE_TEST /* ** This is part of the fts5_decode() debugging aid. ** @@ -248903,9 +235450,9 @@ static void fts5DecodeAverages( zSpace = " "; } } -#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */ +#endif /* SQLITE_TEST */ -#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) +#ifdef SQLITE_TEST /* ** Buffer (a/n) is assumed to contain a list of serialized varints. Read ** each varint and append its string representation to buffer pBuf. Return @@ -248922,9 +235469,9 @@ static int fts5DecodePoslist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){ } return iOff; } -#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */ +#endif /* SQLITE_TEST */ -#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) +#ifdef SQLITE_TEST /* ** 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 @@ -248957,9 +235504,9 @@ static int fts5DecodeDoclist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){ return iOff; } -#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */ +#endif /* SQLITE_TEST */ -#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) +#ifdef SQLITE_TEST /* ** This function is part of the fts5_decode() debugging function. It is ** only ever used with detail=none tables. @@ -249000,27 +235547,9 @@ static void fts5DecodeRowidList( sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp); } } -#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */ - -#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; iin; 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 */ +#endif /* SQLITE_TEST */ -#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) +#ifdef SQLITE_TEST /* ** The implementation of user-defined scalar function fts5_decode(). */ @@ -249031,7 +235560,6 @@ 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 */ @@ -249054,7 +235582,7 @@ static void fts5DecodeFunction( if( a==0 ) goto decode_out; if( n>0 ) memcpy(a, aBlob, n); - fts5DecodeRowid(iRowid, &bTomb, &iSegid, &bDlidx, &iHeight, &iPgno); + fts5DecodeRowid(iRowid, &iSegid, &bDlidx, &iHeight, &iPgno); fts5DebugRowid(&rc, &s, iRowid); if( bDlidx ){ @@ -249073,28 +235601,6 @@ 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; - sqlite3Fts5BufferAppendPrintf(&rc, &s, " nElem=%d", (int)nElem); - if( aBlob[1] ){ - sqlite3Fts5BufferAppendPrintf(&rc, &s, " 0"); - } - for(ii=0; iiszLeaf ){ - rc = FTS5_CORRUPT; - }else{ - fts5DecodeRowidList(&rc, &s, &a[iOff], iTermOff-iOff); - } + + fts5DecodeRowidList(&rc, &s, &a[iOff], iTermOff-iOff); iOff = iTermOff; if( iOffestimatedCost = (double)100; - pIdxInfo->estimatedRows = 100; - pIdxInfo->idxNum = 0; - for(i=0, p=pIdxInfo->aConstraint; inConstraint; 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(sqlite3_vtab *pVtab){ - Fts5StructVtab *p = (Fts5StructVtab*)pVtab; - sqlite3_free(p); - return SQLITE_OK; -} - -/* -** Constructor for a new bytecodevtab_cursor object. -*/ -static int fts5structOpenMethod(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCsr){ - int rc = SQLITE_OK; - Fts5StructVcsr *pNew = 0; - - pNew = sqlite3Fts5MallocZero(&rc, sizeof(*pNew)); - *ppCsr = (sqlite3_vtab_cursor*)pNew; - - return SQLITE_OK; -} - -/* -** Destructor for a bytecodevtab_cursor. -*/ -static int fts5structCloseMethod(sqlite3_vtab_cursor *cur){ - Fts5StructVcsr *pCsr = (Fts5StructVcsr*)cur; - fts5StructureRelease(pCsr->pStruct); - sqlite3_free(pCsr); - return SQLITE_OK; -} - - -/* -** Advance a bytecodevtab_cursor to its next row of output. -*/ -static int fts5structNextMethod(sqlite3_vtab_cursor *cur){ - Fts5StructVcsr *pCsr = (Fts5StructVcsr*)cur; - Fts5Structure *p = pCsr->pStruct; - - assert( pCsr->pStruct ); - pCsr->iSeg++; - pCsr->iRowid++; - while( pCsr->iLevelnLevel && 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(sqlite3_vtab_cursor *cur){ - Fts5StructVcsr *pCsr = (Fts5StructVcsr*)cur; - return pCsr->pStruct==0; -} - -static int fts5structRowidMethod( - 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( - sqlite3_vtab_cursor *cur, /* The cursor */ - sqlite3_context *ctx, /* First argument to 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 */ - sqlite3_result_int(ctx, pCsr->iLevel); - break; - case 1: /* segment */ - sqlite3_result_int(ctx, pCsr->iSeg); - break; - case 2: /* merge */ - sqlite3_result_int(ctx, pCsr->iSeg < p->aLevel[pCsr->iLevel].nMerge); - break; - case 3: /* segid */ - sqlite3_result_int(ctx, pSeg->iSegid); - break; - case 4: /* leaf1 */ - sqlite3_result_int(ctx, pSeg->pgnoFirst); - break; - case 5: /* leaf2 */ - sqlite3_result_int(ctx, pSeg->pgnoLast); - break; - case 6: /* origin1 */ - sqlite3_result_int64(ctx, pSeg->iOrigin1); - break; - case 7: /* origin2 */ - sqlite3_result_int64(ctx, pSeg->iOrigin2); - break; - case 8: /* npgtombstone */ - sqlite3_result_int(ctx, pSeg->nPgTombstone); - break; - case 9: /* nentrytombstone */ - sqlite3_result_int64(ctx, pSeg->nEntryTombstone); - break; - case 10: /* nentry */ - 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( - sqlite3_vtab_cursor *pVtabCursor, - int idxNum, const char *idxStr, - int argc, 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 = sqlite3_value_bytes(argv[0]); - aBlob = (const u8*)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 */ +#endif /* SQLITE_TEST */ /* ** This is called as part of registering the FTS5 module with database @@ -249528,7 +235805,7 @@ static int fts5structFilterMethod( ** SQLite error code is returned instead. */ static int sqlite3Fts5IndexInit(sqlite3 *db){ -#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) +#ifdef SQLITE_TEST int rc = sqlite3_create_function( db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0 ); @@ -249545,37 +235822,6 @@ static int sqlite3Fts5IndexInit(sqlite3 *db){ db, "fts5_rowid", -1, SQLITE_UTF8, 0, fts5RowidFunction, 0, 0 ); } - - if( rc==SQLITE_OK ){ - static const 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 = sqlite3_create_module(db, "fts5_structure", &fts5structure_module, 0); - } return rc; #else return SQLITE_OK; @@ -249711,8 +235957,6 @@ 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 @@ -250001,13 +236245,6 @@ static int fts5InitVtab( pConfig->pzErrmsg = 0; } - if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){ - rc = sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, (int)1); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); - } - if( rc!=SQLITE_OK ){ fts5FreeVtab(pTab); pTab = 0; @@ -250250,15 +236487,12 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ } idxStr[iIdxStr] = '\0'; - /* Set idxFlags flags for the ORDER BY clause - ** - ** Note that tokendata=1 tables cannot currently handle "ORDER BY rowid DESC". - */ + /* Set idxFlags flags for the ORDER BY clause */ 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 && (!pInfo->aOrderBy[0].desc || !pConfig->bTokendata) ){ + }else if( iSort==-1 ){ idxFlags |= FTS5_BI_ORDER_ROWID; } if( BitFlagTest(idxFlags, FTS5_BI_ORDER_RANK|FTS5_BI_ORDER_ROWID) ){ @@ -250510,16 +236744,6 @@ static int fts5NextMethod(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 - ){ - sqlite3Fts5ExprClearTokens(pCsr->pExpr); - } - if( pCsr->ePlan<3 ){ int bSkip = 0; if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc; @@ -250945,9 +237169,6 @@ static int fts5FilterMethod( pCsr->iFirstRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64); } - rc = 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 ORDER BY rank" query (ePlan is @@ -250970,7 +237191,6 @@ 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 ){ @@ -251142,7 +237362,6 @@ static int fts5SpecialInsert( Fts5Config *pConfig = pTab->p.pConfig; int rc = SQLITE_OK; int bError = 0; - int bLoadConfig = 0; if( 0==sqlite3_stricmp("delete-all", zCmd) ){ if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ @@ -251154,7 +237373,6 @@ static int fts5SpecialInsert( }else{ rc = sqlite3Fts5StorageDeleteAll(pTab->pStorage); } - bLoadConfig = 1; }else if( 0==sqlite3_stricmp("rebuild", zCmd) ){ if( pConfig->eContent==FTS5_CONTENT_NONE ){ fts5SetVtabError(pTab, @@ -251164,7 +237382,6 @@ static int fts5SpecialInsert( }else{ rc = sqlite3Fts5StorageRebuild(pTab->pStorage); } - bLoadConfig = 1; }else if( 0==sqlite3_stricmp("optimize", zCmd) ){ rc = sqlite3Fts5StorageOptimize(pTab->pStorage); }else if( 0==sqlite3_stricmp("merge", zCmd) ){ @@ -251177,13 +237394,8 @@ static int fts5SpecialInsert( }else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){ pConfig->bPrefixIndex = sqlite3_value_int(pVal); #endif - }else if( 0==sqlite3_stricmp("flush", zCmd) ){ - rc = sqlite3Fts5FlushToDisk(&pTab->p); }else{ - rc = sqlite3Fts5FlushToDisk(&pTab->p); - if( rc==SQLITE_OK ){ - rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); - } + rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); if( rc==SQLITE_OK ){ rc = sqlite3Fts5ConfigSetValue(pTab->p.pConfig, zCmd, pVal, &bError); } @@ -251195,12 +237407,6 @@ static int fts5SpecialInsert( } } } - - if( rc==SQLITE_OK && bLoadConfig ){ - pTab->p.pConfig->iCookie--; - rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); - } - return rc; } @@ -251257,7 +237463,6 @@ 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 ); @@ -251268,11 +237473,6 @@ static int fts5UpdateMethod( || sqlite3_value_type(apVal[0])==SQLITE_NULL ); assert( pTab->p.pConfig->pzErrmsg==0 ); - if( pConfig->pgsz==0 ){ - rc = 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. */ @@ -251287,15 +237487,7 @@ static int fts5UpdateMethod( if( pConfig->eContent!=FTS5_CONTENT_NORMAL && 0==sqlite3_stricmp("delete", z) ){ - 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; - } + rc = fts5SpecialDelete(pTab, apVal); }else{ rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]); } @@ -251312,7 +237504,7 @@ static int fts5UpdateMethod( ** Cases 3 and 4 may violate the rowid constraint. */ int eConflict = SQLITE_ABORT; - if( pConfig->eContent==FTS5_CONTENT_NORMAL || pConfig->bContentlessDelete ){ + if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ eConflict = sqlite3_vtab_on_conflict(pConfig->db); } @@ -251320,12 +237512,8 @@ static int fts5UpdateMethod( assert( nArg!=1 || eType0==SQLITE_INTEGER ); /* Filter out attempts to run UPDATE or DELETE on contentless tables. - ** 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 - ){ + ** This is not suported. */ + if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){ pTab->p.base.zErrMsg = sqlite3_mprintf( "cannot %s contentless fts5 table: %s", (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName @@ -251337,7 +237525,6 @@ static int fts5UpdateMethod( else if( nArg==1 ){ i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0); - bUpdateOrDelete = 1; } /* INSERT or UPDATE */ @@ -251349,12 +237536,10 @@ static int fts5UpdateMethod( } else if( eType0!=SQLITE_INTEGER ){ - /* An INSERT statement. If the conflict-mode is REPLACE, first remove - ** the current entry (if any). */ + /* If this is a REPLACE, first remove the current entry (if any) */ if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){ i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); - bUpdateOrDelete = 1; } fts5StorageInsert(&rc, pTab, apVal, pRowid); } @@ -251383,24 +237568,10 @@ static int fts5UpdateMethod( rc = 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 = 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; } @@ -251413,7 +237584,8 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){ Fts5FullTable *pTab = (Fts5FullTable*)pVtab; fts5CheckTransactionState(pTab, FTS5_SYNC, 0); pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg; - rc = sqlite3Fts5FlushToDisk(&pTab->p); + fts5TripCursors(pTab); + rc = sqlite3Fts5StorageSync(pTab->pStorage); pTab->p.pConfig->pzErrmsg = 0; return rc; } @@ -251509,10 +237681,7 @@ static int fts5ApiColumnText( ){ int rc = SQLITE_OK; Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); - if( iCol<0 || iCol>=pTab->pConfig->nCol ){ - rc = SQLITE_RANGE; - }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) + if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) || pCsr->ePlan==FTS5_PLAN_SPECIAL ){ *pz = 0; @@ -251537,9 +237706,8 @@ static int fts5CsrPoslist( int rc = SQLITE_OK; int bLive = (pCsr->pSorter==0); - if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){ - rc = SQLITE_RANGE; - }else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){ + if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){ + if( pConfig->eDetail!=FTS5_DETAIL_FULL ){ Fts5PoslistPopulator *aPopulator; int i; @@ -251563,21 +237731,15 @@ static int fts5CsrPoslist( CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST); } - 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 = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa); - } + 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{ - *pa = 0; - *pn = 0; + *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa); } - return rc; } @@ -251684,6 +237846,12 @@ 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]; @@ -251938,56 +238106,13 @@ 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 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 = 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 = { - 3, /* iVersion */ + 2, /* iVersion */ fts5ApiUserData, fts5ApiColumnCount, fts5ApiRowCount, @@ -252007,8 +238132,6 @@ static const Fts5ExtensionApi sFts5Api = { fts5ApiPhraseNext, fts5ApiPhraseFirstColumn, fts5ApiPhraseNextColumn, - fts5ApiQueryToken, - fts5ApiInstToken }; /* @@ -252229,12 +238352,6 @@ static int fts5ColumnMethod( sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1)); } pConfig->pzErrmsg = 0; - }else if( pConfig->bContentlessDelete && sqlite3_vtab_nochange(pCtx) ){ - char *zErr = sqlite3_mprintf("cannot UPDATE a subset of " - "columns on fts5 contentless-delete table: %s", pConfig->zName - ); - sqlite3_result_error(pCtx, zErr, -1); - sqlite3_free(zErr); } return rc; } @@ -252273,10 +238390,8 @@ static int fts5RenameMethod( sqlite3_vtab *pVtab, /* Virtual table handle */ const char *zName /* New name of table */ ){ - int rc; Fts5FullTable *pTab = (Fts5FullTable*)pVtab; - rc = sqlite3Fts5StorageRename(pTab->pStorage, zName); - return rc; + return sqlite3Fts5StorageRename(pTab->pStorage, zName); } static int sqlite3Fts5FlushToDisk(Fts5Table *pTab){ @@ -252290,15 +238405,9 @@ static int sqlite3Fts5FlushToDisk(Fts5Table *pTab){ ** Flush the contents of the pending-terms table to disk. */ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ - Fts5FullTable *pTab = (Fts5FullTable*)pVtab; - int rc = SQLITE_OK; - - fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint); - rc = sqlite3Fts5FlushToDisk((Fts5Table*)pVtab); - if( rc==SQLITE_OK ){ - pTab->iSavepoint = iSavepoint+1; - } - return rc; + UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ + fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_SAVEPOINT, iSavepoint); + return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab); } /* @@ -252307,16 +238416,9 @@ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ ** This is a no-op. */ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ - Fts5FullTable *pTab = (Fts5FullTable*)pVtab; - int rc = SQLITE_OK; - fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint); - if( (iSavepoint+1)iSavepoint ){ - rc = sqlite3Fts5FlushToDisk(&pTab->p); - if( rc==SQLITE_OK ){ - pTab->iSavepoint = iSavepoint; - } - } - return rc; + UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ + fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_RELEASE, iSavepoint); + return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab); } /* @@ -252326,14 +238428,10 @@ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ */ static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ Fts5FullTable *pTab = (Fts5FullTable*)pVtab; - int rc = SQLITE_OK; + UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint); fts5TripCursors(pTab); - if( (iSavepoint+1)<=pTab->iSavepoint ){ - pTab->p.pConfig->pgsz = 0; - rc = sqlite3Fts5StorageRollback(pTab->pStorage); - } - return rc; + return sqlite3Fts5StorageRollback(pTab->pStorage); } /* @@ -252469,16 +238567,14 @@ static int sqlite3Fts5GetTokenizer( if( pMod==0 ){ assert( nArg>0 ); rc = SQLITE_ERROR; - if( pzErr ) *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]); + *pzErr = 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 && rc!=SQLITE_NOMEM ){ - *pzErr = sqlite3_mprintf("error in tokenizer constructor"); - } + if( pzErr ) *pzErr = sqlite3_mprintf("error in tokenizer constructor"); }else{ pConfig->ePattern = sqlite3Fts5TokenizerPattern( pMod->x.xCreate, pConfig->pTok @@ -252537,7 +238633,7 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2022-12-28 14:03:47 df5c253c0b3dd24916e4ec7cf77d3db5294cc9fd45ae7b9c5e82ad8197f38a24", -1, SQLITE_TRANSIENT); } /* @@ -252555,47 +238651,9 @@ 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( - 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 = sqlite3Fts5StorageIntegrity(pTab->pStorage, 0); - if( *pzErr==0 && rc!=SQLITE_OK ){ - if( (rc&0xff)==SQLITE_CORRUPT ){ - *pzErr = sqlite3_mprintf("malformed inverted index for FTS5 table %s.%s", - zSchema, zTabname); - rc = (*pzErr) ? SQLITE_OK : SQLITE_NOMEM; - }else{ - *pzErr = sqlite3_mprintf("unable to validate the inverted index for" - " FTS5 table %s.%s: %s", - zSchema, zTabname, sqlite3_errstr(rc)); - } - } - - sqlite3Fts5IndexCloseReader(pTab->p.pIndex); - pTab->p.pConfig->pzErrmsg = 0; - - return rc; -} - static int fts5Init(sqlite3 *db){ static const sqlite3_module fts5Mod = { - /* iVersion */ 4, + /* iVersion */ 3, /* xCreate */ fts5CreateMethod, /* xConnect */ fts5ConnectMethod, /* xBestIndex */ fts5BestIndexMethod, @@ -252618,8 +238676,7 @@ static int fts5Init(sqlite3 *db){ /* xSavepoint */ fts5SavepointMethod, /* xRelease */ fts5ReleaseMethod, /* xRollbackTo */ fts5RollbackToMethod, - /* xShadowName */ fts5ShadowName, - /* xIntegrity */ fts5IntegrityMethod + /* xShadowName */ fts5ShadowName }; int rc; @@ -252649,9 +238706,7 @@ static int fts5Init(sqlite3 *db){ } if( rc==SQLITE_OK ){ rc = sqlite3_create_function( - db, "fts5_source_id", 0, - SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS, - p, fts5SourceIdFunc, 0, 0 + db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0 ); } } @@ -252789,10 +238844,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(?,?%s)", /* REPLACE_DOCSIZE */ + "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)", /* REPLACE_DOCSIZE */ "DELETE FROM %Q.'%q_docsize' WHERE id=?", /* DELETE_DOCSIZE */ - "SELECT sz%s FROM %Q.'%q_docsize' WHERE id=?", /* LOOKUP_DOCSIZE */ + "SELECT sz FROM %Q.'%q_docsize' WHERE id=?", /* LOOKUP_DOCSIZE */ "REPLACE INTO %Q.'%q_config' VALUES(?,?)", /* REPLACE_CONFIG */ "SELECT %s FROM %s AS T", /* SCAN */ @@ -252840,19 +238895,6 @@ static int fts5StorageGetStmt( break; } - case FTS5_STMT_REPLACE_DOCSIZE: - zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName, - (pC->bContentlessDelete ? ",?" : "") - ); - break; - - case FTS5_STMT_LOOKUP_DOCSIZE: - zSql = sqlite3_mprintf(azStmt[eStmt], - (pC->bContentlessDelete ? ",origin" : ""), - pC->zDb, pC->zName - ); - break; - default: zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName); break; @@ -253042,11 +239084,9 @@ static int sqlite3Fts5StorageOpen( } if( rc==SQLITE_OK && pConfig->bColumnsize ){ - const char *zCols = "id INTEGER PRIMARY KEY, sz BLOB"; - if( pConfig->bContentlessDelete ){ - zCols = "id INTEGER PRIMARY KEY, sz BLOB, origin INTEGER"; - } - rc = sqlite3Fts5CreateTable(pConfig, "docsize", zCols, 0, pzErr); + rc = sqlite3Fts5CreateTable( + pConfig, "docsize", "id INTEGER PRIMARY KEY, sz BLOB", 0, pzErr + ); } if( rc==SQLITE_OK ){ rc = sqlite3Fts5CreateTable( @@ -253123,7 +239163,7 @@ static int fts5StorageDeleteFromIndex( ){ Fts5Config *pConfig = p->pConfig; sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */ - int rc = SQLITE_OK; /* Return code */ + int rc; /* Return code */ int rc2; /* sqlite3_reset() return code */ int iCol; Fts5InsertCtx ctx; @@ -253139,6 +239179,7 @@ static int fts5StorageDeleteFromIndex( ctx.pStorage = p; ctx.iCol = -1; + rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel); for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){ if( pConfig->abUnindexed[iCol-1]==0 ){ const char *zText; @@ -253175,37 +239216,6 @@ 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; - 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 ){ - sqlite3_bind_int64(pLookup, 1, iDel); - if( SQLITE_ROW==sqlite3_step(pLookup) ){ - iOrigin = sqlite3_column_int64(pLookup, 1); - } - rc = sqlite3_reset(pLookup); - } - - if( rc==SQLITE_OK && iOrigin!=0 ){ - rc = sqlite3Fts5IndexContentlessDelete(p->pIndex, iOrigin, iDel); - } - - return rc; -} /* ** Insert a record into the %_docsize table. Specifically, do: @@ -253226,17 +239236,10 @@ static int fts5StorageInsertDocsize( rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64(pReplace, 1, iRowid); - if( p->pConfig->bContentlessDelete ){ - i64 iOrigin = 0; - rc = sqlite3Fts5IndexGetOrigin(p->pIndex, &iOrigin); - sqlite3_bind_int64(pReplace, 3, iOrigin); - } - if( rc==SQLITE_OK ){ - sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC); - sqlite3_step(pReplace); - rc = sqlite3_reset(pReplace); - sqlite3_bind_null(pReplace, 2); - } + sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC); + sqlite3_step(pReplace); + rc = sqlite3_reset(pReplace); + sqlite3_bind_null(pReplace, 2); } } return rc; @@ -253300,15 +239303,7 @@ static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **ap /* Delete the index records */ if( rc==SQLITE_OK ){ - rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel); - } - - if( rc==SQLITE_OK ){ - if( p->pConfig->bContentlessDelete ){ - rc = fts5StorageContentlessDelete(p, iDel); - }else{ - rc = fts5StorageDeleteFromIndex(p, iDel, apVal); - } + rc = fts5StorageDeleteFromIndex(p, iDel, apVal); } /* Delete the %_docsize record */ @@ -253385,7 +239380,7 @@ static int sqlite3Fts5StorageRebuild(Fts5Storage *p){ } if( rc==SQLITE_OK ){ - rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, pConfig->pzErrmsg); + rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0); } while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pScan) ){ @@ -253896,9 +239891,7 @@ static int sqlite3Fts5StorageSync(Fts5Storage *p){ i64 iLastRowid = sqlite3_last_insert_rowid(p->pConfig->db); if( p->bTotalsValid ){ rc = fts5StorageSaveTotals(p); - if( rc==SQLITE_OK ){ - p->bTotalsValid = 0; - } + p->bTotalsValid = 0; } if( rc==SQLITE_OK ){ rc = sqlite3Fts5IndexSync(p->pIndex); @@ -254022,7 +240015,7 @@ static int fts5AsciiCreate( int i; memset(p, 0, sizeof(AsciiTokenizer)); memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar)); - for(i=0; rc==SQLITE_OK && i=0xc0 ){ \ - while( (((unsigned char)*zIn) & 0xc0)==0x80 ){ zIn++; } \ - } \ -} - typedef struct Unicode61Tokenizer Unicode61Tokenizer; struct Unicode61Tokenizer { unsigned char aTokenChar[128]; /* ASCII range token characters */ @@ -254325,16 +240311,17 @@ static int fts5UnicodeCreate( } /* Search for a "categories" argument */ - for(i=0; rc==SQLITE_OK && ibFold = 1; - pNew->iFoldParam = 0; - for(i=0; rc==SQLITE_OK && ibFold = (zArg[0]=='0'); } - }else if( 0==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( iiFoldParam!=0 && pNew->bFold==0 ){ - rc = SQLITE_ERROR; - } - if( rc!=SQLITE_OK ){ fts5TriDelete((Fts5Tokenizer*)pNew); pNew = 0; @@ -255288,62 +241260,40 @@ 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); - - /* 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 ) return SQLITE_OK; - if( p->bFold ) iCode = 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; + 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( zInbFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0); + WRITE_UTF8(zOut, iCode); READ_UTF8(zIn, zEof, iCode); if( iCode==0 ) break; - if( p->bFold ) iCode = 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; + }else{ + break; + } + if( zInbFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0); + WRITE_UTF8(zOut, iCode); + READ_UTF8(zIn, zEof, iCode); + if( iCode==0 ) break; + if( p->bFold ) iCode = 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; } return rc; @@ -255366,9 +241316,7 @@ static int sqlite3Fts5TokenizerPattern( ){ if( xCreate==fts5TriCreate ){ TrigramTokenizer *p = (TrigramTokenizer*)pTok; - if( p->iFoldParam==0 ){ - return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB; - } + return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB; } return FTS5_PATTERN_NONE; } @@ -257157,7 +243105,7 @@ static int fts5VocabFilterMethod( if( pEq ){ zTerm = (const char *)sqlite3_value_text(pEq); nTerm = sqlite3_value_bytes(pEq); - f = FTS5INDEX_QUERY_NOTOKENDATA; + f = 0; }else{ if( pGe ){ zTerm = (const char *)sqlite3_value_text(pGe); @@ -257311,8 +243259,7 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){ /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, - /* xShadowName */ 0, - /* xIntegrity */ 0 + /* xShadowName */ 0 }; void *p = (void*)pGlobal; @@ -257424,10 +243371,6 @@ static int stmtConnect( #define STMT_COLUMN_MEM 10 /* SQLITE_STMTSTATUS_MEMUSED */ - (void)pAux; - (void)argc; - (void)argv; - (void)pzErr; rc = sqlite3_declare_vtab(db, "CREATE TABLE x(sql,ncol,ro,busy,nscan,nsort,naidx,nstep," "reprep,run,mem)"); @@ -257547,10 +243490,6 @@ static int stmtFilter( sqlite3_int64 iRowid = 1; StmtRow **ppRow = 0; - (void)idxNum; - (void)idxStr; - (void)argc; - (void)argv; stmtCsrReset(pCur); ppRow = &pCur->pRow; for(p=sqlite3_next_stmt(pCur->db, 0); p; p=sqlite3_next_stmt(pCur->db, p)){ @@ -257606,7 +243545,6 @@ static int stmtBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ - (void)tab; pIdxInfo->estimatedCost = (double)500; pIdxInfo->estimatedRows = 500; return SQLITE_OK; @@ -257641,7 +243579,6 @@ static sqlite3_module stmtModule = { 0, /* xRelease */ 0, /* xRollbackTo */ 0, /* xShadowName */ - 0 /* xIntegrity */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ -- Gitee From 696890a3d2abf7f83afcdb35661e0abca916ffd3 Mon Sep 17 00:00:00 2001 From: wanghaishuo Date: Fri, 11 Apr 2025 17:36:47 +0800 Subject: [PATCH 2/9] codec, query sharedmemory, drop table callback Signed-off-by: ryne3366 --- src/sqlite3.c | 2863 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 2823 insertions(+), 40 deletions(-) diff --git a/src/sqlite3.c b/src/sqlite3.c index 3469f92..a935685 100644 --- a/src/sqlite3.c +++ b/src/sqlite3.c @@ -870,6 +870,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) +#define SQLITE_WARNING_DUMP (SQLITE_WARNING | (2<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) #define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */ @@ -2832,6 +2833,11 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); */ SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); +#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION +#define SQLITE_DBCONFIG_SET_SHAREDBLOCK 2004 +#define SQLITE_DBCONFIG_USE_SHAREDBLOCK 2005 +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ + /* ** CAPI3REF: Set the Last Insert Rowid value. ** METHOD: sqlite3 @@ -5174,6 +5180,10 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); */ SQLITE_API int sqlite3_step(sqlite3_stmt*); +#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK +SQLITE_API int sqlite3_set_droptable_handle(sqlite3*, void (*xFunc)(sqlite3*,const char*,const char*)); +#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ + /* ** CAPI3REF: Number of columns in a result set ** METHOD: sqlite3_stmt @@ -6439,6 +6449,44 @@ SQLITE_API int sqlite3_collation_needed16( void(*)(void*,sqlite3*,int eTextRep,const void*) ); +#ifdef SQLITE_HAS_CODEC +/* +** Specify the key for an encrypted database. This routine should be +** called right after sqlite3_open(). +** +** The code to implement this API is not available in the public release +** of SQLite. +*/ +SQLITE_API int sqlite3_key( + sqlite3 *db, /* Database to be rekeyed */ + const void *pKey, int nKey /* The key */ +); +SQLITE_API int sqlite3_key_v2( + sqlite3 *db, /* Database to be rekeyed */ + const char *zDbName, /* Name of the database */ + const void *pKey, int nKey /* The key */ +); + +/* +** Change the key on an open database. If the current database is not +** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the +** database is decrypted. +** +** The code to implement this API is not available in the public release +** of SQLite. +*/ +SQLITE_API int sqlite3_rekey( + sqlite3 *db, /* Database to be rekeyed */ + const void *pKey, int nKey /* The new key */ +); +SQLITE_API int sqlite3_rekey_v2( + sqlite3 *db, /* Database to be rekeyed */ + const char *zDbName, /* Name of the database */ + const void *pKey, int nKey /* The new key */ +); + +#endif /* SQLITE_HAS_CODEC */ + #ifdef SQLITE_ENABLE_CEROD /* ** Specify the activation key for a CEROD database. Unless @@ -9872,6 +9920,27 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); */ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); +#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION +typedef struct Sqlite3SharedBlockMethods Sqlite3SharedBlockMethods; +struct Sqlite3SharedBlockMethods { + int iVersion; + void* pContext; + int countAllRows; + int startPos; + int requiredPos; + int (*xAddRow)(void* pCtx, int addedRows); + int (*xReset)(void* pCtx, int startPos); + int (*xFinish)(void* pCtx, int addedRows, int totalRows); + int (*xPutString)(void *pCtx, int addedRows, int column, const char* text, int len); + int (*xPutLong)(void *pCtx, int addedRows, int column, sqlite3_int64 value); + int (*xPutDouble)(void *pCtx, int addedRows, int column, double value); + int (*xPutBlob)(void *pCtx, int addedRows, int column, const void* blob, int len); + int (*xPutNull)(void *pCtx, int addedRows, int column); + int (*xPutOther)(void *pCtx, int addedRows, int column); + /* Additional methods may be added in future releases */ +}; +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ + /* ** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE ** @@ -14914,13 +14983,6 @@ typedef int VList; # 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 */ @@ -15234,6 +15296,9 @@ SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); /* Functions used to configure a Pager object. */ SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *); SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int); +#ifdef SQLITE_HAS_CODEC +SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager*, Pager*); +#endif /* SQLITE_HAS_CODEC */ SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager*, Pgno); SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int); SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int); @@ -15330,6 +15395,10 @@ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno); SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16); +#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) +SQLITE_PRIVATE void *sqlite3PagerCodec(DbPage *); +#endif /* defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) */ + /* Functions to support testing and debugging. */ #if !defined(NDEBUG) || defined(SQLITE_TEST) SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*); @@ -16933,6 +17002,21 @@ SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**); */ #define SQLITE_MAX_DB (SQLITE_MAX_ATTACHED+2) +#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK +typedef void (*sqlite3_xDropTableHandle)(sqlite3*, const char*, const char*); +#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ + +#if defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) +typedef struct CodecParameter { + int kdfIter; + int pageSize; + u8 cipher; + u8 hmacAlgo; + u8 kdfAlgo; + u8 reserved; +} CodecParameter; +#endif /* defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) */ + /* ** Each database connection is an instance of the following structure. */ @@ -17076,6 +17160,15 @@ struct sqlite3 { #ifdef SQLITE_USER_AUTHENTICATION sqlite3_userauth auth; /* User authentication information */ #endif +#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK + unsigned int isDropTable; + char *mDropTableName; + char *mDropSchemaName; + sqlite3_xDropTableHandle xDropTableHandle; /* User drop table callback */ +#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ +#if defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) + CodecParameter codecParm; +#endif /* defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) */ }; /* @@ -20046,7 +20139,14 @@ SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u32,Select*); SQLITE_PRIVATE void sqlite3AddReturning(Parse*,ExprList*); SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*, sqlite3_vfs**,char**,char **); -#define sqlite3CodecQueryParameters(A,B,C) 0 +#ifdef SQLITE_HAS_CODEC +SQLITE_PRIVATE int sqlite3CodecQueryParameters(sqlite3*,const char*,const char*); +#else +# define sqlite3CodecQueryParameters(A,B,C) 0 +#endif /* SQLITE_HAS_CODEC */ +#if defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) +SQLITE_PRIVATE void sqlite3CodecResetParameters(CodecParameter *p); +#endif /* defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) */ SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*); #ifdef SQLITE_UNTESTABLE @@ -21098,6 +21198,10 @@ SQLITE_API extern int sqlite3_open_file_count; #define OpenCounter(X) #endif /* defined(SQLITE_TEST) */ +#ifdef FDSAN_ENABLE +#define SQLITE_FDSAN_TAG 5351 +#endif /* FDSAN_ENABLE */ + #endif /* !defined(_OS_COMMON_H_) */ /************** End of os_common.h *******************************************/ @@ -21480,6 +21584,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_FTS5_NO_WITHOUT_ROWID "FTS5_NO_WITHOUT_ROWID", #endif +#if SQLITE_HAS_CODEC + "HAS_CODEC", +#endif #if HAVE_ISNAN || SQLITE_HAVE_ISNAN "HAVE_ISNAN", #endif @@ -21488,6 +21595,9 @@ static const char * const sqlite3azCompileOpt[] = { "HOMEGROWN_RECURSIVE_MUTEX=" CTIMEOPT_VAL(SQLITE_HOMEGROWN_RECURSIVE_MUTEX), # endif #endif +#if SQLITE_SHARED_BLOCK_OPTIMIZATION + "SHARED_BLOCK_OPTIMIZATION", +#endif #ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS "IGNORE_AFP_LOCK_ERRORS", #endif @@ -22057,9 +22167,16 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { ** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally ** disabled. The default value may be changed by compiling with the ** SQLITE_USE_URI symbol defined. +** +** URI filenames are enabled by default if SQLITE_HAS_CODEC is +** enabled. */ #ifndef SQLITE_USE_URI -# define SQLITE_USE_URI 0 +# ifdef SQLITE_HAS_CODEC +# define SQLITE_USE_URI 1 +# else +# define SQLITE_USE_URI 0 +# endif /* SQLITE_HAS_CODEC */ #endif /* EVIDENCE-OF: R-38720-18127 The default setting is determined by the @@ -22797,6 +22914,13 @@ struct Vdbe { int nScan; /* Entries in aScan[] */ ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */ #endif +#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION + Sqlite3SharedBlockMethods *pSharedBlock; + int totalRows; + int blockFull; + int startPos; + int addedRows; +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ }; /* @@ -31163,7 +31287,11 @@ SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ */ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ StrAccum acc; /* String accumulator */ +#ifndef LOG_DUMP char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ +#else + char zMsg[SQLITE_PRINT_BUF_SIZE*10]; /* Complete log message */ +#endif /* !LOG_DUMP */ sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); sqlite3_str_vappendf(&acc, zFormat, ap); @@ -34841,7 +34969,7 @@ SQLITE_PRIVATE u8 sqlite3HexToInt(int h){ return (u8)(h & 0xf); } -#if !defined(SQLITE_OMIT_BLOB_LITERAL) +#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) /* ** Convert a BLOB literal of the form "x'hhhhhh'" into its binary ** value. Return a pointer to its binary value. Space to hold the @@ -34862,7 +34990,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){ } return zBlob; } -#endif /* !SQLITE_OMIT_BLOB_LITERAL */ +#endif /* !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) */ /* ** Log an error that is an API call on a connection pointer that should @@ -37023,6 +37151,29 @@ static pid_t randomnessPid = 0; #define F2FS_FEATURE_ATOMIC_WRITE 0x0004 #endif /* __linux__ */ +#ifdef HARMONY_OS +#define HMFS_MONITOR_FL 0x00000002 +#define HMFS_IOCTL_HW_GET_FLAGS _IOR(0xf5, 70, unsigned int) +#define HMFS_IOCTL_HW_SET_FLAGS _IOR(0xf5, 71, unsigned int) + +static void enableDbFileDelMonitor(int32_t fd) +{ + unsigned int flags = 0; + int ret = ioctl(fd, HMFS_IOCTL_HW_GET_FLAGS, &flags); + if (ret < 0) { + return; + } + if (flags & HMFS_MONITOR_FL) { + return; + } + flags |= HMFS_MONITOR_FL; + ret = ioctl(fd, HMFS_IOCTL_HW_SET_FLAGS, &flags); + if (ret < 0) { + sqlite3_log(SQLITE_WARNING, "Fd %d enable del monitor go wrong, errno = %d", fd, errno); + } +} + +#endif /* HARMONY_OS */ /* ** Different Unix systems declare open() in different ways. Same use @@ -37033,7 +37184,29 @@ static pid_t randomnessPid = 0; ** which always has the same well-defined interface. */ static int posixOpen(const char *zFile, int flags, int mode){ - return open(zFile, flags, mode); + int fd = open(zFile, flags, mode); +#ifdef FDSAN_ENABLE + if( fd >= 0 ){ + fdsan_exchange_owner_tag(fd, 0, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, SQLITE_FDSAN_TAG)); + } +#endif /* FDSAN_ENABLE */ +#ifdef HARMONY_OS + if( fd >= 0 ){ + enableDbFileDelMonitor(fd); + } +#endif /* HARMONY_OS */ + return fd; +} + +/* +** Change close to posixClose, use fdsan_close_with_tag when fdsan enable. +*/ +static int posixClose(int fd) { +#ifdef FDSAN_ENABLE + return fdsan_close_with_tag(fd, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, SQLITE_FDSAN_TAG)); +#else + return close(fd); +#endif /* FDSAN_ENABLE */ } /* Forward reference */ @@ -37054,7 +37227,7 @@ static struct unix_syscall { { "open", (sqlite3_syscall_ptr)posixOpen, 0 }, #define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent) - { "close", (sqlite3_syscall_ptr)close, 0 }, + { "close", (sqlite3_syscall_ptr)posixClose, 0 }, #define osClose ((int(*)(int))aSyscall[1].pCurrent) { "access", (sqlite3_syscall_ptr)access, 0 }, @@ -38048,6 +38221,9 @@ static int findInodeInfo( #if defined(EOVERFLOW) && defined(SQLITE_DISABLE_LFS) if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS; #endif +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR, "findInodeInfo-osFstat, fd[%d], errno[%d], osFstat[%d]", fd, errno, rc); +#endif /* LOG_DUMP */ return SQLITE_IOERR; } @@ -38066,11 +38242,17 @@ static int findInodeInfo( do{ rc = osWrite(fd, "S", 1); }while( rc<0 && errno==EINTR ); if( rc!=1 ){ storeLastErrno(pFile, errno); +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR, "findInodeInfo-osWrite, fd[%d], errno[%d], osFstat[%d]", fd, errno, rc); +#endif /* LOG_DUMP */ return SQLITE_IOERR; } rc = osFstat(fd, &statbuf); if( rc!=0 ){ storeLastErrno(pFile, errno); +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR, "findInodeInfo-msdos-osFstat, fd[%d], errno[%d], osFstat[%d]", fd, errno, rc); +#endif /* LOG_DUMP */ return SQLITE_IOERR; } } @@ -39232,6 +39414,9 @@ static int flockUnlock(sqlite3_file *id, int eFileLock) { #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS return SQLITE_OK; #endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_UNLOCK, "IOERR_UNLOCK fd[%d], eFileLock[%d]", pFile->h, eFileLock); +#endif /* LOG_DUMP */ return SQLITE_IOERR_UNLOCK; }else{ pFile->eFileLock = NO_LOCK; @@ -40059,8 +40244,14 @@ static int unixRead( #ifdef EDEVERR case EDEVERR: #endif +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_CORRUPTFS, "unixRead-EDEVERR, fd:[%d], amt[%d], got[%d], offset[%lld]", pFile->h, amt, got, offset); +#endif /* LOG_DUMP */ return SQLITE_IOERR_CORRUPTFS; } +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_READ, "unixRead-got<0, fd: [%d], amt[%d], got[%d], offset[%lld]", pFile->h, amt, got, offset); +#endif /* LOG_DUMP */ return SQLITE_IOERR_READ; }else{ storeLastErrno(pFile, 0); /* not a system error */ @@ -40202,9 +40393,19 @@ static int unixWrite( if( amt>wrote ){ if( wrote<0 && pFile->lastErrno!=ENOSPC ){ /* lastErrno set by seekAndWrite */ +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_WRITE, + "unixWrite, lastErrno set by seekAndWrite, fd[%d], offset[%lld], wrote[%d], amt[%d], lastErrno[%d]", + pFile->h, offset, wrote, amt, pFile->lastErrno); +#endif /* LOG_DUMP */ return SQLITE_IOERR_WRITE; }else{ storeLastErrno(pFile, 0); /* not a system error */ +#ifdef LOG_DUMP + sqlite3_log(SQLITE_FULL, + "unixWrite, not a system error, fd[%d], offset[%lld], wrote[%d], amt[%d], lastErrno[%d]", + pFile->h, offset, wrote, amt, pFile->lastErrno); +#endif /* LOG_DUMP */ return SQLITE_FULL; } } @@ -40558,7 +40759,14 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ do{ err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size); }while( err==EINTR ); - if( err && err!=EINVAL ) return SQLITE_IOERR_WRITE; + if( err && err!=EINVAL ) { +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_WRITE, + "fcntlSizeHint-fallocate, fd[%d], bufSize[%lld], nSize[%lld] err[%d]", + pFile->h, buf.st_size, nSize, err); +#endif /* LOG_DUMP */ + return SQLITE_IOERR_WRITE; + } #else /* If the OS does not have posix_fallocate(), fake it. Write a ** single byte to the last byte in each block that falls entirely @@ -40577,7 +40785,14 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ for(/*no-op*/; iWrite=nSize ) iWrite = nSize - 1; nWrite = seekAndWrite(pFile, iWrite, "", 1); - if( nWrite!=1 ) return SQLITE_IOERR_WRITE; + if( nWrite!=1 ) { +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_WRITE, + "fcntlSizeHint-seekAndWrite, fd[%d], nWrite[%d], nSize[%d], nBlk[%d], iWrite[%lld]", + pFile->h, nWrite, nSize, nBlk, iWrite); +#endif /* LOG_DUMP */ + return SQLITE_IOERR_WRITE; + } } #endif } @@ -40632,14 +40847,29 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ #if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: { int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE); +#ifdef LOG_DUMP + if( rc ){ + sqlite3_log(SQLITE_IOERR_BEGIN_ATOMIC, "unixFileControl-begin, fd[%d], op[%d]", pFile->h, op); + } +#endif /* LOG_DUMP */ return rc ? SQLITE_IOERR_BEGIN_ATOMIC : SQLITE_OK; } case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: { int rc = osIoctl(pFile->h, F2FS_IOC_COMMIT_ATOMIC_WRITE); +#ifdef LOG_DUMP + if( rc ){ + sqlite3_log(SQLITE_IOERR_COMMIT_ATOMIC, "unixFileControl-commit, fd[%d], op[%d]", pFile->h, op); + } +#endif /* LOG_DUMP */ return rc ? SQLITE_IOERR_COMMIT_ATOMIC : SQLITE_OK; } case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: { int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE); +#ifdef LOG_DUMP + if( rc ){ + sqlite3_log(SQLITE_IOERR_ROLLBACK_ATOMIC, "unixFileControl-rollback, fd[%d], op[%d]", pFile->h, op); + } +#endif /* LOG_DUMP */ return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK; } #endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ @@ -41585,9 +41815,19 @@ static int unixShmLock( int *aLock; p = pDbFd->pShm; - if( p==0 ) return SQLITE_IOERR_SHMLOCK; + if( p==0 ) { +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_SHMLOCK, "unixShmLock-pShm, fd[%d], ofst[%d], n[%d], flags[%d]", pDbFd->h, ofst, n, flags); +#endif + return SQLITE_IOERR_SHMLOCK; + } pShmNode = p->pShmNode; - if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK; + if( NEVER(pShmNode==0) ) { +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_SHMLOCK, "unixShmLock-pShmNode, fd[%d], ofst[%d], n[%d], flags[%d]", pDbFd->h, ofst, n, flags); +#endif + return SQLITE_IOERR_SHMLOCK; + } aLock = pShmNode->aLock; assert( pShmNode==pDbFd->pInode->pShmNode ); @@ -42959,6 +43199,9 @@ static int unixOpen( if( fstatfs(fd, &fsInfo) == -1 ){ storeLastErrno(p, errno); robust_close(p, fd, __LINE__); +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_ACCESS, "unixOpen, fd[%d], flags[%d], errno[%d]", fd, errno, flags); +#endif /* LOG_DUMP */ return SQLITE_IOERR_ACCESS; } if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) { @@ -43099,6 +43342,184 @@ static int unixAccess( return SQLITE_OK; } +#ifdef HARMONY_OS +/* +** If the last component of the pathname in z[0]..z[j-1] is something +** other than ".." then back it out and return true. If the last +** component is empty or if it is ".." then return false. +*/ +static int unixBackupDir(const char *z, int *pJ){ + int j = *pJ; + int i; + if( j<=0 ) return 0; + for(i=j-1; i>0 && z[i-1]!='/'; i--){} + if( i==0 ) return 0; + if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0; + *pJ = i-1; + return 1; +} + +/* +** Convert a relative pathname into a full pathname. Also +** simplify the pathname as follows: +** +** Remove all instances of /./ +** Remove all isntances of /X/../ for any X +*/ +static int mkFullPathname( + const char *zPath, /* Input path */ + char *zOut, /* Output buffer */ + int nOut /* Allocated size of buffer zOut */ +){ + int nPath = sqlite3Strlen30(zPath); + int iOff = 0; + int i, j; + if( zPath[0]!='/' ){ + if( osGetcwd(zOut, nOut-2)==0 ){ + return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); + } + iOff = sqlite3Strlen30(zOut); + zOut[iOff++] = '/'; + } + if( (iOff+nPath+1)>nOut ){ + /* SQLite assumes that xFullPathname() nul-terminates the output buffer + ** even if it returns an error. */ + zOut[iOff] = '\0'; + return SQLITE_CANTOPEN_BKPT; + } + sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath); + + /* Remove duplicate '/' characters. Except, two // at the beginning + ** of a pathname is allowed since this is important on windows. */ + for(i=j=1; zOut[i]; i++){ + zOut[j++] = zOut[i]; + while( zOut[i]=='/' && zOut[i+1]=='/' ) i++; + } + zOut[j] = 0; + + assert( zOut[0]=='/' ); + for(i=j=0; zOut[i]; i++){ + if( zOut[i]=='/' ){ + /* Skip over internal "/." directory components */ + if( zOut[i+1]=='.' && zOut[i+2]=='/' ){ + i += 1; + continue; + } + + /* If this is a "/.." directory component then back out the + ** previous term of the directory if it is something other than "..". + */ + if( zOut[i+1]=='.' + && zOut[i+2]=='.' + && zOut[i+3]=='/' + && unixBackupDir(zOut, &j) + ){ + i += 2; + continue; + } + } + if( ALWAYS(j>=0) ) zOut[j] = zOut[i]; + j++; + } + if( NEVER(j==0) ) zOut[j++] = '/'; + zOut[j] = 0; + return SQLITE_OK; +} + +/* +** Turn a relative pathname into a full pathname. The relative path +** is stored as a nul-terminated string in the buffer pointed to by +** zPath. +** +** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes +** (in this case, MAX_PATHNAME bytes). The full-path is written to +** this buffer before returning. +*/ +static int unixFullPathname( + sqlite3_vfs *pVfs, /* Pointer to vfs object */ + const char *zPath, /* Possibly relative input path */ + int nOut, /* Size of output buffer in bytes */ + char *zOut /* Output buffer */ +){ +#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT) + return mkFullPathname(zPath, zOut, nOut); +#else + int rc = SQLITE_OK; + int nByte; + int nLink = 0; /* Number of symbolic links followed so far */ + const char *zIn = zPath; /* Input path for each iteration of loop */ + char *zDel = 0; + + assert( pVfs->mxPathname==MAX_PATHNAME ); + UNUSED_PARAMETER(pVfs); + + /* It's odd to simulate an io-error here, but really this is just + ** using the io-error infrastructure to test that SQLite handles this + ** function failing. This function could fail if, for example, the + ** current working directory has been unlinked. + */ + SimulateIOError( return SQLITE_ERROR ); + + do { + + /* Call stat() on path zIn. Set bLink to true if the path is a symbolic + ** link, or false otherwise. */ + int bLink = 0; + struct stat buf; + if( osLstat(zIn, &buf)!=0 ){ + if( errno!=ENOENT ){ + rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn); + } + }else{ + bLink = S_ISLNK(buf.st_mode); + } + + if( bLink ){ + nLink++; + if( zDel==0 ){ + zDel = sqlite3_malloc(nOut); + if( zDel==0 ) rc = SQLITE_NOMEM_BKPT; + }else if( nLink>=SQLITE_MAX_SYMLINKS ){ + rc = SQLITE_CANTOPEN_BKPT; + } + + if( rc==SQLITE_OK ){ + nByte = osReadlink(zIn, zDel, nOut-1); + if( nByte<0 ){ + rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn); + }else{ + if( zDel[0]!='/' ){ + int n; + for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--); + if( nByte+n+1>nOut ){ + rc = SQLITE_CANTOPEN_BKPT; + }else{ + memmove(&zDel[n], zDel, nByte+1); + memcpy(zDel, zIn, n); + nByte += n; + } + } + zDel[nByte] = '\0'; + } + } + + zIn = zDel; + } + + assert( rc!=SQLITE_OK || zIn!=zOut || zIn[0]=='/' ); + if( rc==SQLITE_OK && zIn!=zOut ){ + rc = mkFullPathname(zIn, zOut, nOut); + } + if( bLink==0 ) break; + zIn = zOut; + }while( rc==SQLITE_OK ); + + sqlite3_free(zDel); + if( rc==SQLITE_OK && nLink ) rc = SQLITE_OK_SYMLINK; + return rc; +#endif /* HAVE_READLINK && HAVE_LSTAT */ +} +#else /* ** A pathname under construction */ @@ -43156,7 +43577,7 @@ static void appendOnePathElement( }else if( S_ISLNK(buf.st_mode) ){ ssize_t got; char zLnk[SQLITE_MAX_PATHLEN+2]; - if( pPath->nSymlink++ > SQLITE_MAX_SYMLINK ){ + if( pPath->nSymlink++ > SQLITE_MAX_SYMLINKS ){ pPath->rc = SQLITE_CANTOPEN_BKPT; return; } @@ -43230,6 +43651,7 @@ static int unixFullPathname( if( path.nSymlink ) return SQLITE_OK_SYMLINK; return SQLITE_OK; } +#endif #ifndef SQLITE_OMIT_LOAD_EXTENSION /* @@ -43636,6 +44058,9 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){ if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){ OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n", lPath, errno, osGetpid(0))); +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_LOCK, "proxyGetLockPath len[%d], dbLen[%d], i[%d]", len, dbLen, i); +#endif /* LOG_DUMP */ return SQLITE_IOERR_LOCK; } len = strlcat(lPath, "sqliteplocks", maxLen); @@ -43754,6 +44179,9 @@ static int proxyCreateUnixFile( case EACCES: return SQLITE_PERM; case EIO: +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_LOCK, "proxyCreateUnixFile-EIO, fd[%d]", fd); +#endif /* LOG_DUMP */ return SQLITE_IOERR_LOCK; /* even though it is the conch */ default: return SQLITE_CANTOPEN_BKPT; @@ -43922,6 +44350,9 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ struct stat buf; if( osFstat(conchFile->h, &buf) ){ storeLastErrno(pFile, errno); +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_LOCK, "proxyConchLock pFile fd[%d], conchFile fd[%d], lastErrno[%d]", pFile->h, conchFile->h, errno); +#endif /* LOG_DUMP */ return SQLITE_IOERR_LOCK; } @@ -43942,6 +44373,9 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0); if( len<0 ){ storeLastErrno(pFile, errno); +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_LOCK, "proxyConchLock tries 2, pFile fd[%d], conchFile fd[%d], lastErrno[%d]", pFile->h, conchFile->h, errno); +#endif /* LOG_DUMP */ return SQLITE_IOERR_LOCK; } if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){ @@ -44016,6 +44450,9 @@ static int proxyTakeConch(unixFile *pFile){ if( readLen<0 ){ /* I/O error: lastErrno set by seekAndRead */ storeLastErrno(pFile, conchFile->lastErrno); +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_READ, "proxyTakeConch pFile fd[%d], conchFile fd[%d], lastErrno[%d]", pFile->h, conchFile->h, conchFile->lastErrno); +#endif /* LOG_DUMP */ rc = SQLITE_IOERR_READ; goto end_takeconch; }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) || @@ -51878,13 +52315,6 @@ end_deserialize: return rc; } -/* -** Return true if the VFS is the memvfs. -*/ -SQLITE_PRIVATE int sqlite3IsMemdb(const sqlite3_vfs *pVfs){ - return pVfs==&memdb_vfs; -} - /* ** This routine is called when the extension is loaded. ** Register the new VFS. @@ -55601,6 +56031,20 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ */ #define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1) +#ifdef SQLITE_HAS_CODEC +/* +** A macro used for invoking the codec if there is one +*/ +# define CODEC1(P,D,N,X,E) \ + if( P->xCodec && P->xCodec(P->pCodec,D,N,X)==0 ){ E; } +# define CODEC2(P,D,N,X,E,O) \ + if( P->xCodec==0 ){ O=(char*)D; }else \ + if( (O=(char*)(P->xCodec(P->pCodec,D,N,X)))==0 ){ E; } +#else +# define CODEC1(P,D,N,X,E) /* NO-OP */ +# define CODEC2(P,D,N,X,E,O) O=(char*)D +#endif /* SQLITE_HAS_CODEC */ + /* ** The maximum allowed sector size. 64KiB. If the xSectorsize() method ** returns a value larger than this, then MAX_SECTOR_SIZE is used instead. @@ -55889,6 +56333,12 @@ struct Pager { #endif void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */ int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */ +#ifdef SQLITE_HAS_CODEC + void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ + void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */ + void (*xCodecFree)(void*); /* Destructor for the codec */ + void *pCodec; /* First argument to xCodec... methods */ +#endif /* SQLITE_HAS_CODEC */ char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ PCache *pPCache; /* Pointer to page cache object */ #ifndef SQLITE_OMIT_WAL @@ -56010,6 +56460,9 @@ static const unsigned char aJournalMagic[] = { SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){ if( pPager->fd->pMethods==0 ) return 0; if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; +#ifdef SQLITE_HAS_CODEC + if( pPager->xCodec!=0 ) return 0; +#endif /* SQLITE_HAS_CODEC */ #ifndef SQLITE_OMIT_WAL if( pPager->pWal ){ u32 iRead = 0; @@ -56243,7 +56696,11 @@ 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) +#ifdef SQLITE_HAS_CODEC + && pPager->xCodec==0 +#endif /* SQLITE_HAS_CODEC */ + ){ pPager->xGet = getPageMMap; #endif /* SQLITE_MAX_MMAP_SIZE>0 */ }else{ @@ -57394,6 +57851,32 @@ static u32 pager_cksum(Pager *pPager, const u8 *aData){ return cksum; } +#ifdef SQLITE_HAS_CODEC +/* +** Report the current page size and number of reserved bytes back +** to the codec. +*/ +static void pagerReportSize(Pager *pPager){ + if( pPager->xCodecSizeChng ){ + pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize, + (int)pPager->nReserve); + } +} +/* +** Make sure the number of reserved bits is the same in the destination +** pager as it is in the source. This comes up when a VACUUM changes the +** number of reserved bits to the "optimal" amount. +*/ +SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager *pDest, Pager *pSrc){ + if( pDest->nReserve!=pSrc->nReserve ){ + pDest->nReserve = pSrc->nReserve; + pagerReportSize(pDest); + } +} +#else +# define pagerReportSize(X) /* No-op if we do not support a codec */ +#endif + /* ** Read a single page from either the journal file (if isMainJrnl==1) or ** from the sub-journal (if isMainJrnl==0) and playback that page. @@ -57445,6 +57928,11 @@ static int pager_playback_one_page( char *aData; /* Temporary storage for the page */ sqlite3_file *jfd; /* The file descriptor for the journal file */ int isSynced; /* True if journal page is synced */ +#ifdef SQLITE_HAS_CODEC + /* The jrnlEnc flag is true if Journal pages should be passed through + ** the codec. It is false for pure in-memory journals. */ + const int jrnlEnc = (isMainJrnl || pPager->subjInMemory==0); +#endif /* SQLITE_HAS_CODEC */ assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */ assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */ @@ -57574,12 +58062,26 @@ static int pager_playback_one_page( ** is if the data was just read from an in-memory sub-journal. In that ** case it must be encrypted here before it is copied into the database ** file. */ +#ifdef SQLITE_HAS_CODEC + if( !jrnlEnc ){ + CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData); + rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); + CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT); + }else +#endif /* SQLITE_HAS_CODEC */ rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); if( pgno>pPager->dbFileSize ){ pPager->dbFileSize = pgno; } if( pPager->pBackup ){ +#ifdef SQLITE_HAS_CODEC + if( jrnlEnc ){ + CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT); + sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); + CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT,aData); + }else +#endif /* SQLITE_HAS_CODEC */ sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); } }else if( !isMainJrnl && pPg==0 ){ @@ -57630,6 +58132,10 @@ static int pager_playback_one_page( if( pgno==1 ){ memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers)); } +#if SQLITE_HAS_CODEC + /* Decode the page just read from disk */ + if( jrnlEnc ){ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT); } +#endif /* SQLITE_HAS_CODEC */ sqlite3PcacheRelease(pPg); } return rc; @@ -58206,6 +58712,8 @@ static int readDbPage(PgHdr *pPg){ memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers)); } } + CODEC1(pPager, pPg->pData, pPg->pgno, 3, rc = SQLITE_NOMEM_BKPT); + PAGER_INCR(sqlite3_pager_readdb_count); PAGER_INCR(pPager->nRead); IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno)); @@ -59353,6 +59861,10 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ sqlite3OsClose(pPager->fd); sqlite3PageFree(pTmp); sqlite3PcacheClose(pPager->pPCache); +#ifdef SQLITE_HAS_CODEC + if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec); +#endif /* SQLITE_HAS_CODEC */ + assert( !pPager->aSavepoint && !pPager->pInJournal ); assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) ); @@ -59603,7 +60115,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ assert( (pList->flags&PGHDR_NEED_SYNC)==0 ); if( pList->pgno==1 ) pager_write_changecounter(pList); - pData = pList->pData; + CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM_BKPT, pData); /* Write out the page data. */ rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset); @@ -59692,6 +60204,11 @@ static int subjournalPage(PgHdr *pPg){ void *pData = pPg->pData; i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize); char *pData2; +#if SQLITE_HAS_CODEC + if( !pPager->subjInMemory ){ + CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2); + }else +#endif /* SQLITE_HAS_CODEC */ pData2 = pData; PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno)); rc = write32bits(pPager->sjfd, offset, pPg->pgno); @@ -60795,6 +61312,9 @@ static int getPageMMap( ); assert( USEFETCH(pPager) ); +#ifdef SQLITE_HAS_CODEC + assert( pPager->xCodec==0 ); +#endif /* SQLITE_HAS_CODEC */ /* Optimization note: Adding the "pgno<=1" term before "pgno==0" here ** allows the compiler optimizer to reuse the results of the "pgno>1" @@ -61125,7 +61645,7 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){ assert( pPg->pgno!=PAGER_SJ_PGNO(pPager) ); assert( pPager->journalHdr<=pPager->journalOff ); - pData2 = pPg->pData; + CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2); cksum = pager_cksum(pPager, (u8*)pData2); /* Even if an IO or diskfull error occurs while journalling the @@ -61490,7 +62010,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){ if( DIRECT_MODE ){ const void *zBuf; assert( pPager->dbFileSize>0 ); - zBuf = pPgHdr->pData; + CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM_BKPT, zBuf); if( rc==SQLITE_OK ){ rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0); pPager->aStat[PAGER_STAT_WRITE]++; @@ -62242,6 +62762,48 @@ SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){ return pPager->zJournal; } +#ifdef SQLITE_HAS_CODEC +/* +** Set or retrieve the codec for this pager +*/ +SQLITE_PRIVATE void sqlite3PagerSetCodec( + Pager *pPager, + void *(*xCodec)(void*,void*,Pgno,int), + void (*xCodecSizeChng)(void*,int,int), + void (*xCodecFree)(void*), + void *pCodec +){ + if( pPager->xCodecFree ){ + pPager->xCodecFree(pPager->pCodec); + }else{ + pager_reset(pPager); + } + pPager->xCodec = pPager->memDb ? 0 : xCodec; + pPager->xCodecSizeChng = xCodecSizeChng; + pPager->xCodecFree = xCodecFree; + pPager->pCodec = pCodec; + setGetterMethod(pPager); + pagerReportSize(pPager); +} +SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){ + return pPager->pCodec; +} + +/* +** This function is called by the wal module when writing page content +** into the log file. +** +** This function returns a pointer to a buffer containing the encrypted +** page content. If a malloc fails, this function may return NULL. +*/ +SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){ + void *aData = 0; + CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData); + return aData; +} + +#endif /* SQLITE_HAS_CODEC */ + #ifndef SQLITE_OMIT_AUTOVACUUM /* ** Move the page pPg to location pgno in the file. @@ -64937,6 +65499,11 @@ static void walRestartHdr(Wal *pWal, u32 salt1){ assert( pInfo->aReadMark[0]==0 ); } +#ifdef SQLITE_HDR_CHECK +static int checkHeaderValid(Pager *pager, u8 *zBuf, const char *logStr); +static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf); +#endif /* SQLITE_HDR_CHECK */ + /* ** Copy as much content as we can from the WAL back into the database file ** in response to an sqlite3_wal_checkpoint() request or the equivalent. @@ -65077,6 +65644,10 @@ static int walCheckpoint( if( rc!=SQLITE_OK ) break; iOffset = (iDbpage-1)*(i64)szPage; testcase( IS_BIG_INT(iOffset) ); +#ifdef SQLITE_HDR_CHECK + rc = checkDbHeaderValid(db, iDbpage, zBuf); + if( rc!=SQLITE_OK ) break; +#endif /* SQLITE_HDR_CHECK */ rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); if( rc!=SQLITE_OK ) break; } @@ -66471,7 +67042,18 @@ static int walWriteOneFrame( int rc; /* Result code from subfunctions */ void *pData; /* Data actually written */ u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */ +#ifdef SQLITE_HDR_CHECK + if( pPage->pgno==1 ){ + rc = checkHeaderValid(pPage->pPager, pPage->pData, "walWrite"); + if( rc!=SQLITE_OK ) return rc; + } +#endif /* SQLITE_HDR_CHECK */ + +#ifdef SQLITE_HAS_CODEC + if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT; +#else pData = pPage->pData; +#endif /* SQLITE_HAS_CODEC */ walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame); rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset); if( rc ) return rc; @@ -66654,7 +67236,11 @@ SQLITE_PRIVATE int sqlite3WalFrames( if( pWal->iReCksum==0 || iWriteiReCksum ){ pWal->iReCksum = iWrite; } +#ifdef SQLITE_HAS_CODEC + if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM; +#else pData = p->pData; +#endif /* SQLITE_HAS_CODEC */ rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff); if( rc ) return rc; p->flags &= ~PGHDR_WAL_APPEND; @@ -66765,6 +67351,10 @@ SQLITE_PRIVATE int sqlite3WalFrames( return rc; } +#ifdef LOG_DUMP +static sqlite3_int64 g_lastCkptTime = 0; +#endif /* LOG_DUMP */ + /* ** This routine is called to implement sqlite3_wal_checkpoint() and ** related interfaces. @@ -66888,6 +67478,12 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1); pWal->ckptLock = 0; } +#ifdef LOG_DUMP + if( rc ){ + sqlite3_log(SQLITE_NOTICE, "ckpt rc[%d]", rc); + } + sqlite3OsCurrentTimeInt64(db->pVfs, &g_lastCkptTime); +#endif /* LOG_DUMP */ WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok")); #ifdef SQLITE_ENABLE_SETLK_TIMEOUT if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY; @@ -68264,6 +68860,32 @@ SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){ } #endif +#ifdef SQLITE_HDR_CHECK +static int checkHeaderValid(Pager *pager, u8 *zBuf, const char *logStr){ +#ifdef SQLITE_HAS_CODEC + if( pager==NULL || pager->pCodec ){ + return SQLITE_OK; + } +#endif /* SQLITE_HAS_CODEC */ + if( zBuf && strncmp((const char *)zBuf, zMagicHeader, 16)!=0 ){ + sqlite3_log(SQLITE_NOTADB, "[%s]wrong header format, memory might be overwritten!", logStr); + return SQLITE_NOTADB; + } + return SQLITE_OK; +} + +static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf){ + if( iDbpage==1 && db->aDb ){ + Btree *p = db->aDb[0].pBt; + if( p && p->pBt ){ + Pager *pager = sqlite3BtreePager(p); + return checkHeaderValid(pager, zBuf, "ckpt"); + } + } + return SQLITE_OK; +} +#endif /* SQLITE_HDR_CHECK */ + /* ** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single ** (MemPage*) as an argument. The (MemPage*) must not be NULL. @@ -70094,6 +70716,13 @@ static int decodeFlags(MemPage *pPage, int flagByte){ pPage->intKeyLeaf = 0; pPage->xCellSize = cellSizePtr; pPage->xParseCell = btreeParseCellPtrIndex; +#ifdef LOG_DUMP + sqlite3_log(SQLITE_CORRUPT, + "database corruption at page[%u], flagByte[%x], isInit[%u], intKey[%u], intKeyLeaf[%u], leaf[%u], " + "childPtrSize[%u], cellOffset[%u], nCell[%u], hdrOffset[%u], minLocal[%u], maxLocal[%u], last ckpt time[%lld]", + pPage->pgno, flagByte, pPage->isInit, pPage->intKey, pPage->intKeyLeaf, pPage->leaf, + pPage->childPtrSize, pPage->cellOffset, pPage->nCell, pPage->hdrOffset, pPage->minLocal, pPage->maxLocal, g_lastCkptTime); +#endif /* LOG_DUMP */ return SQLITE_CORRUPT_PAGE(pPage); } pPage->max1bytePayload = pBt->max1bytePayload; @@ -79481,6 +80110,13 @@ static int backupOnePage( int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); const int nCopy = MIN(nSrcPgsz, nDestPgsz); const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; +#ifdef SQLITE_HAS_CODEC + /* Use BtreeGetReserveNoMutex() for the source b-tree, as although it is + ** guaranteed that the shared-mutex is held by this thread, handle + ** p->pSrc may not actually be the owner. */ + int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc); + int nDestReserve = sqlite3BtreeGetRequestedReserve(p->pDest); +#endif /* SQLITE_HAS_CODEC */ int rc = SQLITE_OK; i64 iOff; @@ -79497,6 +80133,26 @@ static int backupOnePage( rc = SQLITE_READONLY; } +#ifdef SQLITE_HAS_CODEC + /* Backup is not possible if the page size of the destination is changing + ** and a codec is in use. + */ + if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){ + rc = SQLITE_READONLY; + } + + /* Backup is not possible if the number of bytes of reserve space differ + ** between source and destination. If there is a difference, try to + ** fix the destination to agree with the source. If that is not possible, + ** then the backup cannot proceed. + */ + if( nSrcReserve!=nDestReserve ){ + u32 newPgsz = nSrcPgsz; + rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve); + if( rc==SQLITE_OK && newPgsz!=(u32)nSrcPgsz ) rc = SQLITE_READONLY; + } +#endif /* SQLITE_HAS_CODEC */ + /* This loop runs once for each destination page spanned by the source ** page. For each iteration, variable iOff is set to the byte offset ** of the destination page. @@ -79992,6 +80648,10 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ b.pDest = pTo; b.iNext = 1; +#ifdef SQLITE_HAS_CODEC + sqlite3PagerAlignReserve(sqlite3BtreePager(pTo), sqlite3BtreePager(pFrom)); +#endif /* SQLITE_HAS_CODEC */ + /* 0x7FFFFFFF is the hard limit for the number of pages in a database ** file. By passing this as the number of pages to copy to ** sqlite3_backup_step(), we can guarantee that the copy finishes @@ -88114,6 +88774,15 @@ end_of_step: return (rc&db->errMask); } +#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK +SQLITE_API int sqlite3_set_droptable_handle(sqlite3 *db, void (*xFunc)(sqlite3*, const char*, const char*)){ + sqlite3_mutex_enter(db->mutex); + db->xDropTableHandle = xFunc; + sqlite3_mutex_leave(db->mutex); + return 0; +} +#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ + /* ** This is the top-level implementation of sqlite3_step(). Call ** sqlite3Step() to do most of the work. If a schema error occurs, @@ -88133,6 +88802,13 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ while( (rc = sqlite3Step(v))==SQLITE_SCHEMA && cnt++ < SQLITE_MAX_SCHEMA_RETRY ){ int savedPc = v->pc; +#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION + Sqlite3SharedBlockMethods *pSharedBlock = v->pSharedBlock; + int totalRows = v->totalRows; + int blockFull = v->blockFull; + int startPos = v->startPos; + int addedRows = v->addedRows; +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ rc = sqlite3Reprepare(v); if( rc!=SQLITE_OK ){ /* This case occurs after failing to recompile an sql statement. @@ -88154,6 +88830,15 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ } break; } + +#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION + v->pSharedBlock = pSharedBlock; + v->totalRows = totalRows; + v->blockFull = blockFull; + v->startPos = startPos; + v->addedRows = addedRows; +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ + sqlite3_reset(pStmt); if( savedPc>=0 ){ /* Setting minWriteFileFormat to 254 is a signal to the OP_Init and @@ -88164,6 +88849,20 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ } assert( v->expired==0 ); } +#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK + if( rc==SQLITE_DONE && db->xDropTableHandle!=NULL && db->isDropTable==1 ){ + db->isDropTable = 0; + db->xDropTableHandle(db, db->mDropTableName, db->mDropSchemaName); + } + if( db->mDropTableName!=NULL ){ + sqlite3_free(db->mDropTableName); + db->mDropTableName = NULL; + } + if( db->mDropSchemaName!=NULL ){ + sqlite3_free(db->mDropSchemaName); + db->mDropSchemaName = NULL; + } +#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ sqlite3_mutex_leave(db->mutex); return rc; } @@ -90192,7 +90891,6 @@ static u16 numericType(Mem *pMem){ testcase( pMem->flags & MEM_Str ); testcase( pMem->flags & MEM_Blob ); return computeNumericType(pMem); - return 0; } #ifdef SQLITE_DEBUG @@ -90351,6 +91049,61 @@ static int checkSavepointCount(sqlite3 *db){ } #endif +#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION +static int copySharedBlockRow( + Vdbe *p, /* The VDBE */ + Op *pOp, /* Current operation */ + Mem *pMem, + void *pCtx +){ + int i = 0; + + int rc = p->pSharedBlock->xAddRow(pCtx, p->addedRows); + if( rc!=SQLITE_OK ){ + return rc; + } + + for(i=0; ip2; i++){ + switch (sqlite3_value_type(&pMem[i])) { + case SQLITE_INTEGER:{ + rc = p->pSharedBlock->xPutLong(pCtx, p->addedRows, i, (sqlite3_int64)pMem[i].u.i); + break; + } + case SQLITE_FLOAT: { + rc = p->pSharedBlock->xPutDouble(pCtx, p->addedRows, i, pMem[i].u.r); + break; + } + case SQLITE_TEXT: { + Deephemeralize(&pMem[i]); + sqlite3VdbeMemNulTerminate(&pMem[i]); + sqlite3VdbeChangeEncoding(&pMem[i],SQLITE_UTF8); + rc = p->pSharedBlock->xPutString(pCtx, p->addedRows, i, pMem[i].z, pMem[i].n+1); + break; + } + case SQLITE_BLOB: { + rc = p->pSharedBlock->xPutBlob(pCtx, p->addedRows, i, pMem[i].z, pMem[i].n); + break; + } + case SQLITE_NULL: { + rc = p->pSharedBlock->xPutNull(pCtx, p->addedRows, i); + break; + } + default: + rc = p->pSharedBlock->xPutOther(pCtx, p->addedRows, i); + break; + } + if( rc!=SQLITE_OK ){ + return rc; + } + } + + return rc; +no_mem: + rc = SQLITE_NOMEM; + return rc; +} +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ + /* ** Return the register of pOp->p2 after first preparing it to be ** overwritten with an integer value. @@ -90852,6 +91605,12 @@ case OP_Halt: { VdbeFrame *pFrame; int pcx; +#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION + if( p->pSharedBlock!=NULL ){ + p->pSharedBlock->xFinish(p->pSharedBlock->pContext, p->addedRows, p->totalRows); + } +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ + #ifdef SQLITE_DEBUG if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); } #endif @@ -91295,6 +92054,43 @@ case OP_ResultRow: { assert( pOp->p1>0 || CORRUPT_DB ); assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); +#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION + if( p->pSharedBlock!=NULL ){ + void *pCtx = p->pSharedBlock->pContext; + p->totalRows++; + if( p->totalRows<=p->startPos || p->blockFull ){ + break; + } + Mem *pMem = &aMem[pOp->p1]; + rc = copySharedBlockRow(p, pOp, pMem, pCtx); + if( rc==SQLITE_FULL && p->addedRows && (p->startPos + p->addedRows) <= p->pSharedBlock->requiredPos ){ + p->startPos += p->addedRows; + p->addedRows = 0; + p->pSharedBlock->xReset(pCtx,p->startPos); + p->blockFull = 0; + rc = copySharedBlockRow(p, pOp, pMem, pCtx); + } + + if( rc==SQLITE_OK ){ + p->addedRows++; + }else if( rc==SQLITE_FULL ){ + p->blockFull = 1; + }else{ + //SQLITE_NOMEM + goto no_mem; + } + + if( p->blockFull && p->pSharedBlock->countAllRows==0 ){ + p->pSharedBlock->xFinish(pCtx, p->addedRows, p->totalRows); + rc = SQLITE_DONE; + goto vdbe_return; + }else if( p->blockFull && p->pSharedBlock->countAllRows==1 ){ + rc = SQLITE_OK; + } + break; + } +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ + p->cacheCtr = (p->cacheCtr + 2)|1; p->pResultSet = &aMem[pOp->p1]; #ifdef SQLITE_DEBUG @@ -92091,6 +92887,17 @@ case OP_Compare: { ** This opcode must immediately follow an OP_Compare opcode. */ case OP_Jump: { /* jump */ +#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION + if( pOp->p5&0x80 ){ + if( p->pSharedBlock!=NULL ){ + if( p->totalRows < p->startPos || p->blockFull ){ + p->totalRows++; + pOp = &aOp[pOp->p2 - 1]; + } + } + break; + } +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ assert( pOp>aOp && pOp[-1].opcode==OP_Compare ); if( iCompare<0 ){ VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1]; @@ -97106,6 +97913,20 @@ case OP_IfNotZero: { /* jump, in1 */ ** and jump to P2 if the new value is exactly zero. */ case OP_DecrJumpZero: { /* jump, in1 */ +#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION + if( pOp->p5&0x80 ){ + if( p->pSharedBlock!=NULL ){ + if( p->totalRows < p->startPos || p->blockFull ){ + pIn1 = &aMem[pOp->p1]; + assert( pIn1->flags&MEM_Int ); + if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--; + VdbeBranchTaken(pIn1->u.i==-1, 2); + if( pIn1->u.i==-1 ) goto jump_to_p2; + } + } + break; + } +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--; @@ -116053,6 +116874,40 @@ static void attachFunc( if( rc==SQLITE_OK && pNew->zDbSName==0 ){ rc = SQLITE_NOMEM_BKPT; } +#ifdef SQLITE_HAS_CODEC + if( rc==SQLITE_OK ){ + extern int sqlite3CodecAttach(sqlite3*, int, const void*, int); + extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); + int nKey; + char *zKey; + int t = sqlite3_value_type(argv[2]); + switch( t ){ + case SQLITE_INTEGER: + case SQLITE_FLOAT: + zErrDyn = sqlite3DbStrDup(db, "Invalid key value"); + rc = SQLITE_ERROR; + break; + + case SQLITE_TEXT: + case SQLITE_BLOB: + nKey = sqlite3_value_bytes(argv[2]); + zKey = (char *)sqlite3_value_blob(argv[2]); + rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); + break; + + case SQLITE_NULL: + /* No key specified. Use the key from URI filename, or if none, + ** use the key from the main database. */ + if( sqlite3CodecQueryParameters(db, zName, zPath)==0 ){ + sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); + if( nKey || sqlite3BtreeGetRequestedReserve(db->aDb[0].pBt)>0 ){ + rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); + } + } + break; + } + } +#endif /* SQLITE_HAS_CODEC */ sqlite3_free_filename( zPath ); /* If the file was opened successfully, read the schema for the new database. @@ -117624,8 +118479,24 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char testcase( zTabName[0]==0 ); /* Zero-length table names are allowed */ pDb = &db->aDb[iDb]; p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0); +#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK + u8 tableType = p->eTabType; +#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ sqlite3DeleteTable(db, p); db->mDbFlags |= DBFLAG_SchemaChange; +#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK + if( tableType!=TABTYP_VIEW ){ + db->isDropTable = 1; + db->mDropTableName = sqlite3_malloc(strlen(zTabName) + 1); + if( db->mDropTableName!=NULL ){ + memcpy(db->mDropTableName, zTabName, strlen(zTabName) + 1); + } + db->mDropSchemaName = sqlite3_malloc(strlen(db->aDb[iDb].zDbSName) + 1); + if( db->mDropSchemaName!=NULL ){ + memcpy(db->mDropSchemaName, db->aDb[iDb].zDbSName, strlen(db->aDb[iDb].zDbSName) + 1); + } + } +#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ } /* @@ -125898,10 +126769,16 @@ static void groupConcatValue(sqlite3_context *context){ */ SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){ int rc = sqlite3_overload_function(db, "MATCH", 2); +#ifdef SQLITE_HAS_CODEC + extern void sqlite3CodecExportData(sqlite3_context *, int, sqlite3_value **); +#endif /* SQLITE_HAS_CODEC */ assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); } +#ifdef SQLITE_HAS_CODEC + sqlite3CreateFunc(db, "export_database", 1, SQLITE_TEXT, 0, sqlite3CodecExportData, 0, 0, 0, 0, 0); +#endif /* SQLITE_HAS_CODEC */ } /* @@ -131535,6 +132412,10 @@ struct sqlite3_api_routines { const char *(*db_name)(sqlite3*,int); /* Version 3.40.0 and later */ int (*value_encoding)(sqlite3_value*); +#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK + /* handle after drop table done */ + int (*set_droptable_handle)(sqlite3*,void(*)(sqlite3*,const char*,const char*)); +#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ }; /* @@ -131861,6 +132742,10 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_db_name sqlite3_api->db_name /* Version 3.40.0 and later */ #define sqlite3_value_encoding sqlite3_api->value_encoding +#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK +/* handle after drop table done */ +#define sqlite3_set_droptable_handle sqlite3_api->set_droptable_handle +#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) @@ -131884,7 +132769,7 @@ typedef int (*sqlite3_loadext_entry)( /************** Continuing where we left off in loadext.c ********************/ /* #include "sqliteInt.h" */ -#ifndef SQLITE_OMIT_LOAD_EXTENSION +#if !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS) /* ** Some API routines are omitted when various features are ** excluded from a build of SQLite. Substitute a NULL pointer @@ -131898,7 +132783,9 @@ typedef int (*sqlite3_loadext_entry)( # define sqlite3_column_origin_name 0 # define sqlite3_column_origin_name16 0 #endif +#endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS) */ +#ifndef SQLITE_OMIT_LOAD_EXTENSION #ifdef SQLITE_OMIT_AUTHORIZATION # define sqlite3_set_authorizer 0 #endif @@ -131979,6 +132866,7 @@ typedef int (*sqlite3_loadext_entry)( #if defined(SQLITE_OMIT_TRACE) # define sqlite3_trace_v2 0 #endif +#endif /* !SQLITE_OMIT_LOAD_EXTENSION */ /* ** The following structure contains pointers to all SQLite API routines. @@ -131995,6 +132883,7 @@ typedef int (*sqlite3_loadext_entry)( ** also check to make sure that the pointer to the function is ** not NULL before calling it. */ +#if !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS) static const sqlite3_api_routines sqlite3Apis = { sqlite3_aggregate_context, #ifndef SQLITE_OMIT_DEPRECATED @@ -132264,7 +133153,11 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_bind_blob64, sqlite3_bind_text64, sqlite3_cancel_auto_extension, +#ifndef SQLITE_OMIT_LOAD_EXTENSION sqlite3_load_extension, +#else + 0, +#endif /* !SQLITE_OMIT_LOAD_EXTENSION */ sqlite3_malloc64, sqlite3_msize, sqlite3_realloc64, @@ -132375,7 +133268,10 @@ static const sqlite3_api_routines sqlite3Apis = { #endif sqlite3_db_name, /* Version 3.40.0 and later */ - sqlite3_value_encoding + sqlite3_value_encoding, +#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK + sqlite3_set_droptable_handle +#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ }; /* True if x is the directory separator character @@ -132386,6 +133282,9 @@ static const sqlite3_api_routines sqlite3Apis = { # define DirSep(X) ((X)=='/') #endif +#endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS) */ + +#ifndef SQLITE_OMIT_LOAD_EXTENSION /* ** Attempt to load an SQLite extension library contained in the file ** zFile. The entry point is zProc. zProc may be 0 in which case a @@ -132846,6 +133745,9 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ #define PragTyp_WAL_CHECKPOINT 43 #define PragTyp_LOCK_STATUS 44 #define PragTyp_STATS 45 +#ifdef SQLITE_HAS_CODEC +#define PragTyp_KEY 255 +#endif /* SQLITE_HAS_CODEC */ /* Property flags associated with various pragma. */ #define PragFlg_NeedSchema 0x01 /* Force schema load before running */ @@ -133136,6 +134038,18 @@ static const PragmaName aPragmaName[] = { /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, +#if defined(SQLITE_HAS_CODEC) + {/* zName: */ "hexkey", + /* ePragTyp: */ PragTyp_KEY, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 2 }, + {/* zName: */ "hexrekey", + /* ePragTyp: */ PragTyp_KEY, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 3 }, +#endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_CHECK) {/* zName: */ "ignore_check_constraints", @@ -133188,6 +134102,13 @@ static const PragmaName aPragmaName[] = { /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif +#if defined(SQLITE_HAS_CODEC) + {/* zName: */ "key", + /* ePragTyp: */ PragTyp_KEY, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "legacy_alter_table", /* ePragTyp: */ PragTyp_FLAG, @@ -133295,6 +134216,15 @@ static const PragmaName aPragmaName[] = { /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_RecTriggers }, +#endif +#if defined(SQLITE_HAS_CODEC) + {/* zName: */ "rekey", + /* ePragTyp: */ PragTyp_KEY, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 1 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "reverse_unordered_selects", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, @@ -133383,6 +134313,18 @@ static const PragmaName aPragmaName[] = { /* ePragFlg: */ PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, +#endif +#if defined(SQLITE_HAS_CODEC) + {/* zName: */ "textkey", + /* ePragTyp: */ PragTyp_KEY, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 4 }, + {/* zName: */ "textrekey", + /* ePragTyp: */ PragTyp_KEY, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 5 }, #endif {/* zName: */ "threads", /* ePragTyp: */ PragTyp_THREADS, @@ -133824,6 +134766,10 @@ SQLITE_PRIVATE void sqlite3Pragma( Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */ const PragmaName *pPragma; /* The pragma */ +#ifdef SQLITE_HAS_CODEC + extern int sqlite3CodecPragma(sqlite3*, int, Parse *, const char *, const char *); +#endif /* SQLITE_HAS_CODEC */ + if( v==0 ) return; sqlite3VdbeRunOnlyOnce(v); pParse->nMem = 2; @@ -133893,6 +134839,13 @@ SQLITE_PRIVATE void sqlite3Pragma( goto pragma_out; } +#ifdef SQLITE_HAS_CODEC + if(sqlite3CodecPragma(db, iDb, pParse, zLeft, zRight)) { + /* sqlite3CodecPragma executes internal */ + goto pragma_out; + } +#endif /* SQLITE_HAS_CODEC */ + /* Locate the pragma in the lookup table */ pPragma = pragmaLocate(zLeft); if( pPragma==0 ){ @@ -135935,6 +136888,48 @@ SQLITE_PRIVATE void sqlite3Pragma( } #endif +#ifdef SQLITE_HAS_CODEC + /* Pragma iArg + ** ---------- ------ + ** key 0 + ** rekey 1 + ** hexkey 2 + ** hexrekey 3 + ** textkey 4 + ** textrekey 5 + */ + case PragTyp_KEY: { + if( zRight ){ + char zBuf[40]; + const char *zKey = zRight; + int n; + if( pPragma->iArg==2 || pPragma->iArg==3 ){ + u8 iByte; + int i; + for(i=0, iByte=0; i<(int)(sizeof(zBuf)*2) && sqlite3Isxdigit(zRight[i]); i++){ + iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]); + if( (i&1)!=0 ) zBuf[i/2] = iByte; + } + zKey = zBuf; + n = i/2; + }else{ + n = pPragma->iArg<4 ? sqlite3Strlen30(zRight) : -1; + } + if( (pPragma->iArg & 1)==0 ){ + rc = sqlite3_key_v2(db, zDb, zKey, n); + }else{ + rc = sqlite3_rekey_v2(db, zDb, zKey, n); + } + if( rc==SQLITE_OK && n!=0 ){ + sqlite3VdbeSetNumCols(v, 1); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "ok", SQLITE_STATIC); + returnSingleText(v, "ok"); + } + } + break; + } +#endif /* SQLITE_HAS_CODEC */ + #if defined(SQLITE_ENABLE_CEROD) case PragTyp_ACTIVATE_EXTENSIONS: if( zRight ){ if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){ @@ -138460,9 +139455,25 @@ static void selectInnerLoop( assert( p->pEList!=0 ); hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP; if( pSort && pSort->pOrderBy==0 ) pSort = 0; +#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION + if( hasDistinct && (pDistinct->eTnctType==WHERE_DISTINCT_UNIQUE) ){ + hasDistinct = WHERE_DISTINCT_NOOP; + sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct); + } +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ if( pSort==0 && !hasDistinct ){ assert( iContinue!=0 ); codeOffset(v, p->iOffset, iContinue); +#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION + if( eDest==SRT_Output ){ + if( p->iLimit ){ + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); + sqlite3VdbeChangeP5(v, 128); + } + sqlite3VdbeAddOp2(v, OP_Jump, 0, iContinue); + sqlite3VdbeChangeP5(v, 128); + } +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ } /* Pull the requested columns. @@ -138591,6 +139602,16 @@ static void selectInnerLoop( fixDistinctOpenEph(pParse, eType, iTab, pDistinct->addrTnct); if( pSort==0 ){ codeOffset(v, p->iOffset, iContinue); +#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION + if( eDest==SRT_Output ){ + if( p->iLimit ){ + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); + sqlite3VdbeChangeP5(v, 128); + } + sqlite3VdbeAddOp2(v, OP_Jump, 0, iContinue); + sqlite3VdbeChangeP5(v, 128); + } +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ } } @@ -139037,11 +140058,23 @@ static void generateSortTail( addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); VdbeCoverage(v); assert( p->iLimit==0 && p->iOffset==0 ); +#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION + if( eDest==SRT_Output ){ + sqlite3VdbeAddOp2(v, OP_Jump, 0, addrContinue); + sqlite3VdbeChangeP5(v, 128); + } +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ sqlite3VdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab); bSeq = 0; }else{ addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); +#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION + if( eDest==SRT_Output ){ + sqlite3VdbeAddOp2(v, OP_Jump, 0, addrContinue); + sqlite3VdbeChangeP5(v, 128); + } +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ iSortTab = iTab; bSeq = 1; if( p->iOffset>0 ){ @@ -148844,6 +149877,17 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( } nRes = sqlite3BtreeGetRequestedReserve(pMain); +#ifdef SQLITE_HAS_CODEC + /* A VACUUM cannot change the pagesize of an encrypted database. */ + if( db->nextPagesize ){ + extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); + int nKey; + char *zKey; + sqlite3CodecGetKey(db, iDb, (void**)&zKey, &nKey); + if( nKey ) db->nextPagesize = 0; + } +#endif /* SQLITE_HAS_CODEC */ + sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); sqlite3BtreeSetPagerFlags(pTemp, pgflags|PAGER_CACHESPILL); @@ -173422,6 +174466,29 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ rc = setupLookaside(db, pBuf, sz, cnt); break; } +#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION + case SQLITE_DBCONFIG_SET_SHAREDBLOCK: { + Vdbe *pVdbe = (Vdbe *)va_arg(ap, sqlite3_stmt*); + Sqlite3SharedBlockMethods *pSharedBlock = va_arg(ap, Sqlite3SharedBlockMethods*); + if( pVdbe==NULL ){ + rc = SQLITE_MISUSE; + break; + } + pVdbe->pSharedBlock = pSharedBlock; + if( pSharedBlock!=NULL ){ + pVdbe->startPos = pSharedBlock->startPos; + } + pVdbe->totalRows = 0; + pVdbe->blockFull = 0; + pVdbe->addedRows = 0; + rc = SQLITE_OK; + break; + } + case SQLITE_DBCONFIG_USE_SHAREDBLOCK: { + rc = SQLITE_OK; + break; + } +#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ default: { static const struct { int op; /* The opcode */ @@ -175642,7 +176709,41 @@ static const char *uriParameter(const char *zFilename, const char *zParam){ return 0; } - +#ifdef SQLITE_HAS_CODEC +/* +** Process URI filename query parameters relevant to the SQLite Encryption +** Extension. Return true if any of the relevant query parameters are +** seen and return false if not. +*/ +SQLITE_PRIVATE int sqlite3CodecQueryParameters( + sqlite3 *db, /* Database connection */ + const char *zDb, /* Which schema is being created/attached */ + const char *zUri /* URI filename */ +){ + const char *zKey; + if( zUri==0 ){ + return 0; + }else if( (zKey = uriParameter(zUri, "hexkey"))!=0 && zKey[0] ){ + u8 iByte; + int i; + char zDecoded[40]; + for(i=0, iByte=0; i<(int)(sizeof(zDecoded)*2) && sqlite3Isxdigit(zKey[i]); i++){ + iByte = (iByte<<4) + sqlite3HexToInt(zKey[i]); + if( (i&1)!=0 ) zDecoded[i/2] = iByte; + } + sqlite3_key_v2(db, zDb, zDecoded, i/2); + return 1; + }else if( (zKey = uriParameter(zUri, "key"))!=0 ){ + sqlite3_key_v2(db, zDb, zKey, sqlite3Strlen30(zKey)); + return 1; + }else if( (zKey = uriParameter(zUri, "textkey"))!=0 ){ + sqlite3_key_v2(db, zDb, zKey, -1); + return 1; + }else{ + return 0; + } +} +#endif /* SQLITE_HAS_CODEC */ /* ** This routine does the work of opening a database on behalf of @@ -175987,6 +177088,12 @@ opendb_out: }else if( rc!=SQLITE_OK ){ db->eOpenState = SQLITE_STATE_SICK; } +#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK + db->isDropTable = 0; + db->mDropTableName = NULL; + db->mDropSchemaName = NULL; + db->xDropTableHandle = NULL; +#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ *ppDb = db; #ifdef SQLITE_ENABLE_SQLLOG if( sqlite3GlobalConfig.xSqllog ){ @@ -175995,6 +177102,14 @@ opendb_out: sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0); } #endif +#ifdef SQLITE_HAS_CODEC + if( rc==SQLITE_OK ) { +#ifdef SQLITE_CODEC_ATTACH_CHANGED + sqlite3CodecResetParameters(&db->codecParm); +#endif /* SQLITE_CODEC_ATTACH_CHANGED */ + sqlite3CodecQueryParameters(db, 0, zOpen); + } +#endif /* SQLITE_HAS_CODEC */ sqlite3_free_filename(zOpen); return rc; } @@ -217581,15 +218696,19 @@ static int sessionReadRecord( } } if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ - sqlite3_int64 v = sessionGetI64(aVal); - if( eType==SQLITE_INTEGER ){ - sqlite3VdbeMemSetInt64(apOut[i], v); + if( (pIn->nData-pIn->iNext)<8 ){ + rc = SQLITE_CORRUPT_BKPT; }else{ - double d; - memcpy(&d, &v, 8); - sqlite3VdbeMemSetDouble(apOut[i], d); + sqlite3_int64 v = sessionGetI64(aVal); + if( eType==SQLITE_INTEGER ){ + sqlite3VdbeMemSetInt64(apOut[i], v); + }else{ + double d; + memcpy(&d, &v, 8); + sqlite3VdbeMemSetDouble(apOut[i], d); + } + pIn->iNext += 8; } - pIn->iNext += 8; } } } @@ -243614,3 +244733,1667 @@ SQLITE_API int sqlite3_stmt_init( /* Return the source-id for this library */ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } /************************** End of sqlite3.c ******************************/ + +#ifdef SQLITE_HAS_CODEC +/************** Begin file hw_codec_openssl.h *******************************/ +#ifndef EXPOSE_INTERNAL_FUNC +#define CODEC_STATIC static +#else +#define CODEC_STATIC +#endif + +#define DEFAULT_CIPHER "aes-256-gcm" + +typedef struct{ + unsigned char *buffer; + int bufferSize; +}Buffer; +/************** End file hw_codec_openssl.h *********************************/ +/************** Begin file hw_codec.h ***************************************/ +#define DEFAULT_PAGE_SIZE 1024 +#define DEFAULT_ITER 10000 +#define FILE_HEADER_SIZE 16 +#define SALT_SIZE FILE_HEADER_SIZE +#define HMAC_SALT_MASK 0x3a +#define HMAC_ITER 2 +#define MAX_HMAC_SIZE 64 +#define MAX_INIT_VECTOR_SIZE 16 +#define MIN_BLOCK_SIZE 16 + +#define CODEC_OPERATION_ENCRYPT 1 +#define CODEC_OPERATION_DECRYPT 0 + +#define KEY_CONTEXT_HEAD_SIZE (sizeof(CodecConstant) + 3 * sizeof(int)) + +typedef struct{ + void *cipher; + int keySize; + int keyInfoSize; + int cipherPageSize; + int initVectorSize; + int hmacSize; + int reserveSize; + int hmacAlgo; + int kdfAlgo; + int rekeyHmacAlgo; +}CodecConstant; + +typedef struct{ + CodecConstant codecConst; + int deriveFlag; + int iter; + int passwordSize; + unsigned char *password; + unsigned char *key; + unsigned char *hmacKey; + unsigned char *keyInfo; +}KeyContext; + +typedef struct{ + Btree *pBt; + int savePassword; + unsigned char salt[SALT_SIZE]; + unsigned char hmacSalt[SALT_SIZE]; + unsigned char *buffer; + KeyContext *readCtx; + KeyContext *writeCtx; +}CodecContext; + +/************** End file hw_codec.h *****************************************/ +/************** Begin file hw_codec_openssl.c *******************************/ +#include +#include +#include +#include + +unsigned int openssl_init_count = 0; +unsigned int openssl_external_init_flag = 0; +sqlite3_mutex *openssl_random_mutex = NULL; + +CODEC_STATIC void opensslActive(){ + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + + if(openssl_init_count == 0){ + if(EVP_get_cipherbyname(DEFAULT_CIPHER) == NULL){ + OpenSSL_add_all_algorithms(); + }else{ + openssl_external_init_flag = 1; + } + } + + if(openssl_random_mutex == NULL){ + openssl_random_mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + } + openssl_init_count++; + + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + return; +} + +CODEC_STATIC void opensslDeactive(){ + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + + openssl_init_count--; + if(openssl_init_count == 0){ + if(openssl_external_init_flag){ + openssl_external_init_flag = 0; + }else{ + EVP_cleanup(); + } + } + + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + return; +} + +CODEC_STATIC int opensslGetRandom(Buffer *buffer){ + sqlite3_mutex_enter(openssl_random_mutex); + int rc = RAND_bytes(buffer->buffer, buffer->bufferSize); + sqlite3_mutex_leave(openssl_random_mutex); + if(rc != 1){ + return SQLITE_ERROR; + } + return SQLITE_OK; +} + +CODEC_STATIC void *opensslGetCipher(const char *cipherName){ + return (void *)EVP_get_cipherbyname(cipherName); +} + +CODEC_STATIC int opensslFreeCipher(void *cipher){ + return SQLITE_OK; +} + +CODEC_STATIC const char *opensslGetCipherName(void *cipher){ + return EVP_CIPHER_name((EVP_CIPHER *)cipher); +} + +CODEC_STATIC int opensslGetKeySize(void *cipher){ + return EVP_CIPHER_key_length((EVP_CIPHER *)cipher); +} + +CODEC_STATIC int opensslGetInitVectorSize(void *cipher){ + return EVP_CIPHER_iv_length((EVP_CIPHER *)cipher); +} + +#define CIPHER_HMAC_ALGORITHM_SHA1 1 +#define CIPHER_HMAC_ALGORITHM_SHA256 2 +#define CIPHER_HMAC_ALGORITHM_SHA512 3 + +#define DEFAULT_HMAC_ALGORITHM CIPHER_HMAC_ALGORITHM_SHA1 + +#define CIPHER_HMAC_ALGORITHM_NAME_SHA1 "SHA1" +#define CIPHER_HMAC_ALGORITHM_NAME_SHA256 "SHA256" +#define CIPHER_HMAC_ALGORITHM_NAME_SHA512 "SHA512" + +#define CIPHER_KDF_ALGORITHM_SHA1 1 +#define CIPHER_KDF_ALGORITHM_SHA256 2 +#define CIPHER_KDF_ALGORITHM_SHA512 3 + +#define DEFAULT_KDF_ALGORITHM CIPHER_KDF_ALGORITHM_SHA1 + +#define CIPHER_KDF_ALGORITHM_NAME_SHA1 "KDF_SHA1" +#define CIPHER_KDF_ALGORITHM_NAME_SHA256 "KDF_SHA256" +#define CIPHER_KDF_ALGORITHM_NAME_SHA512 "KDF_SHA512" + + +CODEC_STATIC int opensslGetHmacSize(KeyContext *keyCtx){ + if( keyCtx==NULL ){ + return 0; + } + if( keyCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){ + return EVP_MD_size(EVP_sha1()); + }else if( keyCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){ + return EVP_MD_size(EVP_sha256()); + }else if( keyCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){ + return EVP_MD_size(EVP_sha512()); + } + return 0; +} + +CODEC_STATIC int opensslGetBlockSize(void *cipher){ + return EVP_CIPHER_block_size((EVP_CIPHER *)cipher); +} + +CODEC_STATIC void *opensslGetCtx(void *cipher, int mode, unsigned char *key, unsigned char *initVector){ + EVP_CIPHER_CTX *tmpCtx = EVP_CIPHER_CTX_new(); + if(tmpCtx == NULL){ + return (void *)tmpCtx; + } + EVP_CipherInit_ex(tmpCtx, (EVP_CIPHER *)cipher, NULL, NULL, NULL, mode); + EVP_CIPHER_CTX_set_padding(tmpCtx, 0); + EVP_CipherInit_ex(tmpCtx, NULL, NULL, key, initVector, mode); + return (void *)tmpCtx; +} + +CODEC_STATIC int opensslCipher(void *iCtx, Buffer *input, unsigned char *output){ + int outputLength = 0; + int cipherLength; + EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)iCtx; + EVP_CipherUpdate(ctx, output, &cipherLength, input->buffer, input->bufferSize); + outputLength += cipherLength; + output += cipherLength; + EVP_CipherFinal_ex(ctx, output, &cipherLength); + outputLength += cipherLength; + if(outputLength != input->bufferSize){ + return SQLITE_ERROR; + } + return SQLITE_OK; +} + +CODEC_STATIC void opensslFreeCtx(void *ctx){ + EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)ctx); +} + +CODEC_STATIC int opensslHmac(Buffer *key, Buffer *input1, Buffer *input2, Buffer *output, int hmacAlgo){ + HMAC_CTX *ctx = HMAC_CTX_new(); + if(ctx == NULL){ + return SQLITE_ERROR; + } + if( hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){ + HMAC_Init_ex(ctx, key->buffer, key->bufferSize, EVP_sha1(), NULL); + }else if( hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){ + HMAC_Init_ex(ctx, key->buffer, key->bufferSize, EVP_sha256(), NULL); + }else if( hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){ + HMAC_Init_ex(ctx, key->buffer, key->bufferSize, EVP_sha512(), NULL); + } + HMAC_Update(ctx, input1->buffer, input1->bufferSize); + HMAC_Update(ctx, input2->buffer, input2->bufferSize); + HMAC_Final(ctx, output->buffer, (unsigned int *)(&output->bufferSize)); + + HMAC_CTX_free(ctx); + return SQLITE_OK; +} + +CODEC_STATIC void opensslKdf(Buffer *password, Buffer *salt, int workfactor, Buffer *key, int kdfAlgo){ + if( kdfAlgo==CIPHER_KDF_ALGORITHM_SHA1 ){ + PKCS5_PBKDF2_HMAC((const char *)(password->buffer), password->bufferSize, salt->buffer, salt->bufferSize, + workfactor, EVP_sha1(), key->bufferSize, key->buffer); + }else if( kdfAlgo==CIPHER_KDF_ALGORITHM_SHA256 ){ + PKCS5_PBKDF2_HMAC((const char *)(password->buffer), password->bufferSize, salt->buffer, salt->bufferSize, + workfactor, EVP_sha256(), key->bufferSize, key->buffer); + }else if( kdfAlgo==CIPHER_KDF_ALGORITHM_SHA512 ){ + PKCS5_PBKDF2_HMAC((const char *)(password->buffer), password->bufferSize, salt->buffer, salt->bufferSize, + workfactor, EVP_sha512(), key->bufferSize, key->buffer); + } +} + +/************** End file hw_codec_openssl.c *********************************/ +/************** Begin file hw_codec.c ***************************************/ + +#include "securec.h" + +typedef enum{ + OPERATE_CONTEXT_READ = 0, + OPERATE_CONTEXT_WRITE, + OPERATE_CONTEXT_BOTH +}OperateContext; + +CODEC_STATIC int sqlite3CodecIsHex(const unsigned char *buffer, int bufferSize){ + int i; + for(i = 0; i < bufferSize; i++){ + if((buffer[i] < '0' || buffer[i] > '9') && + (buffer[i] < 'a' || buffer[i] > 'f') && + (buffer[i] < 'A' || buffer[i] > 'F')){ + return 0; + } + } + return 1; +} + +CODEC_STATIC int sqlite3CodecHex2int(char input){ + if(input >= '0' && input <= '9'){ + return (int)(input - '0'); + }else if(input >= 'a' && input <= 'f'){ + return (int)(input - 'a') + 10; + }else if(input >= 'A' && input <= 'F'){ + return (int)(input - 'A') + 10; + }else{ + return 0; + } +} + +CODEC_STATIC void sqlite3CodecHex2Bin(unsigned char *inputBuffer, int inputBuffersize, unsigned char *outputBuffer){ + int i; + for(i = 0; i < inputBuffersize - 1; i += 2){ + outputBuffer[i / 2] = sqlite3CodecHex2int(inputBuffer[i]) << 4 | sqlite3CodecHex2int(inputBuffer[i + 1]); + } + return; +} + +CODEC_STATIC void sqlite3CodecBin2Hex(unsigned char *inputBuffer, int inputBuffersize, unsigned char *outputBuffer){ + char *buffer = NULL; + int i; + for(i = 0; i < inputBuffersize; i++){ + buffer = (char *)(outputBuffer + i * 2); + sqlite3_snprintf(3, buffer, "%02x ", inputBuffer[i]); + } + return; +} + +CODEC_STATIC int sqlite3CodecIfMemset(unsigned char *input, unsigned char val, int len){ + int i; + for(i = 0; i < len; i++){ + if(input[i] != val){ + return 0; + } + } + return 1; +} + +CODEC_STATIC int sqlite3CodecIsKeyInfoFormat(const unsigned char *input, int inputSize){ + return (input[0] == 'x') && (input[1] == '\'') && (input[inputSize - 1] == '\'') && (sqlite3CodecIsHex(input + 2, inputSize - 3)) ? 1 : 0; +} + +CODEC_STATIC void sqlite3CodecSetError(CodecContext *ctx, int error){ + if(ctx->pBt){ + ctx->pBt->pBt->pPager->errCode = error; + ctx->pBt->pBt->db->errCode = error; + } + return; +} + +CODEC_STATIC void sqlite3CodecClearDeriveKey(KeyContext *keyCtx){ + if(keyCtx->key != NULL){ + (void)memset_s(keyCtx->key, keyCtx->codecConst.keySize, 0, keyCtx->codecConst.keySize); + sqlite3_free(keyCtx->key); + keyCtx->key = NULL; + } + if(keyCtx->hmacKey != NULL){ + (void)memset_s(keyCtx->hmacKey, keyCtx->codecConst.keySize, 0, keyCtx->codecConst.keySize); + sqlite3_free(keyCtx->hmacKey); + keyCtx->hmacKey = NULL; + } + if(keyCtx->keyInfo != NULL){ + (void)memset_s(keyCtx->keyInfo, keyCtx->codecConst.keyInfoSize, 0, keyCtx->codecConst.keyInfoSize); + sqlite3_free(keyCtx->keyInfo); + keyCtx->keyInfo = NULL; + } + keyCtx->deriveFlag = 0; +} + +CODEC_STATIC void sqlite3CodecClearPassword(KeyContext *keyCtx){ + if(keyCtx->password != NULL){ + (void)memset_s(keyCtx->password, keyCtx->passwordSize, 0, keyCtx->passwordSize); + sqlite3_free(keyCtx->password); + keyCtx->password = NULL; + } + keyCtx->passwordSize = 0; +} + +CODEC_STATIC void sqlite3CodecInitDeriveKeyMemory(KeyContext *keyCtx){ + keyCtx->key = (unsigned char *)sqlite3Malloc(keyCtx->codecConst.keySize); + keyCtx->hmacKey = (unsigned char *)sqlite3Malloc(keyCtx->codecConst.keySize); + keyCtx->keyInfo = (unsigned char *)sqlite3Malloc(keyCtx->codecConst.keyInfoSize); + return; +} + +CODEC_STATIC int sqlite3CodecKeyCtxCmp(KeyContext *first, KeyContext *second){ + if(memcmp((unsigned char *)first, (unsigned char *)second, sizeof(CodecConstant))){ + return 0; + } + if(first->iter != second->iter){ + return 0; + } + if(first->passwordSize != second->passwordSize){ + return 0; + } + if((first->password != second->password) && memcmp(first->password, second->password, first->passwordSize)){ + return 0; + } + return 1; +} + +// This function will free all resources of key context, except it self. +CODEC_STATIC void sqlite3CodecFreeKeyContext(KeyContext *keyCtx){ + sqlite3CodecClearDeriveKey(keyCtx); + sqlite3CodecClearPassword(keyCtx); + (void)opensslFreeCipher(keyCtx->codecConst.cipher); + (void)memset_s(keyCtx, sizeof(KeyContext), 0, KEY_CONTEXT_HEAD_SIZE); +} + +// You should clear key derive result of output before you call this function +CODEC_STATIC int sqlite3CodecCopyDeriveKey(KeyContext *input, KeyContext *output){ + errno_t rc = EOK; + if(input->key != NULL && input->codecConst.keySize > 0){ + output->key = (unsigned char *)sqlite3Malloc(output->codecConst.keySize); + if(output->key == NULL){ + sqlite3CodecFreeKeyContext(output); + return SQLITE_NOMEM; + } + rc = memcpy_s(output->key, output->codecConst.keySize, input->key, input->codecConst.keySize); + if(rc != EOK){ + sqlite3CodecFreeKeyContext(output); + return SQLITE_ERROR; + } + } + if(input->hmacKey != NULL && input->codecConst.keySize > 0){ + output->hmacKey = (unsigned char *)sqlite3Malloc(output->codecConst.keySize); + if(output->hmacKey == NULL){ + sqlite3CodecFreeKeyContext(output); + return SQLITE_NOMEM; + } + rc = memcpy_s(output->hmacKey, output->codecConst.keySize, input->hmacKey, input->codecConst.keySize); + if(rc != EOK){ + sqlite3CodecFreeKeyContext(output); + return SQLITE_ERROR; + } + } + if(input->keyInfo != NULL && input->codecConst.keyInfoSize > 0){ + output->keyInfo = (unsigned char *)sqlite3Malloc(output->codecConst.keyInfoSize); + if(output->keyInfo == NULL){ + sqlite3CodecFreeKeyContext(output); + return SQLITE_NOMEM; + } + rc = memcpy_s(output->keyInfo, output->codecConst.keyInfoSize, input->keyInfo, input->codecConst.keyInfoSize); + if(rc != EOK){ + sqlite3CodecFreeKeyContext(output); + return SQLITE_ERROR; + } + } + return SQLITE_OK; +} + +// You should set all key infos including salt before you call this function +CODEC_STATIC int sqlite3CodecDeriveKey(CodecContext *ctx, OperateContext whichKey){ + KeyContext *keyCtx = NULL; + KeyContext *secondKeyCtx = NULL; + switch(whichKey){ + case OPERATE_CONTEXT_READ: + keyCtx = ctx->readCtx; + secondKeyCtx = ctx->writeCtx; + break; + case OPERATE_CONTEXT_WRITE: + keyCtx = ctx->writeCtx; + secondKeyCtx = ctx->readCtx; + break; + default: + return SQLITE_ERROR; + } + if(keyCtx->password == NULL || keyCtx->passwordSize <= 0){ + return SQLITE_ERROR; + } + if(keyCtx->deriveFlag){ + return SQLITE_OK; + } + errno_t memcpyRc = EOK; + unsigned char salt[SALT_SIZE]; + if (ctx->pBt != NULL && sqlite3OsRead(ctx->pBt->pBt->pPager->fd, salt, SALT_SIZE, 0) == SQLITE_OK) { + assert(SALT_SIZE == FILE_HEADER_SIZE); + if (memcmp(SQLITE_FILE_HEADER, salt, SALT_SIZE) != 0 && memcmp(ctx->salt, salt, SALT_SIZE) != 0) { + memcpyRc = memcpy_s(ctx->salt, FILE_HEADER_SIZE, salt, SALT_SIZE); + if(memcpyRc != EOK){ + return SQLITE_ERROR; + } + } + } + sqlite3CodecInitDeriveKeyMemory(keyCtx); + if(keyCtx->key == NULL || keyCtx->hmacKey == NULL || keyCtx->keyInfo == NULL){ + sqlite3CodecClearDeriveKey(keyCtx); + return SQLITE_NOMEM; + } + if((keyCtx->passwordSize == keyCtx->codecConst.keyInfoSize) && + (sqlite3CodecIsKeyInfoFormat(keyCtx->password, keyCtx->passwordSize))){ + sqlite3CodecHex2Bin(keyCtx->password + 2, keyCtx->codecConst.keySize * 2, keyCtx->key); + sqlite3CodecHex2Bin(keyCtx->password + 2 + keyCtx->codecConst.keySize * 2, SALT_SIZE * 2, ctx->salt); + memcpyRc = memcpy_s(keyCtx->keyInfo, keyCtx->codecConst.keyInfoSize, keyCtx->password, keyCtx->passwordSize); + if(memcpyRc != EOK){ + return SQLITE_ERROR; + } + }else if((keyCtx->passwordSize == keyCtx->codecConst.keyInfoSize - SALT_SIZE * 2) && + (sqlite3CodecIsKeyInfoFormat(keyCtx->password, keyCtx->passwordSize))){ + sqlite3CodecHex2Bin(keyCtx->password + 2, keyCtx->codecConst.keySize * 2, keyCtx->key); + memcpyRc = memcpy_s(keyCtx->keyInfo, keyCtx->codecConst.keyInfoSize, keyCtx->password, keyCtx->passwordSize); + if(memcpyRc != EOK){ + return SQLITE_ERROR; + } + sqlite3CodecBin2Hex(ctx->salt, SALT_SIZE, keyCtx->keyInfo + 2 + keyCtx->codecConst.keySize * 2); + keyCtx->keyInfo[keyCtx->codecConst.keyInfoSize - 1] = '\''; + }else{ + Buffer password; + Buffer salt; + Buffer key; + password.buffer = keyCtx->password; + password.bufferSize = keyCtx->passwordSize; + salt.buffer = ctx->salt; + salt.bufferSize = SALT_SIZE; + key.buffer = keyCtx->key; + key.bufferSize = keyCtx->codecConst.keySize; + opensslKdf(&password, &salt, keyCtx->iter, &key, keyCtx->codecConst.kdfAlgo); + keyCtx->keyInfo[0] = 'x'; + keyCtx->keyInfo[1] = '\''; + sqlite3CodecBin2Hex(keyCtx->key, keyCtx->codecConst.keySize, keyCtx->keyInfo + 2); + sqlite3CodecBin2Hex(ctx->salt, SALT_SIZE, keyCtx->keyInfo + 2 + keyCtx->codecConst.keySize * 2); + keyCtx->keyInfo[keyCtx->codecConst.keyInfoSize - 1] = '\''; + } + int i; + for(i = 0; i < SALT_SIZE; i++){ + ctx->hmacSalt[i] = ctx->salt[i] ^ HMAC_SALT_MASK; + } + Buffer hmacPassword; + Buffer hmacSalt; + Buffer hmacKey; + hmacPassword.buffer = keyCtx->key; + hmacPassword.bufferSize = keyCtx->codecConst.keySize; + hmacSalt.buffer = ctx->hmacSalt; + hmacSalt.bufferSize = SALT_SIZE; + hmacKey.buffer = keyCtx->hmacKey; + hmacKey.bufferSize = keyCtx->codecConst.keySize; + opensslKdf(&hmacPassword, &hmacSalt, HMAC_ITER, &hmacKey, keyCtx->codecConst.kdfAlgo); + keyCtx->deriveFlag = 1; + if(sqlite3CodecKeyCtxCmp(keyCtx, secondKeyCtx)){ + sqlite3CodecClearDeriveKey(secondKeyCtx); + int rc = sqlite3CodecCopyDeriveKey(keyCtx, secondKeyCtx); + if(rc == SQLITE_OK){ + secondKeyCtx->deriveFlag = 1; + // clear password + if(!(ctx->savePassword)){ + sqlite3CodecClearPassword(secondKeyCtx); + } + } + } + // clear password + if(!(ctx->savePassword)){ + sqlite3CodecClearPassword(keyCtx); + } + return SQLITE_OK; +} + +// This function may clear key derive infos +CODEC_STATIC int sqlite3CodecSetCodecConstant(KeyContext *keyCtx, const char *cipherName){ + if(keyCtx->codecConst.cipher){ + if(sqlite3StrICmp(cipherName, opensslGetCipherName(keyCtx->codecConst.cipher)) == 0){ + return SQLITE_OK; + } + } + sqlite3CodecClearDeriveKey(keyCtx); + void *cipher = opensslGetCipher(cipherName); + if(cipher != NULL){ + keyCtx->codecConst.cipher = cipher; + } else { + return SQLITE_ERROR; + } + keyCtx->codecConst.keySize = opensslGetKeySize(keyCtx->codecConst.cipher); + keyCtx->codecConst.keyInfoSize = (keyCtx->codecConst.keySize + SALT_SIZE) * 2 + 3; + keyCtx->codecConst.initVectorSize = opensslGetInitVectorSize(keyCtx->codecConst.cipher); + return SQLITE_OK; +} + +// You should clear key derive infos before you call this function +CODEC_STATIC int sqlite3CodecSetIter(KeyContext *keyCtx, int iter){ + keyCtx->iter = iter; + return SQLITE_OK; +} + +#ifdef SQLITE_CODEC_ATTACH_CHANGED +#define CIPHER_ID_AES_256_CBC 0 +#define CIPHER_ID_AES_256_GCM 1 + +#define CIPHER_TOTAL_NUM 2 + +#define CIPHER_NAME_AES_256_CBC "aes-256-cbc" +#define CIPHER_NAME_AES_256_GCM "aes-256-gcm" + +struct CodecCipherNameId { + int cipherId; + const char *cipherName; +}; + +static const struct CodecCipherNameId g_cipherNameIdMap[CIPHER_TOTAL_NUM] = { + { CIPHER_ID_AES_256_CBC, CIPHER_NAME_AES_256_CBC }, + { CIPHER_ID_AES_256_GCM, CIPHER_NAME_AES_256_GCM } +}; + +SQLITE_PRIVATE void sqlite3CodecResetParameters(CodecParameter *p) +{ + p->kdfIter = DEFAULT_ITER; + p->pageSize = DEFAULT_PAGE_SIZE; + p->cipher = CIPHER_ID_AES_256_GCM; + p->hmacAlgo = DEFAULT_HMAC_ALGORITHM; + p->kdfAlgo = DEFAULT_KDF_ALGORITHM; +} + +CODEC_STATIC void sqlite3CodecSetDefaultAttachCipher(CodecParameter *parm, const char *cipherName){ + int i; + for( i=0; icipher = g_cipherNameIdMap[i].cipherId; + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + return; + } + } + sqlite3_log(SQLITE_WARNING, "invalid attach cipher algorithm"); +} + +CODEC_STATIC const char *sqlite3CodecGetDefaultAttachCipher(CodecParameter *parm){ + const char *attachedCipher = CIPHER_NAME_AES_256_GCM; + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + if( (parm->cipher>=0) && (parm->ciphercipher].cipherName; + } + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + return attachedCipher; +} + +CODEC_STATIC void sqlite3CodecSetDefaultAttachKdfIter(CodecParameter *parm, int iter){ + if( iter<=0 ){ + return; + } + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + parm->kdfIter = iter; + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); +} + +CODEC_STATIC int sqlite3CodecGetDefaultAttachKdfIter(CodecParameter *parm){ + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + int iterNum = parm->kdfIter; + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + return iterNum; +} + +CODEC_STATIC void sqlite3CodecSetDefaultAttachHmacAlgo(CodecParameter *parm, int hmacAlgo){ + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + parm->hmacAlgo = hmacAlgo; + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); +} + +CODEC_STATIC int sqlite3CodecGetDefaultAttachHmacAlgo(CodecParameter *parm){ + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + int hmacAlgo = parm->hmacAlgo; + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + return hmacAlgo; +} + +CODEC_STATIC void sqlite3CodecSetDefaultAttachKdfAlgo(CodecParameter *parm, int kdfAlgo){ + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + parm->kdfAlgo = kdfAlgo; + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); +} + +CODEC_STATIC int sqlite3CodecGetDefaultAttachKdfAlgo(CodecParameter *parm){ + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + int kdfAlgo = parm->kdfAlgo; + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + return kdfAlgo; +} + +CODEC_STATIC void sqlite3CodecSetDefaultAttachPageSize(CodecParameter *parm, int pageSize){ + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + parm->pageSize = pageSize; + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); +} + +CODEC_STATIC int sqlite3CodecGetDefaultAttachPageSize(CodecParameter *parm){ + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + int pageSize = parm->pageSize; + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); + return pageSize; +} + +#endif /* SQLITE_CODEC_ATTACH_CHANGED */ + +// You should clear key derive infos and password infos before you call this function +CODEC_STATIC int sqlite3CodecSetPassword(KeyContext *keyCtx, const void *zKey, int nKey){ + keyCtx->passwordSize = nKey; + keyCtx->password = (unsigned char *)sqlite3Malloc(keyCtx->passwordSize); + if(keyCtx->password == NULL){ + return SQLITE_NOMEM; + } + errno_t rc = memcpy_s(keyCtx->password, keyCtx->passwordSize, zKey, nKey); + if(rc != EOK){ + sqlite3CodecClearPassword(keyCtx); + return SQLITE_ERROR; + } + return SQLITE_OK; +} + +// You should clear key derive infos and password infos before you call this function +CODEC_STATIC int sqlite3CodecSetHmacAlgorithm(KeyContext *keyCtx, int hmacAlgo){ + keyCtx->codecConst.hmacAlgo = hmacAlgo; + keyCtx->codecConst.hmacSize = opensslGetHmacSize(keyCtx); + int cipherBlockSize = opensslGetBlockSize(keyCtx->codecConst.cipher); + int blockSize = cipherBlockSize; + while(blockSize < MIN_BLOCK_SIZE){ + blockSize += cipherBlockSize; + } + int reserveSize = MAX_INIT_VECTOR_SIZE + keyCtx->codecConst.hmacSize; + if(reserveSize % blockSize == 0){ + keyCtx->codecConst.reserveSize = reserveSize; + }else{ + keyCtx->codecConst.reserveSize = (reserveSize / blockSize + 1) * blockSize; + } + return SQLITE_OK; +} + +CODEC_STATIC int sqlite3CodecSetKdfAlgorithm(KeyContext *keyCtx, int kdfAlgo){ + keyCtx->codecConst.kdfAlgo = kdfAlgo; + return SQLITE_OK; +} + +CODEC_STATIC int sqlite3CodecSetCipherPageSize(CodecContext *ctx, int size){ + if(!((size != 0) && ((size & (size - 1)) == 0)) || size < 512 || size > 65536) { + sqlite3_log(SQLITE_ERROR, "codec: cipher_page_size not a power of 2 and between 512 and 65536 inclusive(%d).", size); + return SQLITE_ERROR; + } + int cipherPageSize = ctx->readCtx->codecConst.cipherPageSize; + (void)memset_s(ctx->buffer, cipherPageSize, 0, cipherPageSize); + sqlite3_free(ctx->buffer); + ctx->readCtx->codecConst.cipherPageSize = size; + ctx->writeCtx->codecConst.cipherPageSize = size; + + ctx->buffer = (unsigned char *)sqlite3Malloc(size); + if (ctx->buffer == NULL) { + sqlite3_log(SQLITE_NOMEM, "codec: alloc mem failed when set cipher page size(%d).", size); + return SQLITE_NOMEM; + } + return SQLITE_OK; +} + +// You should clear output before you call this function +CODEC_STATIC int sqlite3CodecCopyKeyContext(KeyContext *input, KeyContext *output){ + errno_t rc = memcpy_s(output, sizeof(KeyContext), input, KEY_CONTEXT_HEAD_SIZE); + if(rc != EOK){ + return SQLITE_ERROR; + } + if(input->password != NULL && input->passwordSize > 0){ + output->password = (unsigned char *)sqlite3Malloc(output->passwordSize); + if(output->password == NULL){ + sqlite3CodecFreeKeyContext(output); + return SQLITE_NOMEM; + } + rc = memcpy_s(output->password, output->passwordSize, input->password, input->passwordSize); + if(rc != EOK){ + sqlite3CodecFreeKeyContext(output); + return SQLITE_ERROR; + } + } + return sqlite3CodecCopyDeriveKey(input, output); +} + +// You should clear key context before you call this function +#ifdef SQLITE_CODEC_ATTACH_CHANGED +CODEC_STATIC int sqlite3CodecInitKeyContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey, int attachFlag){ +#else +CODEC_STATIC int sqlite3CodecInitKeyContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey){ +#endif /* SQLITE_CODEC_ATTACH_CHANGED */ + int rc = SQLITE_OK; + KeyContext *keyCtx = ctx->readCtx; +#ifdef SQLITE_CODEC_ATTACH_CHANGED + if( attachFlag!=0 ){ + CodecParameter *parm = &p->db->codecParm; + int hmacAlgo = sqlite3CodecGetDefaultAttachHmacAlgo(parm); + rc = sqlite3CodecSetCodecConstant(keyCtx, sqlite3CodecGetDefaultAttachCipher(parm)); + rc += sqlite3CodecSetIter(keyCtx, sqlite3CodecGetDefaultAttachKdfIter(parm)); + if( hmacAlgo!=0 ){ + rc += sqlite3CodecSetHmacAlgorithm(keyCtx, hmacAlgo); + } + int attachKdfAlgo = sqlite3CodecGetDefaultAttachKdfAlgo(parm); + if( attachKdfAlgo!=0 ){ + rc += sqlite3CodecSetKdfAlgorithm(keyCtx, attachKdfAlgo); + } + int cipherPageSize = sqlite3CodecGetDefaultAttachPageSize(parm); + if( cipherPageSize!=0 ){ + rc += sqlite3CodecSetCipherPageSize(ctx, cipherPageSize); + if ( rc != SQLITE_OK ) { + sqlite3CodecFreeKeyContext(keyCtx); + return SQLITE_ERROR; + } + rc += sqlite3BtreeSetPageSize(p, cipherPageSize, keyCtx->codecConst.reserveSize, 0); + } + }else{ + rc = sqlite3CodecSetCodecConstant(keyCtx, DEFAULT_CIPHER); + rc += sqlite3CodecSetIter(keyCtx, DEFAULT_ITER); + rc += sqlite3CodecSetHmacAlgorithm(keyCtx, DEFAULT_HMAC_ALGORITHM); + rc += sqlite3CodecSetKdfAlgorithm(keyCtx, DEFAULT_KDF_ALGORITHM); + } +#else + rc = sqlite3CodecSetCodecConstant(keyCtx, DEFAULT_CIPHER); + rc += sqlite3CodecSetIter(keyCtx, DEFAULT_ITER); + rc += sqlite3CodecSetHmacAlgorithm(keyCtx, DEFAULT_HMAC_ALGORITHM); + rc += sqlite3CodecSetKdfAlgorithm(keyCtx, DEFAULT_KDF_ALGORITHM); +#endif /* SQLITE_CODEC_ATTACH_CHANGED */ + keyCtx->codecConst.rekeyHmacAlgo = DEFAULT_HMAC_ALGORITHM; + rc += sqlite3CodecSetPassword(keyCtx, zKey, nKey); + if(rc != SQLITE_OK){ + sqlite3CodecFreeKeyContext(keyCtx); + return SQLITE_ERROR; + } + return SQLITE_OK; +} + +// This function will free all resources of codec context, except it self. +CODEC_STATIC void sqlite3CodecFreeContext(CodecContext *ctx){ + if(ctx->buffer){ + int cipherPageSize = ctx->readCtx->codecConst.cipherPageSize; + (void)memset_s(ctx->buffer, cipherPageSize, 0, cipherPageSize); + sqlite3_free(ctx->buffer); + ctx->buffer = NULL; + } + if(ctx->readCtx){ + sqlite3CodecFreeKeyContext(ctx->readCtx); + sqlite3_free(ctx->readCtx); + ctx->readCtx = NULL; + } + if(ctx->writeCtx){ + sqlite3CodecFreeKeyContext(ctx->writeCtx); + sqlite3_free(ctx->writeCtx); + ctx->writeCtx = NULL; + } + (void)memset_s(ctx, sizeof(CodecContext), 0, sizeof(CodecContext)); + return; +} +#ifdef SQLITE_CODEC_ATTACH_CHANGED +CODEC_STATIC int sqlite3CodecInitContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey, int nDb){ + int attachFlag = (nDb > 1) ? 1 : 0; + int defaultPageSz = attachFlag ? p->db->codecParm.pageSize : DEFAULT_PAGE_SIZE; +#else +CODEC_STATIC int sqlite3CodecInitContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey){ + int defaultPageSz = DEFAULT_PAGE_SIZE; +#endif /* SQLITE_CODEC_ATTACH_CHANGED */ + sqlite3_file *fd = p->pBt->pPager->fd; + ctx->pBt = p; + ctx->savePassword = 0; + ctx->buffer = (unsigned char *)sqlite3Malloc(defaultPageSz); + ctx->readCtx = (KeyContext *)sqlite3Malloc(sizeof(KeyContext)); + ctx->writeCtx = (KeyContext *)sqlite3Malloc(sizeof(KeyContext)); + if(ctx->buffer == NULL || ctx->readCtx == NULL || ctx->writeCtx == NULL){ + sqlite3CodecFreeContext(ctx); + return SQLITE_NOMEM; + } + errno_t memsetRc = memset_s(ctx->buffer, defaultPageSz, 0, defaultPageSz); + memsetRc += memset_s(ctx->readCtx, sizeof(KeyContext), 0, sizeof(KeyContext)); + memsetRc += memset_s(ctx->writeCtx, sizeof(KeyContext), 0, sizeof(KeyContext)); + if(memsetRc != EOK){ + sqlite3CodecFreeContext(ctx); + return SQLITE_ERROR; + } + ctx->readCtx->codecConst.cipherPageSize = defaultPageSz; + ctx->writeCtx->codecConst.cipherPageSize = defaultPageSz; +#ifdef SQLITE_CODEC_ATTACH_CHANGED + int rc = sqlite3CodecInitKeyContext(ctx, p, zKey, nKey, attachFlag); +#else + int rc = sqlite3CodecInitKeyContext(ctx, p, zKey, nKey); +#endif /* SQLITE_CODEC_ATTACH_CHANGED */ + if(rc != SQLITE_OK){ + sqlite3CodecFreeContext(ctx); + return SQLITE_ERROR; + } + rc = sqlite3CodecCopyKeyContext(ctx->readCtx, ctx->writeCtx); + if(rc != SQLITE_OK){ + sqlite3CodecFreeContext(ctx); + return SQLITE_ERROR; + } + if(fd == NULL || !(isOpen(fd)) || sqlite3OsRead(fd, ctx->salt, SALT_SIZE, 0) != SQLITE_OK){ + Buffer salt; + salt.buffer = ctx->salt; + salt.bufferSize = SALT_SIZE; + rc = opensslGetRandom(&salt); + if(rc != SQLITE_OK){ + sqlite3CodecFreeContext(ctx); + return rc; + } + } + return SQLITE_OK; +} + +CODEC_STATIC int sqlite3CodecGetDbIndex(sqlite3 *db, const char *zDb){ + int nDbIndex; + if(zDb == NULL){ + return 0; + } + for(nDbIndex = 0; nDbIndex < db->nDb; nDbIndex++){ + const char *zDbSName = db->aDb[nDbIndex].zDbSName; + if(strcmp(zDbSName, zDb) == 0){ + return nDbIndex; + } + } + return 0; +} + +CODEC_STATIC void sqlite3CodecTransPgno(Pgno input, unsigned char *output){ +#ifdef CIPHER_BIG_ENDAIN + sqlite3Put4byte(output, input); +#else + output[0] = (u8)input; + output[1] = (u8)(input>>8); + output[2] = (u8)(input>>16); + output[3] = (u8)(input>>24); +#endif +} + +CODEC_STATIC int sqlite3CodecHmac(KeyContext *ctx, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *output){ + Buffer key; + key.buffer = ctx->hmacKey; + key.bufferSize = ctx->codecConst.keySize; + Buffer input1; + input1.buffer = input; + input1.bufferSize = bufferSize; + Buffer input2; + unsigned char pgnoBuffer[sizeof(Pgno)]; + sqlite3CodecTransPgno(pgno, pgnoBuffer); + input2.buffer = pgnoBuffer; + input2.bufferSize = sizeof(Pgno); + Buffer outputBuffer; + outputBuffer.buffer = output; + outputBuffer.bufferSize = 0; + int rc = opensslHmac(&key, &input1, &input2, &outputBuffer, ctx->codecConst.hmacAlgo); + if(rc != SQLITE_OK || outputBuffer.bufferSize != ctx->codecConst.hmacSize){ + return SQLITE_ERROR; + } + return SQLITE_OK; +} + +CODEC_STATIC int sqlite3CodecCheckHmac(KeyContext *ctx, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *expectResult){ + if (ctx->codecConst.hmacSize <= 0) { + return 1; + } + int rc = SQLITE_OK; + if (ctx->codecConst.hmacSize <= MAX_HMAC_SIZE) { + unsigned char buffer[MAX_HMAC_SIZE]; + rc = sqlite3CodecHmac(ctx, pgno, bufferSize, input, buffer); + if(rc != SQLITE_OK){ + return 1; + } + return memcmp(buffer, expectResult, ctx->codecConst.hmacSize); + } else { + unsigned char *output = (unsigned char *)malloc(ctx->codecConst.hmacSize); + if (output == NULL) { + return 1; + } + rc = sqlite3CodecHmac(ctx, pgno, bufferSize, input, output); + if(rc != SQLITE_OK){ + free(output); + return 1; + } + rc = memcmp(output, expectResult, ctx->codecConst.hmacSize); + free(output); + return rc; + } +} + +CODEC_STATIC int sqlite3CodecEncryptData(CodecContext *ctx, OperateContext whichKey, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *output){ + KeyContext *keyCtx = NULL; + switch(whichKey){ + case OPERATE_CONTEXT_READ: + keyCtx = ctx->readCtx; + break; + case OPERATE_CONTEXT_WRITE: + keyCtx = ctx->writeCtx; + break; + default: + return SQLITE_ERROR; + } + int rc = SQLITE_OK; + if(!(keyCtx->deriveFlag)){ + rc = sqlite3CodecDeriveKey(ctx, whichKey); + if(rc != SQLITE_OK){ + return rc; + } + } + if(keyCtx->codecConst.keySize == 0){ + return SQLITE_ERROR; + } + Buffer inputBuffer; + inputBuffer.buffer = input; + inputBuffer.bufferSize = bufferSize - keyCtx->codecConst.reserveSize; + Buffer initVector; + initVector.buffer = output + inputBuffer.bufferSize; + initVector.bufferSize = keyCtx->codecConst.initVectorSize; + rc = opensslGetRandom(&initVector); + if(rc != SQLITE_OK){ + return rc; + } + void *cipherCtx = opensslGetCtx(keyCtx->codecConst.cipher, CODEC_OPERATION_ENCRYPT, keyCtx->key, initVector.buffer); + if(cipherCtx == NULL){ + return SQLITE_ERROR; + } + rc = opensslCipher(cipherCtx, &inputBuffer, output); + opensslFreeCtx(cipherCtx); + if(rc != SQLITE_OK){ + return rc; + } + rc = sqlite3CodecHmac(keyCtx, pgno, inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize, output, output + inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize); + if(rc != SQLITE_OK){ + return rc; + } + return SQLITE_OK; +} + +CODEC_STATIC int sqlite3CodecDecryptData(CodecContext *ctx, OperateContext whichKey, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *output){ + KeyContext *keyCtx = NULL; + switch(whichKey){ + case OPERATE_CONTEXT_READ: + keyCtx = ctx->readCtx; + break; + case OPERATE_CONTEXT_WRITE: + keyCtx = ctx->writeCtx; + break; + default: + return SQLITE_ERROR; + } + int rc = SQLITE_OK; + if(!(keyCtx->deriveFlag)){ + rc = sqlite3CodecDeriveKey(ctx, whichKey); + if(rc != SQLITE_OK){ + return rc; + } + } + if(keyCtx->codecConst.keySize == 0){ + return SQLITE_ERROR; + } + if(sqlite3CodecIfMemset(input, 0, bufferSize)){ + errno_t memsetRc = memset_s(output, bufferSize, 0, bufferSize); + if(memsetRc != EOK){ + return SQLITE_ERROR; + } + return SQLITE_OK; + }else{ + Buffer inputBuffer; + inputBuffer.buffer = input; + inputBuffer.bufferSize = bufferSize - keyCtx->codecConst.reserveSize; + if(sqlite3CodecCheckHmac(keyCtx, pgno, inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize, input, input + inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize)){ + sqlite3_log(SQLITE_ERROR, "codec: check hmac error at page %d, hmac %d, kdf %d, pageSize %d, iter %d.", + pgno, keyCtx->codecConst.hmacAlgo, keyCtx->codecConst.kdfAlgo, keyCtx->codecConst.cipherPageSize, keyCtx->iter); + return SQLITE_ERROR; + } + unsigned char *initVector = input + inputBuffer.bufferSize; + void *cipherCtx = opensslGetCtx(keyCtx->codecConst.cipher, CODEC_OPERATION_DECRYPT, keyCtx->key, initVector); + if(cipherCtx == NULL){ + return SQLITE_ERROR; + } + rc = opensslCipher(cipherCtx, &inputBuffer, output); + opensslFreeCtx(cipherCtx); + if(rc != SQLITE_OK){ + return rc; + } + } + return SQLITE_OK; +} + +void* sqlite3Codec(void *ctx, void *data, Pgno pgno, int mode){ + CodecContext *pCtx = (CodecContext *)ctx; + unsigned char *pData = (unsigned char *)data; + int offset = 0; + int rc = SQLITE_OK; + errno_t memcpyRc = EOK; + if(ctx == NULL || data == NULL){ + return pData; + } + if(pgno == 1){ + offset = FILE_HEADER_SIZE; + } + int cipherPageSize = pCtx->readCtx->codecConst.cipherPageSize; + switch(mode){ + case 0: + case 2: + case 3: + if(pgno == 1){ + memcpyRc = memcpy_s(pCtx->buffer, cipherPageSize, SQLITE_FILE_HEADER, FILE_HEADER_SIZE); + if(memcpyRc != EOK){ + sqlite3CodecSetError(pCtx, SQLITE_ERROR); + return pData; + } + } + rc = sqlite3CodecDecryptData(pCtx, OPERATE_CONTEXT_READ, pgno, cipherPageSize - offset, (unsigned char *)(pData + offset), pCtx->buffer + offset); + if(rc != SQLITE_OK){ + sqlite3CodecSetError(pCtx, rc); + } + (void)memcpy_s(pData, cipherPageSize, pCtx->buffer, cipherPageSize); + return pData; + break; + case 6: + if(pgno == 1){ + memcpyRc = memcpy_s(pCtx->buffer, cipherPageSize, pCtx->salt, FILE_HEADER_SIZE); + if(memcpyRc != EOK){ + sqlite3CodecSetError(pCtx, SQLITE_ERROR); + return pData; + } + } + rc = sqlite3CodecEncryptData(pCtx, OPERATE_CONTEXT_WRITE, pgno, cipherPageSize - offset, (unsigned char *)(pData + offset), pCtx->buffer + offset); + if(rc != SQLITE_OK){ + sqlite3CodecSetError(pCtx, rc); + return pData; + } + return pCtx->buffer; + break; + case 7: + if(pgno == 1){ + memcpyRc = memcpy_s(pCtx->buffer, cipherPageSize, pCtx->salt, FILE_HEADER_SIZE); + if(memcpyRc != EOK){ + sqlite3CodecSetError(pCtx, SQLITE_ERROR); + return pData; + } + } + rc = sqlite3CodecEncryptData(pCtx, OPERATE_CONTEXT_READ, pgno, cipherPageSize - offset, (unsigned char *)(pData + offset), pCtx->buffer + offset); + if(rc != SQLITE_OK){ + sqlite3CodecSetError(pCtx, rc); + return pData; + } + return pCtx->buffer; + break; + default: + return pData; + break; + } +} + +void sqlite3CodecDetach(void *ctx){ + if(ctx != NULL){ + sqlite3CodecFreeContext((CodecContext *)ctx); + sqlite3_free(ctx); + opensslDeactive(); + } + return; +} + +int sqlite3CodecAttach(sqlite3* db, int nDb, const void *pKey, int nKey){ + if(db == NULL){ + return SQLITE_ERROR; + } + Btree *p = db->aDb[nDb].pBt; + if(p == NULL || pKey == NULL || nKey <= 0){ + return SQLITE_OK; + } + opensslActive(); + CodecContext *ctx = (CodecContext *)sqlite3Malloc(sizeof(CodecContext)); + if(ctx == NULL){ + return SQLITE_NOMEM; + } + errno_t memsetRc = memset_s(ctx, sizeof(CodecContext), 0, sizeof(CodecContext)); + if(memsetRc != EOK){ + sqlite3_free(ctx); + return SQLITE_ERROR; + } + sqlite3_mutex_enter(db->mutex); +#ifdef SQLITE_CODEC_ATTACH_CHANGED + int rc = sqlite3CodecInitContext(ctx, p, pKey, nKey, nDb); +#else + int rc = sqlite3CodecInitContext(ctx, p, pKey, nKey); +#endif /* SQLITE_CODEC_ATTACH_CHANGED */ + if(rc != SQLITE_OK){ + sqlite3_free(ctx); + return rc; + } + sqlite3PagerSetCodec(sqlite3BtreePager(p), sqlite3Codec, NULL, sqlite3CodecDetach, (void *)ctx); + + db->nextPagesize = ctx->readCtx->codecConst.cipherPageSize; + p->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED; + sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); + sqlite3BtreeSecureDelete(p, 1); + if(isOpen(p->pBt->pPager->fd)){ + sqlite3BtreeSetAutoVacuum(p, SQLITE_DEFAULT_AUTOVACUUM); + } + + sqlite3_mutex_leave(db->mutex); + + return SQLITE_OK; +} + +void sqlite3CodecGetKey(sqlite3* db, int nDb, void **pKey, int *nKey) +{ + Btree *p = db->aDb[nDb].pBt; + if(p == NULL){ + return; + } + CodecContext *ctx = (CodecContext *)(p->pBt->pPager->pCodec); + if(ctx){ + if(ctx->savePassword){ + *pKey = ctx->readCtx->password; + *nKey = ctx->readCtx->passwordSize; + }else{ + *pKey = ctx->readCtx->keyInfo; + *nKey = ctx->readCtx->codecConst.keyInfoSize; + } + }else{ + *pKey = NULL; + *nKey = 0; + } + return; +} + +int sqlite3_key(sqlite3 *db, const void *pKey, int nKey){ + return sqlite3_key_v2(db, "main", pKey, nKey); +} + +int sqlite3_key_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey){ + if(db == NULL || pKey == NULL || nKey <= 0){ + return SQLITE_ERROR; + } + int iDb = sqlite3CodecGetDbIndex(db, zDb); + return sqlite3CodecAttach(db, iDb, pKey, nKey); +} + +int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey){ + return sqlite3_rekey_v2(db, "main", pKey, nKey); +} + +int sqlite3_rekey_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey){ + if(db == NULL || pKey == NULL || nKey == 0){ + return SQLITE_ERROR; + } + int iDb = sqlite3CodecGetDbIndex(db, zDb); + Btree *p = db->aDb[iDb].pBt; + if(p == NULL){ + return SQLITE_OK; + } + int pageCount; + Pgno pgno; + PgHdr *page = NULL; + Pager *pPager = p->pBt->pPager; + CodecContext *ctx = (CodecContext *)(p->pBt->pPager->pCodec); + if(ctx == NULL){ + return SQLITE_OK; + } + sqlite3CodecClearDeriveKey(ctx->writeCtx); + sqlite3CodecClearPassword(ctx->writeCtx); + int rc = sqlite3CodecSetPassword(ctx->writeCtx, pKey, nKey); + if(rc != SQLITE_OK){ + return rc; + } + sqlite3_mutex_enter(db->mutex); + (void)sqlite3BtreeBeginTrans(p, 1, 0); + sqlite3PagerPagecount(pPager, &pageCount); + // support hmac algo changed by using rekey operation + int oldHmacAlgo = ctx->writeCtx->codecConst.hmacAlgo; + if( ctx->writeCtx->codecConst.rekeyHmacAlgo!=ctx->writeCtx->codecConst.hmacAlgo ){ + sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, ctx->writeCtx->codecConst.rekeyHmacAlgo); + sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, ctx->writeCtx->codecConst.rekeyHmacAlgo); + } + + for(pgno = 1; pgno <= (unsigned int)pageCount; pgno++){ + if(PAGER_SJ_PGNO(pPager) != pgno){ + rc = sqlite3PagerGet(pPager, pgno, &page, 0); + if(rc == SQLITE_OK){ + rc = sqlite3PagerWrite(page); + if(rc == SQLITE_OK){ + sqlite3PagerUnref(page); + }else{ + sqlite3_log(SQLITE_WARNING, "sqlite3_rekey_v2: error when writing page %d: errno = %d.", pgno, rc); + } + }else{ + sqlite3_log(SQLITE_WARNING, "sqlite3_rekey_v2: error when reading page %d: errno = %d.", pgno, rc); + } + } + } + if(rc == SQLITE_OK){ + (void)sqlite3BtreeCommit(p); + sqlite3CodecFreeKeyContext(ctx->readCtx); + (void)sqlite3CodecCopyKeyContext(ctx->writeCtx, ctx->readCtx); + }else{ + if( ctx->writeCtx->codecConst.rekeyHmacAlgo!=oldHmacAlgo ){ + sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, oldHmacAlgo); + sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, oldHmacAlgo); + } + (void)sqlite3BtreeRollback(p, SQLITE_ABORT_ROLLBACK, 0); + } + sqlite3_mutex_leave(db->mutex); + + return rc; +} + +void sqlite3_activate_see(const char* zPassPhrase){ + return; +} + +CODEC_STATIC void sqlite3CodecReturnPragmaResult(Parse *parse, const char *label, const char *value){ + Vdbe *v = sqlite3GetVdbe(parse); + sqlite3VdbeSetNumCols(v, 1); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, label, SQLITE_STATIC); + sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, value, 0); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); + return; +} + +// Each configuration setting operation should be done before read/write DB file or there might be some error. +int sqlite3CodecPragma(sqlite3 *db, int iDb, Parse *parse, const char *zLeft, const char *zRight){ + Btree *p = db->aDb[iDb].pBt; + if(p == NULL){ + return 0; + } + CodecContext *ctx = (CodecContext *)(p->pBt->pPager->pCodec); +#ifdef SQLITE_CODEC_ATTACH_CHANGED + CodecParameter *parm = &db->codecParm; + if(sqlite3StrICmp(zLeft, "cipher_default_attach_cipher") == 0 && zRight != NULL){ + (void)sqlite3CodecSetDefaultAttachCipher(parm, zRight); + return 1; + }else if(sqlite3StrICmp(zLeft, "cipher_default_attach_kdf_iter") == 0 && zRight != NULL){ + (void)sqlite3CodecSetDefaultAttachKdfIter(parm, atoi(zRight)); + return 1; + }else if( sqlite3StrICmp(zLeft, "cipher_default_attach_hmac_algo")==0 && zRight!=NULL ){ + /* + ** Make sure to set the Kdf algorithm after setting the Hmac algorithm, or it will not take effect. + ** This behavior is to ensure backward compatible. + */ + if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA1)==0 ){ + sqlite3CodecSetDefaultAttachHmacAlgo(parm, CIPHER_HMAC_ALGORITHM_SHA1); + sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA1); + }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA256)==0 ){ + sqlite3CodecSetDefaultAttachHmacAlgo(parm, CIPHER_HMAC_ALGORITHM_SHA256); + sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA256); + }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA512)==0 ){ + sqlite3CodecSetDefaultAttachHmacAlgo(parm, CIPHER_HMAC_ALGORITHM_SHA512); + sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA512); + }else{ + return 0; + } + return 1; + }else if( sqlite3StrICmp(zLeft, "cipher_default_attach_kdf_algo")==0 && zRight!=NULL ){ + if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA1)==0 ){ + sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA1); + }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA256)==0 ){ + sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA256); + }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA512)==0 ){ + sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA512); + }else{ + return 0; + } + return 1; + }else if( sqlite3StrICmp(zLeft, "cipher_default_attach_page_size")==0 && zRight!=NULL ){ + (void)sqlite3CodecSetDefaultAttachPageSize(parm, atoi(zRight)); + return 1; + } +#endif /* SQLITE_CODEC_ATTACH_CHANGED */ + if(ctx == NULL){ + return 0; + } + if(sqlite3StrICmp(zLeft, "codec_cipher") == 0){ + if(zRight){ + sqlite3_mutex_enter(db->mutex); + (void)sqlite3CodecSetCodecConstant(ctx->readCtx, zRight); + (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, ctx->readCtx->codecConst.hmacAlgo); + (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, ctx->readCtx->codecConst.hmacAlgo); + sqlite3CodecFreeKeyContext(ctx->writeCtx); + (void)sqlite3CodecCopyKeyContext(ctx->readCtx, ctx->writeCtx); + sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); + sqlite3_mutex_leave(db->mutex); + }else{ + sqlite3CodecReturnPragmaResult(parse, "codec_cipher", opensslGetCipherName(ctx->writeCtx->codecConst.cipher)); + } + }else if(sqlite3StrICmp(zLeft, "codec_kdf_iter") == 0){ + if(zRight){ + (void)sqlite3CodecSetIter(ctx->readCtx, atoi(zRight)); + (void)sqlite3CodecSetIter(ctx->writeCtx, atoi(zRight)); + }else{ + char *iter = sqlite3_mprintf("%d", ctx->writeCtx->iter); + if(iter != NULL){ + sqlite3CodecReturnPragmaResult(parse, "codec_kdf_iter", iter); + sqlite3_free(iter); + } + } + }else if( sqlite3StrICmp(zLeft, "codec_hmac_algo")==0 ){ + /* + ** Make sure to set the Kdf algorithm after setting the Hmac algorithm, or it will not take effect. + ** This behavior is to ensure backward compatible. + */ + if(zRight){ + sqlite3_mutex_enter(db->mutex); + if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA1)==0 ){ + (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, CIPHER_HMAC_ALGORITHM_SHA1); + (void)sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, CIPHER_HMAC_ALGORITHM_SHA1); + (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA1); + (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA1); + }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA256)==0 ){ + (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, CIPHER_HMAC_ALGORITHM_SHA256); + (void)sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, CIPHER_HMAC_ALGORITHM_SHA256); + (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA256); + (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA256); + }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA512)==0 ){ + (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, CIPHER_HMAC_ALGORITHM_SHA512); + (void)sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, CIPHER_HMAC_ALGORITHM_SHA512); + (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA512); + (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA512); + }else{ + sqlite3_mutex_leave(db->mutex); + return 0; + } + sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); + sqlite3_mutex_leave(db->mutex); + }else{ + if( ctx->writeCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){ + sqlite3CodecReturnPragmaResult(parse, "codec_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA1); + }else if( ctx->writeCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){ + sqlite3CodecReturnPragmaResult(parse, "codec_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA256); + }else if( ctx->writeCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){ + sqlite3CodecReturnPragmaResult(parse, "codec_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA512); + } + } + }else if( sqlite3StrICmp(zLeft, "codec_kdf_algo")==0 ){ + if(zRight){ + sqlite3_mutex_enter(db->mutex); + if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA1)==0 ){ + (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA1); + (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA1); + }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA256)==0 ){ + (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA256); + (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA256); + }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA512)==0 ){ + (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA512); + (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA512); + }else{ + sqlite3_mutex_leave(db->mutex); + return 0; + } + sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); + sqlite3_mutex_leave(db->mutex); + }else{ + if( ctx->writeCtx->codecConst.kdfAlgo==CIPHER_KDF_ALGORITHM_SHA1 ){ + sqlite3CodecReturnPragmaResult(parse, "codec_kdf_algo", CIPHER_KDF_ALGORITHM_NAME_SHA1); + }else if( ctx->writeCtx->codecConst.kdfAlgo==CIPHER_KDF_ALGORITHM_SHA256 ){ + sqlite3CodecReturnPragmaResult(parse, "codec_kdf_algo", CIPHER_KDF_ALGORITHM_NAME_SHA256); + }else if( ctx->writeCtx->codecConst.kdfAlgo==CIPHER_KDF_ALGORITHM_SHA512 ){ + sqlite3CodecReturnPragmaResult(parse, "codec_kdf_algo", CIPHER_KDF_ALGORITHM_NAME_SHA512); + } + } + }else if( sqlite3StrICmp(zLeft, "codec_page_size")==0 ){ + if(zRight){ + sqlite3_mutex_enter(db->mutex); + int rc = sqlite3CodecSetCipherPageSize(ctx, atoi(zRight)); + if (rc != SQLITE_OK){ + sqlite3_mutex_leave(db->mutex); + return 0; + } + sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); + sqlite3_mutex_leave(db->mutex); + } else { + char *pageSize = sqlite3_mprintf("%d", ctx->readCtx->codecConst.cipherPageSize); + if (pageSize != NULL) { + sqlite3CodecReturnPragmaResult(parse, "codec_page_size", pageSize); + sqlite3_free(pageSize); + } + } + }else if(sqlite3StrICmp(zLeft, "codec_rekey_hmac_algo") == 0){ + if(zRight){ + sqlite3_mutex_enter(db->mutex); + if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA1)==0 ){ + ctx->writeCtx->codecConst.rekeyHmacAlgo = CIPHER_HMAC_ALGORITHM_SHA1; + }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA256)==0 ){ + ctx->writeCtx->codecConst.rekeyHmacAlgo = CIPHER_HMAC_ALGORITHM_SHA256; + }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA512)==0 ){ + ctx->writeCtx->codecConst.rekeyHmacAlgo = CIPHER_HMAC_ALGORITHM_SHA512; + }else{ + sqlite3_mutex_leave(db->mutex); + return 0; + } + sqlite3_mutex_leave(db->mutex); + }else{ + if( ctx->writeCtx->codecConst.rekeyHmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){ + sqlite3CodecReturnPragmaResult(parse, "codec_rekey_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA1); + }else if( ctx->writeCtx->codecConst.rekeyHmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){ + sqlite3CodecReturnPragmaResult(parse, "codec_rekey_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA256); + }else if( ctx->writeCtx->codecConst.rekeyHmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){ + sqlite3CodecReturnPragmaResult(parse, "codec_rekey_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA512); + } + } + }else{ + return 0; + } + return 1; +} + +CODEC_STATIC int sqlite3CodecExportMetadata(sqlite3 *db, const char *dbName, const char *metaName){ + char *sql = sqlite3_mprintf("PRAGMA %s;", metaName); + if(sql == NULL){ + return SQLITE_NOMEM; + } + sqlite3_stmt *statement = NULL; + int rc = sqlite3_prepare_v2(db, sql, -1, &statement, NULL); + sqlite3_free(sql); + if(rc != SQLITE_OK){ + return rc; + } + rc = sqlite3_step(statement); + if(rc != SQLITE_ROW){ + sqlite3_finalize(statement); + return rc; + } + int metadata = sqlite3_column_int(statement, 0); + sqlite3_finalize(statement); + + sql = sqlite3_mprintf("PRAGMA %s.%s=%d;", dbName, metaName, metadata); + if(sql == NULL){ + return SQLITE_NOMEM; + } + rc = sqlite3_exec(db, sql, NULL, NULL, NULL); + sqlite3_free(sql); + return rc; +} + +CODEC_STATIC int sqlite3CodecBatchExportSql(sqlite3 *db, const char *sql, char **errMsg){ + sqlite3_stmt *statement = NULL; + int rc = sqlite3_prepare_v2(db, sql, -1, &statement, NULL); + if(rc != SQLITE_OK){ + return rc; + } + while(sqlite3_step(statement) == SQLITE_ROW){ + rc = sqlite3_exec(db, (char*)sqlite3_column_text(statement, 0), NULL, NULL, errMsg); + if(rc != SQLITE_OK){ + sqlite3_finalize(statement); + return rc; + } + } + sqlite3_finalize(statement); + return rc; +} + +void sqlite3CodecExportData(sqlite3_context *context, int argc, sqlite3_value **argv){ + sqlite3 *db = sqlite3_context_db_handle(context); + const char *dbName = (const char*) sqlite3_value_text(argv[0]); + + int rc = SQLITE_OK; + char *sql = NULL; + char *errMsg = NULL; + + u64 flagsBackup = db->flags; + u32 mDbFlagsBackup = db->mDbFlags; + int nChangeBackup = db->nChange; + int nTotalChangeBackup = db->nTotalChange; + int (*xTraceBackup)(u32,void*,void*,void*) = db->trace.xV2; + + db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; + db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder); + db->mDbFlags |= DBFLAG_PreferBuiltin; + db->trace.xV2 = 0; + + rc = sqlite3CodecExportMetadata(db, dbName, "schema_version"); + if(rc != SQLITE_OK){ + goto export_finish; + } + rc = sqlite3CodecExportMetadata(db, dbName, "user_version"); + if(rc != SQLITE_OK){ + goto export_finish; + } + rc = sqlite3CodecExportMetadata(db, dbName, "application_id"); + if(rc != SQLITE_OK){ + goto export_finish; + } + sql = sqlite3_mprintf("SELECT 'CREATE TABLE %s.' || substr(sql,14) FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence' AND rootpage>0;", dbName); + if(sql == NULL){ + rc = SQLITE_NOMEM; + goto export_finish; + } + rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); + sqlite3_free(sql); + if(rc != SQLITE_OK){ + goto export_finish; + } + sql = sqlite3_mprintf("SELECT 'CREATE INDEX %s.' || substr(sql,14) FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %%';", dbName); + if(sql == NULL){ + rc = SQLITE_NOMEM; + goto export_finish; + } + rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); + sqlite3_free(sql); + if(rc != SQLITE_OK){ + goto export_finish; + } + sql = sqlite3_mprintf("SELECT 'CREATE UNIQUE INDEX %s.' || substr(sql,21) FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%';", dbName); + if(sql == NULL){ + rc = SQLITE_NOMEM; + goto export_finish; + } + rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); + sqlite3_free(sql); + if(rc != SQLITE_OK){ + goto export_finish; + } + sql = sqlite3_mprintf("SELECT 'INSERT INTO %s.' || quote(name) || ' SELECT * FROM main.' || quote(name) || ';' FROM main.sqlite_master WHERE type = 'table' AND name!='sqlite_sequence' AND rootpage>0;", dbName); + if(sql == NULL){ + rc = SQLITE_NOMEM; + goto export_finish; + } + rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); + sqlite3_free(sql); + if(rc != SQLITE_OK){ + goto export_finish; + } + sql = sqlite3_mprintf("SELECT 'DELETE FROM %s.' || quote(name) || ';' FROM %s.sqlite_master WHERE name='sqlite_sequence';", dbName, dbName); + if(sql == NULL){ + rc = SQLITE_NOMEM; + goto export_finish; + } + rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); + sqlite3_free(sql); + if(rc != SQLITE_OK){ + goto export_finish; + } + sql = sqlite3_mprintf("SELECT 'INSERT INTO %s.' || quote(name) || ' SELECT * FROM main.' || quote(name) || ';' FROM %s.sqlite_master WHERE name=='sqlite_sequence';", dbName, dbName); + if(sql == NULL){ + rc = SQLITE_NOMEM; + goto export_finish; + } + rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); + sqlite3_free(sql); + if(rc != SQLITE_OK){ + goto export_finish; + } + sql = sqlite3_mprintf("INSERT INTO %s.sqlite_master SELECT type, name, tbl_name, rootpage, sql FROM main.sqlite_master WHERE type='view' OR type='trigger' OR (type='table' AND rootpage=0);", dbName, dbName); + if(sql == NULL){ + rc = SQLITE_NOMEM; + goto export_finish; + } + rc = sqlite3_exec(db, sql, NULL, NULL, &errMsg); + sqlite3_free(sql); + if(rc != SQLITE_OK){ + goto export_finish; + } +export_finish: + db->flags = flagsBackup; + db->mDbFlags = mDbFlagsBackup; + db->nChange = nChangeBackup; + db->nTotalChange = nTotalChangeBackup; + db->trace.xV2 = xTraceBackup; + if(rc != SQLITE_OK){ + if(errMsg != NULL) { + sqlite3_result_error(context, errMsg, -1); + sqlite3DbFree(db, errMsg); + } else { + sqlite3_result_error(context, sqlite3ErrStr(rc), -1); + } + } + return; +} +/************** End file hw_codec.c *****************************************/ +#endif /* SQLITE_HAS_CODEC */ + + +#ifdef SQLITE_EXPORT_SYMBOLS +/************** Begin hw export the symbols *****************************************/ +#if defined(__GNUC__) +# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) +#elif defined(_MSC_VER) +# define EXPORT_SYMBOLS __declspec(dllexport) +#else +# define EXPORT_SYMBOLS +#endif + +struct sqlite3_api_routines_hw { + int (*initialize)(); + int (*config)(int,...); + int (*key)(sqlite3*,const void*,int); + int (*key_v2)(sqlite3*,const char*,const void*,int); + int (*rekey)(sqlite3*,const void*,int); + int (*rekey_v2)(sqlite3*,const char*,const void*,int); +}; + +typedef struct sqlite3_api_routines_hw sqlite3_api_routines_hw; +static const sqlite3_api_routines_hw sqlite3HwApis = { + sqlite3_initialize, + sqlite3_config, +#ifdef SQLITE_HAS_CODEC + sqlite3_key, + sqlite3_key_v2, + sqlite3_rekey, + sqlite3_rekey_v2 +#else + 0, + 0, + 0, + 0 +#endif /* SQLITE_HAS_CODEC */ +}; + +EXPORT_SYMBOLS const sqlite3_api_routines *sqlite3_export_symbols = &sqlite3Apis; +EXPORT_SYMBOLS const sqlite3_api_routines_hw *sqlite3_export_hw_symbols = &sqlite3HwApis; +/************** End hw export the symbols *****************************************/ +#endif /* SQLITE_EXPORT_SYMBOLS */ -- Gitee From 65a555b62c822dc4825c76c9da28e89234d83765 Mon Sep 17 00:00:00 2001 From: wanghaishuo Date: Fri, 11 Apr 2025 19:47:08 +0800 Subject: [PATCH 3/9] add busy debug Signed-off-by: ryne3366 --- src/sqlite3.c | 375 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 365 insertions(+), 10 deletions(-) diff --git a/src/sqlite3.c b/src/sqlite3.c index a935685..f7bb7d5 100644 --- a/src/sqlite3.c +++ b/src/sqlite3.c @@ -36790,6 +36790,45 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){ #endif /************** End of os_kv.c ***********************************************/ +/************** Define dump function *****************************************/ +#if SQLITE_OS_UNIX +#define DB_LOCK_NUM 3 +#define WAL_LOCK_NUM 9 +// 8 wal lock, 1 SHM_DMS lock, 1 TRX lock +#define MAX_LOCK_NUM (WAL_LOCK_NUM + 1) +#define SHM_DMS_IDX (WAL_LOCK_NUM - 1) +#define TRX_LOCK_IDX WAL_LOCK_NUM +#define LOCK_BY_PROCESS 1 +#define LOCK_BY_THREAD 0 +#define DUMP_BUF_MAX_LEN 180 +#define DUMP_MAX_STR_LEN 21 + +typedef struct LocalLockStatus { + u8 busyLockIdx; + u8 busyLockType; + u8 lockByProcess; + u8 reserved; + u32 lockLen; + u32 busyLine; + int curTid; + u8 lockStatus[MAX_LOCK_NUM]; // last index is trx lock +} LocalLockStatus; +__thread LocalLockStatus g_lockStatus = {0}; + +#define MARK_LAST_BUSY_LINE(rc) {if ((rc)==SQLITE_BUSY || (rc) == SQLITE_LOCKED) g_lockStatus.busyLine = __LINE__;} +static void ResetLockStatus(void); +static void TryRecordTid(int *tidBuf, int ofs, int lockLen); +static void TryClearTid(int *tidBuf, int ofs, int lockLen); +static void MarkLockBusy(u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess); +static void MarkLockStatus(u32 lockIdx, u32 lockLen, u8 lockType); +static void MarkLockStatusByRc(int rc, u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess); +#else +#define MARK_LAST_BUSY_LINE(rc) +#define ResetLockStatus(void) +#define MarkLockBusy(A, B, C, D) +#define MarkLockStatusByRc(A, B, C, D, E) +#endif +/************** End define dump function *************************************/ /************** Begin file os_unix.c *****************************************/ /* ** 2004 May 22 @@ -38564,6 +38603,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ if( pFile->eFileLock>=eFileLock ){ OSTRACE(("LOCK %d %s ok (already held) (unix)\n", pFile->h, azFileLock(eFileLock))); + MarkLockStatus(TRX_LOCK_IDX, 1, eFileLock); return SQLITE_OK; } @@ -38588,6 +38628,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK)) ){ rc = SQLITE_BUSY; + MarkLockBusy(TRX_LOCK_IDX, 1, eFileLock, LOCK_BY_THREAD); goto end_lock; } @@ -38603,6 +38644,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ pFile->eFileLock = SHARED_LOCK; pInode->nShared++; pInode->nLock++; + MarkLockStatus(TRX_LOCK_IDX, 1, eFileLock); goto end_lock; } @@ -38624,11 +38666,11 @@ static int unixLock(sqlite3_file *id, int eFileLock){ if( rc!=SQLITE_BUSY ){ storeLastErrno(pFile, tErrno); } + MarkLockStatusByRc(rc, TRX_LOCK_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS); goto end_lock; } } - /* If control gets to this point, then actually go ahead and make ** operating system calls for the specified lock. */ @@ -38644,7 +38686,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); } - + MarkLockStatusByRc(rc, TRX_LOCK_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS); /* Drop the temporary PENDING lock */ lock.l_start = PENDING_BYTE; lock.l_len = 1L; @@ -38669,6 +38711,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ /* We are trying for an exclusive lock but another thread in this ** same process is still holding a shared lock. */ rc = SQLITE_BUSY; + MarkLockBusy(TRX_LOCK_IDX, 1, eFileLock, LOCK_BY_THREAD); }else{ /* The request was for a RESERVED or EXCLUSIVE lock. It is ** assumed that there is a SHARED or greater lock on the file @@ -38693,6 +38736,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ storeLastErrno(pFile, tErrno); } } + MarkLockStatusByRc(rc, TRX_LOCK_IDX, 1, eFileLock, LOCK_BY_PROCESS); } @@ -38890,7 +38934,6 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ pFile->eFileLock = NO_LOCK; } } - /* Decrement the count of locks against this same file. When the ** count reaches zero, close any other file descriptors whose close ** was deferred because of outstanding locks. @@ -41187,6 +41230,7 @@ struct unixShmNode { int nRef; /* Number of unixShm objects pointing to this */ unixShm *pFirst; /* All unixShm objects pointing to this */ int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */ + int aLockTid[SQLITE_SHM_NLOCK]; #ifdef SQLITE_DEBUG u8 exclMask; /* Mask of exclusive locks held */ u8 sharedMask; /* Mask of shared locks held */ @@ -41429,6 +41473,8 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ rc = SQLITE_READONLY_CANTINIT; }else{ rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1); + MarkLockStatusByRc(rc, SHM_DMS_IDX, 1, EXCLUSIVE_LOCK, LOCK_BY_PROCESS); + MARK_LAST_BUSY_LINE(rc); /* 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 @@ -41440,11 +41486,15 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ } }else if( lock.l_type==F_WRLCK ){ rc = SQLITE_BUSY; + MarkLockStatusByRc(rc, SHM_DMS_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS); + MARK_LAST_BUSY_LINE(rc); } if( rc==SQLITE_OK ){ assert( lock.l_type==F_UNLCK || lock.l_type==F_RDLCK ); rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1); + MarkLockStatusByRc(rc, SHM_DMS_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS); + MARK_LAST_BUSY_LINE(rc); } return rc; } @@ -41829,7 +41879,8 @@ static int unixShmLock( return SQLITE_IOERR_SHMLOCK; } aLock = pShmNode->aLock; - + int *aLockTid = pShmNode->aLockTid; + u8 useProcessLock = LOCK_BY_THREAD; assert( pShmNode==pDbFd->pInode->pShmNode ); assert( pShmNode->pInode==pDbFd->pInode ); assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK ); @@ -41884,15 +41935,17 @@ static int unixShmLock( if( rc==SQLITE_OK ){ memset(&aLock[ofst], 0, sizeof(int)*n); } + useProcessLock = LOCK_BY_PROCESS; }else if( ALWAYS(p->sharedMask & (1<1 ); aLock[ofst]--; } - + MarkLockStatusByRc(rc, ofst, n, NO_LOCK, useProcessLock); /* Undo the local locks */ if( rc==SQLITE_OK ){ p->exclMask &= ~mask; p->sharedMask &= ~mask; + TryClearTid(aLockTid, ofst, n); } } }else if( flags & SQLITE_SHM_SHARED ){ @@ -41903,12 +41956,14 @@ static int unixShmLock( rc = SQLITE_BUSY; }else if( aLock[ofst]==0 ){ rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n); + useProcessLock = LOCK_BY_PROCESS; } - + MarkLockStatusByRc(rc, ofst, n, SHARED_LOCK, useProcessLock); /* Get the local shared locks */ if( rc==SQLITE_OK ){ p->sharedMask |= mask; aLock[ofst]++; + TryRecordTid(aLockTid, ofst, n); } } }else{ @@ -41927,14 +41982,17 @@ static int unixShmLock( ** also update the in-memory values. */ if( rc==SQLITE_OK ){ rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n); + useProcessLock = LOCK_BY_PROCESS; if( rc==SQLITE_OK ){ assert( (p->sharedMask & mask)==0 ); p->exclMask |= mask; for(ii=ofst; iipShmMutex); @@ -59933,6 +59991,7 @@ static int syncJournal(Pager *pPager, int newHdr){ assert( !pagerUseWal(pPager) ); rc = sqlite3PagerExclusiveLock(pPager); + MARK_LAST_BUSY_LINE(rc); if( rc!=SQLITE_OK ) return rc; if( !pPager->noSync ){ @@ -60840,6 +60899,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){ sqlite3OsDelete(pVfs, pPager->zJournal, 0); if( !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK); } + MARK_LAST_BUSY_LINE(rc); sqlite3EndBenignMalloc(); }else{ /* The journal file exists and no other connection has a reserved @@ -60929,6 +60989,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ assert( pPager->tempFile==0 || pPager->eLock==EXCLUSIVE_LOCK ); rc = pager_wait_on_lock(pPager, SHARED_LOCK); + MARK_LAST_BUSY_LINE(rc); if( rc!=SQLITE_OK ){ assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK ); goto failed; @@ -60965,6 +61026,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ ** downgraded to SHARED_LOCK before this function returns. */ rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); + MARK_LAST_BUSY_LINE(rc); if( rc!=SQLITE_OK ){ goto failed; } @@ -61579,6 +61641,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory */ if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){ rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); + MARK_LAST_BUSY_LINE(rc); if( rc!=SQLITE_OK ){ return rc; } @@ -61591,6 +61654,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory ** holds the write-lock. If possible, the upper layer will call it. */ rc = sqlite3WalBeginWriteTransaction(pPager->pWal); + MARK_LAST_BUSY_LINE(rc); }else{ /* Obtain a RESERVED lock on the database file. If the exFlag parameter ** is true, then immediately upgrade this to an EXCLUSIVE lock. The @@ -61598,8 +61662,10 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory ** lock, but not when obtaining the RESERVED lock. */ rc = pagerLockDb(pPager, RESERVED_LOCK); + MARK_LAST_BUSY_LINE(rc); if( rc==SQLITE_OK && exFlag ){ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); + MARK_LAST_BUSY_LINE(rc); } } @@ -63100,6 +63166,7 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ if( pPager->eState==PAGER_READER ){ assert( rc==SQLITE_OK ); rc = pagerLockDb(pPager, RESERVED_LOCK); + MARK_LAST_BUSY_LINE(rc); } if( rc==SQLITE_OK ){ sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); @@ -63264,6 +63331,7 @@ static int pagerOpenWal(Pager *pPager){ */ if( pPager->exclusiveMode ){ rc = pagerExclusiveLock(pPager); + MARK_LAST_BUSY_LINE(rc); } /* Open the connection to the log file. If this operation fails, @@ -63347,6 +63415,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){ if( !pPager->pWal ){ int logexists = 0; rc = pagerLockDb(pPager, SHARED_LOCK); + MARK_LAST_BUSY_LINE(rc); if( rc==SQLITE_OK ){ rc = sqlite3OsAccess( pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &logexists @@ -63362,6 +63431,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){ */ if( rc==SQLITE_OK && pPager->pWal ){ rc = pagerExclusiveLock(pPager); + MARK_LAST_BUSY_LINE(rc); if( rc==SQLITE_OK ){ rc = sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize, (u8*)pPager->pTmpSpace); @@ -64736,6 +64806,7 @@ static int walIndexRecover(Wal *pWal){ iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock; rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock); if( rc ){ + MARK_LAST_BUSY_LINE(rc); return rc; } @@ -65576,6 +65647,7 @@ static int walCheckpoint( if( mxSafeFrame>y ){ assert( y<=pWal->hdr.mxFrame ); rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1); + MARK_LAST_BUSY_LINE(rc); if( rc==SQLITE_OK ){ u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED); AtomicStore(pInfo->aReadMark+i, iMark); @@ -65670,8 +65742,9 @@ static int walCheckpoint( /* Release the reader lock held while backfilling */ walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1); + } else { + MARK_LAST_BUSY_LINE(rc); } - if( rc==SQLITE_BUSY ){ /* Reset the return code so as not to report a checkpoint failure ** just because there are active readers. */ @@ -65688,11 +65761,13 @@ static int walCheckpoint( assert( pWal->writeLock ); if( pInfo->nBackfillhdr.mxFrame ){ rc = SQLITE_BUSY; + MARK_LAST_BUSY_LINE(rc); }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){ u32 salt1; sqlite3_randomness(4, &salt1); assert( pInfo->nBackfill==pWal->hdr.mxFrame ); rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1); + MARK_LAST_BUSY_LINE(rc); if( rc==SQLITE_OK ){ if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){ /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as @@ -65790,6 +65865,8 @@ SQLITE_PRIVATE int sqlite3WalClose( walLimitSize(pWal, 0); } } + } else { + MARK_LAST_BUSY_LINE(rc); } walIndexClose(pWal, isDelete); @@ -65944,6 +66021,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ walUnlockShared(pWal, WAL_WRITE_LOCK); rc = SQLITE_READONLY_RECOVERY; } + MARK_LAST_BUSY_LINE(rc); }else{ int bWriteLock = pWal->writeLock; if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){ @@ -65964,6 +66042,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); } } + MARK_LAST_BUSY_LINE(rc); } } @@ -65983,6 +66062,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ ** writer truncated the WAL out from under it. If that happens, it ** indicates that a writer has fixed the SHM file for us, so retry */ if( rc==SQLITE_IOERR_SHORT_READ ) rc = WAL_RETRY; + MARK_LAST_BUSY_LINE(rc); } pWal->exclusiveMode = WAL_NORMAL_MODE; } @@ -66214,6 +66294,7 @@ 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 void DumpLocksByWal(Wal *pWal); static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */ u32 mxReadMark; /* Largest aReadMark[] value */ @@ -66251,6 +66332,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ return SQLITE_PROTOCOL; } if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39; +#if SQLITE_OS_UNIX + if( cnt>=15 ) DumpLocksByWal(pWal); +#endif /* SQLITE_OS_UNIX */ sqlite3OsSleep(pWal->pVfs, nDelay); } @@ -66277,11 +66361,14 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** must be zeroed before the requested page is returned. */ rc = WAL_RETRY; + MARK_LAST_BUSY_LINE(SQLITE_BUSY); }else if( SQLITE_OK==(rc = walLockShared(pWal, WAL_RECOVER_LOCK)) ){ walUnlockShared(pWal, WAL_RECOVER_LOCK); rc = WAL_RETRY; + MARK_LAST_BUSY_LINE(SQLITE_BUSY); }else if( rc==SQLITE_BUSY ){ rc = SQLITE_BUSY_RECOVERY; + MARK_LAST_BUSY_LINE(SQLITE_BUSY); } } if( rc!=SQLITE_OK ){ @@ -66304,6 +66391,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** and can be safely ignored. */ rc = walLockShared(pWal, WAL_READ_LOCK(0)); + MARK_LAST_BUSY_LINE(SQLITE_BUSY); walShmBarrier(pWal); if( rc==SQLITE_OK ){ if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){ @@ -66321,6 +66409,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** it finished. Leaving a corrupt image in the database file. */ walUnlockShared(pWal, WAL_READ_LOCK(0)); + MARK_LAST_BUSY_LINE(SQLITE_BUSY); return WAL_RETRY; } pWal->readLock = 0; @@ -66365,6 +66454,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ }else if( rc!=SQLITE_BUSY ){ return rc; } + MARK_LAST_BUSY_LINE(rc); } } if( mxI==0 ){ @@ -66374,6 +66464,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ rc = walLockShared(pWal, WAL_READ_LOCK(mxI)); if( rc ){ + MARK_LAST_BUSY_LINE(rc); return rc==SQLITE_BUSY ? WAL_RETRY : rc; } /* Now that the read-lock has been obtained, check that neither the @@ -66416,6 +66507,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){ walUnlockShared(pWal, WAL_READ_LOCK(mxI)); + MARK_LAST_BUSY_LINE(rc); return WAL_RETRY; }else{ assert( mxReadMark<=pWal->hdr.mxFrame ); @@ -66542,6 +66634,7 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ (void)walEnableBlocking(pWal); rc = walLockShared(pWal, WAL_CKPT_LOCK); walDisableBlocking(pWal); + MARK_LAST_BUSY_LINE(rc); if( rc!=SQLITE_OK ){ return rc; @@ -67365,6 +67458,7 @@ static sqlite3_int64 g_lastCkptTime = 0; ** If parameter xBusy is not NULL, it is a pointer to a busy-handler ** callback. In this case this function runs a blocking checkpoint. */ +static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime); SQLITE_PRIVATE int sqlite3WalCheckpoint( Wal *pWal, /* Wal connection */ sqlite3 *db, /* Check this handle's interrupt flag */ @@ -67406,6 +67500,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( ** it will not be invoked in this case. */ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); + MARK_LAST_BUSY_LINE(rc); testcase( rc==SQLITE_BUSY ); testcase( rc!=SQLITE_OK && xBusy2!=0 ); if( rc==SQLITE_OK ){ @@ -67422,6 +67517,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( */ if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){ rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1); + MARK_LAST_BUSY_LINE(rc); if( rc==SQLITE_OK ){ pWal->writeLock = 1; }else if( rc==SQLITE_BUSY ){ @@ -67449,7 +67545,12 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ rc = SQLITE_CORRUPT_BKPT; }else{ + sqlite3_int64 startTime; + sqlite3OsCurrentTimeInt64(db->pVfs, &startTime); rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf); + if (rc == SQLITE_OK){ + walLogCheckpointInfo(pWal, db, startTime); + } } /* If no error occurred, set the output variables. */ @@ -71166,6 +71267,7 @@ static void pageReinit(DbPage *pData){ } } +static void DumpLocksByPager(Pager *pPager); /* ** Invoke the busy handler for a btree. */ @@ -71173,7 +71275,13 @@ static int btreeInvokeBusyHandler(void *pArg){ BtShared *pBt = (BtShared*)pArg; assert( pBt->db ); assert( sqlite3_mutex_held(pBt->db->mutex) ); - return sqlite3InvokeBusyHandler(&pBt->db->busyHandler); + int rc = sqlite3InvokeBusyHandler(&pBt->db->busyHandler); +#if SQLITE_OS_UNIX + if (rc == 0) { + DumpLocksByPager(pBt->pPager); + } +#endif /* SQLITE_OS_UNIX */ + return rc; } /* @@ -71601,7 +71709,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){ } } #endif - + ResetLockStatus(); /* Rollback any active transaction and free the handle structure. ** The call to sqlite3BtreeRollback() drops any table-locks held by ** this handle. @@ -79629,8 +79737,10 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int * if( p ){ BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); + ResetLockStatus(); if( pBt->inTransaction!=TRANS_NONE ){ rc = SQLITE_LOCKED; + MARK_LAST_BUSY_LINE(rc); }else{ rc = sqlite3PagerCheckpoint(pBt->pPager, p->db, eMode, pnLog, pnCkpt); } @@ -85479,6 +85589,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ nTrans++; } rc = sqlite3PagerExclusiveLock(pPager); + MARK_LAST_BUSY_LINE(rc); sqlite3BtreeLeave(pBt); } } @@ -246354,9 +246465,253 @@ export_finish: return; } /************** End file hw_codec.c *****************************************/ -#endif /* SQLITE_HAS_CODEC */ +#endif +#if SQLITE_OS_UNIX +#include +#include +static inline int OsGetTid(void) +{ +#if defined(__linux__) + return (int)syscall(__NR_gettid); +#elif defined(__APPLE__) + return (int)syscall(SYS_thread_selfid); +#else + return 0; +#endif +} +static void ResetLockStatus(void) +{ + (void)memset(&g_lockStatus, 0, sizeof(g_lockStatus)); + g_lockStatus.curTid = OsGetTid(); +} +/* +** Record lock info, correspond wal aLock buf, 1 aLock: 1 +*/ +static inline void TryRecordTid(int *tidBuf, int ofs, int lockLen) +{ + int lockOfs = ofs + lockLen; + for (int i = ofs; i < lockOfs; i++) { + if (tidBuf[i] == 0) { + tidBuf[i] = g_lockStatus.curTid; + } + } +} +/* +** Clear locks info. +*/ +static inline void TryClearTid(int *tidBuf, int ofs, int lockLen) +{ + int lockOfs = ofs + lockLen; + for (int i = ofs; i < lockOfs; i++) { + if (tidBuf[i] == g_lockStatus.curTid) { + tidBuf[i] = 0; + } + } +} + +static inline void MarkLockBusy(u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess) +{ + g_lockStatus.busyLockIdx = lockIdx; + g_lockStatus.busyLockType = lockType; + g_lockStatus.lockByProcess = lockByProcess; + g_lockStatus.lockLen = lockLen; +} + +static void MarkLockStatus(u32 lockIdx, u32 lockLen, u8 lockType) +{ + if (lockLen == 0 || (lockIdx + lockLen) > MAX_LOCK_NUM) { + sqlite3_log(SQLITE_ERROR, "Unexpect lock index %u lockLen %d!", lockIdx, lockLen); + return; + } + // only busy error code need record + if (g_lockStatus.lockLen != 0 && lockIdx == g_lockStatus.busyLockIdx) { + g_lockStatus.busyLockIdx = 0; + g_lockStatus.busyLockType = NO_LOCK; + g_lockStatus.lockLen = 0; + } + if (lockLen == 1) { + g_lockStatus.lockStatus[lockIdx] = lockType; + } else { + size_t len = sizeof(u8) * lockLen; + (void)memset(&g_lockStatus.lockStatus[lockIdx], lockType, len); + } +} + +static inline void MarkLockStatusByRc(int rc, u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess) +{ + if (rc == SQLITE_OK) { + MarkLockStatus(lockIdx, lockLen, lockType); + } else if (rc == SQLITE_BUSY) { + MarkLockBusy(lockIdx, lockLen, lockType, lockByProcess); + } +} + +static inline const char *IdxToLockName(u32 idx) +{ + const char *lockName[MAX_LOCK_NUM] = {"write", "ckpt", "recover", "read0", + "read1", "read2", "read3", "read4", "wal_dms", "trxLock"}; + return (idx < MAX_LOCK_NUM) ? lockName[idx] : "errLock"; +} + +static void DumpHandleLock(char *dumpBuf, int dumpBufLen) +{ + char *tmp = dumpBuf; + u8 *lockStatus = g_lockStatus.lockStatus; + int availLen = dumpBufLen - 1; + dumpBuf[availLen] = '\0'; + for (int i = 0; i < MAX_LOCK_NUM && availLen > DUMP_MAX_STR_LEN; i++) { + if (lockStatus[i] != NO_LOCK) { + tmp[0] = '\0'; + sqlite3_snprintf(availLen, tmp, "<%s, %d>", IdxToLockName((u32)i), lockStatus[i]); + int len = strlen(tmp); + tmp += len; + availLen -= len; + } + } + sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]BusyLine:%d, idx:%d, type:%d, fileLock:%d, len:%d, handleLocks:%s", + g_lockStatus.busyLine, g_lockStatus.busyLockIdx, g_lockStatus.busyLockType, g_lockStatus.lockByProcess, + g_lockStatus.lockLen, tmp != dumpBuf ? dumpBuf : "none"); +} + +static inline const char *FlockToName(int l_type) +{ + return l_type == F_RDLCK ? "F_RDLCK" : + l_type == F_WRLCK ? "F_WRLCK" : + l_type == F_UNLCK ? "F_UNLCK" : "F_UNKNOWN"; +} + +static int DumpProcessLocks(int fd, struct flock *lock, const char *lockName, char *dumpBuf, int bufLen) +{ + dumpBuf[0] = '\0'; + if (osFcntl(fd, F_GETLK, lock) != SQLITE_OK) { + sqlite3_log(SQLITE_ERROR, "[SQLite]Get wal file lock ofs %u failed, errno: %d", lock->l_start, errno); + return 0; + } + if (lock->l_type != F_UNLCK) { + sqlite3_snprintf(bufLen, dumpBuf, "<%s, pid:%u, %s>", lockName, lock->l_pid, FlockToName(lock->l_type)); + return strlen(dumpBuf); + } + return 0; +} + +static void DumpTrxProcessLocks(unixFile *file, char *dumpBuf, int dumpBufLen) +{ + unixInodeInfo *inode = file->pInode; + if (inode == NULL) { + sqlite3_log(SQLITE_ERROR, "[SQLite]Inode is null!"); + return; + } + sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]acqLock:%d, dbRef:%d, lockCnt:%d, curLock:%d, processLock:%d", + file->eFileLock, inode->nRef, inode->nLock, inode->eFileLock, inode->bProcessLock); + const char *lockName[DB_LOCK_NUM] = {"pending", "reserved", "shared_first"}; + char *tmp = dumpBuf; + int availLen = dumpBufLen - 1; + dumpBuf[availLen] = '\0'; + for (int i = 0; i < DB_LOCK_NUM && availLen > DUMP_MAX_STR_LEN; i++) { + off_t ofs = i + PENDING_BYTE; + off_t lockLen = (ofs == SHARED_FIRST) ? SHARED_SIZE : 1; + struct flock lock = {.l_type = F_WRLCK, .l_start = ofs, .l_len = lockLen, .l_whence = SEEK_SET}; + int lockBufLen = DumpProcessLocks(file->h, &lock, lockName[i], tmp, availLen); + tmp += lockBufLen; + availLen -= lockBufLen; + } + if (tmp != dumpBuf) { + sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]Trx locks: %s", dumpBuf); + } +} + +static void DumpWalLocks(unixFile *file, u8 walEnabled, char *dumpBuf, int dumpBufLen) +{ + if (file->pShm == NULL || file->pShm->pShmNode == NULL) { + sqlite3_log(SQLITE_ERROR, "[SQLite]Wal mode disabled! pShm or pShmNode is NULL"); + return; + } + if (!walEnabled) { + sqlite3_log(SQLITE_ERROR, "[SQLite] walEnabled false"); + } + unixShmNode *pShmNode = file->pShm->pShmNode; + char *tmp = dumpBuf; + int availLen = dumpBufLen - 1; + dumpBuf[availLen] = '\0'; + for (int i = 0; i < WAL_LOCK_NUM && availLen > DUMP_MAX_STR_LEN; i++) { + if (i < SQLITE_SHM_NLOCK && pShmNode->aLock[i]) { + tmp[0] = '\0'; + sqlite3_snprintf(availLen, tmp, "<%s, %d, tid:%d>", IdxToLockName((u32)i), pShmNode->aLock[i], + pShmNode->aLockTid[i]); + int strLen = strlen(tmp); + tmp += strLen; + availLen -= strLen; + } + off_t ofs = i + WALINDEX_LOCK_OFFSET; + struct flock lock = {.l_type = F_WRLCK, .l_start = ofs, .l_len = 1, .l_whence = SEEK_SET}; + int bufLen = DumpProcessLocks(pShmNode->hShm, &lock, IdxToLockName((u32)i), tmp, availLen); + tmp += bufLen; + availLen -= bufLen; + } + if (tmp != dumpBuf) { + sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]Wal locks: %s", dumpBuf); + } +} + +static void DumpLocksInfo(unixFile *file, int walEnabled) +{ + char *dumpBuf = sqlite3Malloc(DUMP_BUF_MAX_LEN); + if (dumpBuf == NULL) { + sqlite3_log(SQLITE_ERROR, "[SQLite]Can't alloc bufferSz %d for dump!", DUMP_BUF_MAX_LEN); + return; + } + DumpHandleLock(dumpBuf, DUMP_BUF_MAX_LEN); + DumpTrxProcessLocks(file, dumpBuf, DUMP_BUF_MAX_LEN); + DumpWalLocks(file, walEnabled, dumpBuf, DUMP_BUF_MAX_LEN); + sqlite3_free(dumpBuf); +} + +#ifndef SQLITE_OMIT_WAL +static void DumpLocksByWal(Wal *pWal) +{ + if (pWal == NULL) { + sqlite3_log(SQLITE_ERROR, "Wal ptr is NULL!"); + return; + } + if (pWal->pVfs == NULL || sqlite3_stricmp(pWal->pVfs->zName, "unix") != 0) { + return; + } + DumpLocksInfo((unixFile *)(pWal->pDbFd), 1); +} +#endif /* #ifndef SQLITE_OMIT_WAL */ + +static void DumpLocksByPager(Pager *pPager) +{ + if (pPager == NULL) { + sqlite3_log(SQLITE_ERROR, "Pager ptr is NULL!"); + return; + } + if (pPager->pVfs == NULL || sqlite3_stricmp(pPager->pVfs->zName, "unix") != 0) { + return; + } +#ifndef SQLITE_OMIT_WAL + DumpLocksInfo((unixFile *)(pPager->fd), pPager->pWal != NULL); +#else /* #ifndef SQLITE_OMIT_WAL */ + DumpLocksInfo((unixFile *)(pPager->fd), 0); +#endif /* #ifndef SQLITE_OMIT_WAL */ +} +#endif /* SQLITE_OS_UNIX */ + +#ifndef SQLITE_OMIT_WAL +static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime) { + sqlite3_int64 endTime; + sqlite3OsCurrentTimeInt64(db->pVfs, &endTime); + sqlite3_int64 timeUse = endTime - startTime; + /* Only when timeUse > 1500ms or wal size > 50MB, default pageSize 4K, 50*1024/4 = 12800 */ + if (timeUse > 1500 || pWal->hdr.mxFrame > 12800) { + sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]Wal ckpt use time: %lld(ms), wal frame: %u", + timeUse, pWal->hdr.mxFrame); + } +} +#endif +// hw export the symbols #ifdef SQLITE_EXPORT_SYMBOLS /************** Begin hw export the symbols *****************************************/ #if defined(__GNUC__) -- Gitee From 528a2badfd4a5e1a79e1359436f628b0821df231 Mon Sep 17 00:00:00 2001 From: wanghaishuo Date: Sat, 12 Apr 2025 09:26:04 +0800 Subject: [PATCH 4/9] add meta dwr Signed-off-by: ryne3366 --- src/sqlite3.c | 1148 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 1136 insertions(+), 12 deletions(-) diff --git a/src/sqlite3.c b/src/sqlite3.c index f7bb7d5..71f902b 100644 --- a/src/sqlite3.c +++ b/src/sqlite3.c @@ -779,6 +779,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ #define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ #define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ +#define SQLITE_META_RECOVERED 66 /* meta page recovered*/ /* end-of-error-codes */ /* @@ -14964,7 +14965,6 @@ typedef int VList; # define SQLITE_OS_UNIX 0 #endif - #endif /* SQLITE_OS_SETUP_H */ /************** End of os_setup.h ********************************************/ @@ -56138,6 +56138,26 @@ struct PagerSavepoint { #endif }; +#if !defined(SQLITE_OS_UNIX) && defined(SQLITE_META_DWR) +#undef SQLITE_META_DWR +#endif + +#ifdef SQLITE_META_DWR +static int PragmaMetaDoubleWrie(sqlite3 *db, int iDb, Parse *parse, const char *zLeft, const char *zRight); +typedef struct MetaDwrHdr MetaDwrHdr; +static int MetaDwrWriteHeader(Pager *pPager, MetaDwrHdr *hdr); +static int MetaDwrUpdateMetaPages(Btree *pBt); +static void MetaDwrPagerRelease(Pager *pPager); +static int MetaDwrOpenFile(Pager *pPager, u8 openCreate); +static void MetaDwrCheckVacuum(BtShared *pBt); +static int MetaDwrRecoverAndBeginTran(Btree *pBt, int wrflag, int *pSchemaVersion); +static int MetaDwrOpenAndCheck(Btree *pBt); +static void MetaDwrDisable(Btree *pBt); +#define META_HEADER_CHANGED 1 +#define META_SCHEMA_CHANGED 2 +#define META_IN_RECOVERY 1 +#define META_RECOVER_SUCCESS 2 +#endif /* ** Bits of the Pager.doNotSpill flag. See further description below. */ @@ -56403,6 +56423,13 @@ struct Pager { Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */ char *zWal; /* File name for write-ahead log */ #endif +#ifdef SQLITE_META_DWR + u8 metaChanged; + sqlite3_file *metaFd; + MetaDwrHdr *metaHdr; + void *metaMapPage; + int (*xGetMethod)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */ +#endif }; /* @@ -56762,7 +56789,11 @@ static void setGetterMethod(Pager *pPager){ pPager->xGet = getPageMMap; #endif /* SQLITE_MAX_MMAP_SIZE>0 */ }else{ +#ifdef SQLITE_META_DWR + pPager->xGet = pPager->xGetMethod ? pPager->xGetMethod : getPageNormal; +#else pPager->xGet = getPageNormal; +#endif } } @@ -57813,7 +57844,14 @@ static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){ } sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize); } - +#ifdef SQLITE_META_DWR + if (bCommit && pPager->metaChanged != 0) { + sqlite3BeginBenignMalloc(); + (void)MetaDwrWriteHeader(pPager, pPager->metaHdr); + sqlite3EndBenignMalloc(); + pPager->metaChanged = 0; + } +#endif if( pagerUseWal(pPager) ){ /* Drop the WAL write-lock, if any. Also, if the connection was in ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE @@ -59890,6 +59928,9 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,a); pPager->pWal = 0; } +#endif +#ifdef SQLITE_META_DWR + MetaDwrPagerRelease(pPager); #endif pager_reset(pPager); if( MEMDB ){ @@ -60736,7 +60777,11 @@ act_like_temp_file: rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb, !memDb?pagerStress:0, (void *)pPager, pPager->pPCache); } - +#ifdef SQLITE_META_DWR + if( rc==SQLITE_OK && !memDb && !readOnly){ + (void)MetaDwrOpenFile(pPager, 0); + } +#endif /* If an error occurred above, free the Pager structure and close the file. */ if( rc!=SQLITE_OK ){ @@ -61168,7 +61213,6 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ if( pPager->tempFile==0 && pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){ rc = pagerPagecount(pPager, &pPager->dbSize); } - failed: if( rc!=SQLITE_OK ){ assert( !MEMDB ); @@ -62436,7 +62480,6 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){ pPager->eState = PAGER_READER; return SQLITE_OK; } - PAGERTRACE(("COMMIT %d\n", PAGERID(pPager))); rc = pager_end_transaction(pPager, pPager->setSuper, 1); return pager_error(pPager, rc); @@ -68267,6 +68310,10 @@ struct BtShared { #endif u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ int nPreformatSize; /* Size of last cell written by TransferRow() */ +#ifdef SQLITE_META_DWR + u32 maxMetaPage; + u32 metaRecoverStatus; +#endif }; /* @@ -71563,8 +71610,8 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( } } #endif - *ppBtree = p; + *ppBtree = p; btree_open_out: if( rc!=SQLITE_OK ){ if( pBt && pBt->pPager ){ @@ -72529,7 +72576,12 @@ trans_begun: rc = sqlite3PagerOpenSavepoint(pPager, p->db->nSavepoint); } } - +#ifdef SQLITE_META_DWR + if (rc == SQLITE_NOTADB || rc == SQLITE_CORRUPT) { + int rc1 = MetaDwrRecoverAndBeginTran(p, wrflag, pSchemaVersion); + rc = (rc1 == SQLITE_OK) ? SQLITE_OK : rc; + } +#endif btreeIntegrity(p); sqlite3BtreeLeave(p); return rc; @@ -72896,6 +72948,9 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){ if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); put4byte(&pBt->pPage1->aData[28], pBt->nPage); +#ifdef SQLITE_META_DWR + MetaDwrCheckVacuum(pBt); +#endif } }else{ rc = SQLITE_DONE; @@ -72980,6 +73035,9 @@ static int autoVacuumCommit(Btree *p){ put4byte(&pBt->pPage1->aData[28], nFin); pBt->bDoTruncate = 1; pBt->nPage = nFin; +#ifdef SQLITE_META_DWR + MetaDwrCheckVacuum(pBt); +#endif } if( rc!=SQLITE_OK ){ sqlite3PagerRollback(pPager); @@ -73036,6 +73094,9 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){ if( pBt->bDoTruncate ){ sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage); } +#endif +#ifdef SQLITE_META_DWR + (void)MetaDwrUpdateMetaPages(p); #endif rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zSuperJrnl, 0); sqlite3BtreeLeave(p); @@ -78937,6 +78998,11 @@ SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ assert( iMeta==0 || iMeta==1 ); pBt->incrVacuum = (u8)iMeta; } +#endif +#ifdef SQLITE_META_DWR + if (idx == 1 && pBt->pPager->metaFd) { + pBt->pPager->metaChanged = META_SCHEMA_CHANGED; + } #endif } sqlite3BtreeLeave(p); @@ -79307,7 +79373,6 @@ static int checkTreePage( "unable to get the page. error code=%d", rc); goto end_of_check; } - /* Clear MemPage.isInit to make sure the corruption detection code in ** btreeInitPage() is executed. */ savedIsInit = pPage->isInit; @@ -80514,6 +80579,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ } } } + if( rc==SQLITE_OK ){ rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1); } @@ -80546,7 +80612,12 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ sqlite3PagerTruncateImage(pDestPager, nDestTruncate); rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0); } - + #ifdef SQLITE_META_DWR + if (rc == SQLITE_OK && p->pDest->pBt->pPager->metaFd) { + p->pDest->pBt->pPager->metaChanged = META_SCHEMA_CHANGED; + (void)MetaDwrUpdateMetaPages(p->pDest); + } + #endif /* Finish committing the transaction to the destination database. */ if( SQLITE_OK==rc && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0)) @@ -134955,8 +135026,14 @@ SQLITE_PRIVATE void sqlite3Pragma( /* sqlite3CodecPragma executes internal */ goto pragma_out; } -#endif /* SQLITE_HAS_CODEC */ - +#endif +/* END CODEC */ +#ifdef SQLITE_META_DWR + if(PragmaMetaDoubleWrie(db, iDb, pParse, zLeft, zRight)) { + /* PragmaMetaDoubleWrie executes internal */ + goto pragma_out; + } +#endif /* Locate the pragma in the lookup table */ pPragma = pragmaLocate(zLeft); if( pPragma==0 ){ @@ -149391,7 +149468,6 @@ static void updateVirtualTable( } } - if( eOnePass==ONEPASS_OFF ){ /* End the virtual table scan */ if( pSrc->nSrc==1 ){ @@ -175302,6 +175378,10 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){ zErr = "no more rows available"; break; } + case SQLITE_META_RECOVERED: { + zErr = "warning meta recover message"; + break; + } default: { rc &= 0xff; if( ALWAYS(rc>=0) && rccheckFileId) { + unixFile *fd = (unixFile *)pPager->fd; + if (fd == NULL || fd->pInode == NULL || pPager->pVfs == NULL) { + return SQLITE_INTERNAL; + } + if (fd->pInode->fileId.ino != hdr->dbFileInode) { + sqlite3_log(SQLITE_IOERR_DATA, "Ino mismatch file %llu dwr file %llu", + fd->pInode->fileId.ino, hdr->dbFileInode); + return SQLITE_IOERR_DATA; + } + } +#endif + if (hdr->pageCnt > META_DWR_MAX_PAGES || hdr->version != META_DWR_VERSION || + hdr->magic != META_DWR_MAGIC || hdr->checkSum != META_DWR_MAGIC) { + sqlite3_log(SQLITE_IOERR_DATA, "Meta dwr file check wrong pageCnt %u, version %u, magic %u, checkSum %u", + hdr->pageCnt, hdr->version, hdr->magic, hdr->checkSum); + return SQLITE_IOERR_DATA; + } + if (hdr->pageSz != pPager->pageSize) { + sqlite3_log(SQLITE_IOERR_DATA, "Meta dwr file check wrong pageSz %u-%u", hdr->pageSz, pPager->pageSize); + return SQLITE_IOERR_DATA; + } + return SQLITE_OK; +} + +static int PragmaMetaDoubleWrie(sqlite3 *db, int iDb, Parse *parse, const char *zLeft, const char *zRight) { + Btree *pBt = db->aDb[iDb].pBt; + if (pBt == NULL || zLeft == NULL || sqlite3StrICmp(zLeft, "meta_double_write") != 0) { + return 0; + } + Pager *pPager = pBt->pBt->pPager; + if (pPager == NULL) { + sqlite3_log(SQLITE_WARNING_DUMP, "Invalid pager handle"); + return 1; + } + if (zRight == NULL) { + Vdbe *v = sqlite3GetVdbe(parse); + sqlite3VdbeSetNumCols(v, 1); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "meta_double_write", SQLITE_STATIC); + sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, pPager->metaFd ? "enabled" : "disabled", 0); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); + } else if (strncmp(zRight, "enabled", 7) == 0) { + sqlite3_mutex_enter(db->mutex); + // only support enabled meta double write + int rc = MetaDwrOpenAndCheck(pBt); + if (rc != SQLITE_OK) { + parse->nErr++; + parse->rc = rc; + } + sqlite3_mutex_leave(db->mutex); + } else if (strncmp(zRight, "disabled", 8) == 0) { + sqlite3_mutex_enter(db->mutex); + MetaDwrDisable(pBt); + sqlite3_mutex_leave(db->mutex); + } + return 1; +} + +static int GetBtreePageNo(MemPage *pPage, void *args) { + ScanPages *pInfo = (ScanPages *)args; + // realloc buffer to store pages + u32 pageCnt = pInfo->pageCnt; + if (pageCnt == pInfo->pageBufSize) { + u32 memSz = sizeof(Pgno) * ROUND8(pageCnt + 1); + Pgno *pages = sqlite3Malloc(memSz); + if (pages == NULL) { + sqlite3_log(SQLITE_NOMEM, "GetPages alloc buffer go wrong %u", memSz); + return SQLITE_NOMEM; + } + if (pageCnt != 0) { + memcpy(pages, pInfo->pages, pageCnt * sizeof(Pgno)); + } + sqlite3_free(pInfo->pages); + pInfo->pageBufSize = ROUND8(pageCnt + 1); + pInfo->pages = pages; + } + pInfo->pages[pageCnt] = pPage->pgno; + pInfo->pageCnt++; + if (pInfo->maxPageNo < pPage->pgno) { + pInfo->maxPageNo = pPage->pgno; + } + return 0; +} + +typedef int (*ScanFn)(MemPage *pPage, void *args); +static SQLITE_NOINLINE int ScanOverflowPages( + MemPage *pPage, /* The page that contains the Cell */ + unsigned char *pCell, /* First byte of the Cell */ + CellInfo *pInfo, /* Size information about the cell */ + ScanFn fn, /* Scan pages function */ + void *args) { + BtShared *pBt; + Pgno ovflPgno; + int rc; + int nOvfl; + u32 ovflPageSize; + + if (pCell + pInfo->nSize > pPage->aDataEnd) { + /* Cell extends past end of page */ + return SQLITE_CORRUPT_BKPT; + } + ovflPgno = get4byte(pCell + pInfo->nSize - 4); + pBt = pPage->pBt; + assert(pBt->usableSize > 4); + ovflPageSize = pBt->usableSize - 4; + nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1) / ovflPageSize; + assert(nOvfl > 0 || + (CORRUPT_DB && (pInfo->nPayload + ovflPageSize) < ovflPageSize)); + while (nOvfl > 0) { + nOvfl--; + Pgno iNext = 0; + MemPage *pOvfl = 0; + if (ovflPgno < 2 || ovflPgno > btreePagecount(pBt)) { + sqlite3_log(SQLITE_WARNING_DUMP, "Ignore for ovfl page not as expect, pgno %u ovflPgno %u novfl %d payload %u local %u", + pPage->pgno, ovflPgno, nOvfl, pInfo->nPayload, pInfo->nLocal); + return SQLITE_MISUSE; + } + rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext); + if (rc) + return rc; + if (pOvfl) { + rc = fn(pOvfl, args); + if (rc) { + return rc; + } + sqlite3PagerUnref(pOvfl->pDbPage); + } + ovflPgno = iNext; + } + return SQLITE_OK; +} + +static int ScanBtreePage( + BtShared *pBt, /* The BTree that contains the table */ + Pgno pgno, /* Page number to clear */ + ScanFn fn, /* Scan pages function */ + void *args) { /* Scan pages args */ + MemPage *pPage; + int rc; + unsigned char *pCell; + int i; + int hdr; + CellInfo info; + + assert(sqlite3_mutex_held(pBt->mutex)); + if (pgno > btreePagecount(pBt)) { + return SQLITE_OK; + } + rc = getAndInitPage(pBt, pgno, &pPage, 0, 0); + if (rc) { + return rc; + } + rc = fn(pPage, args); + if (rc) { + goto SCAN_PAGE_OUT; + } + hdr = pPage->hdrOffset; + for (i = pPage->nCell - 1; i >= 0; i--) { + pCell = findCell(pPage, i); + if (!pPage->leaf) { + rc = ScanBtreePage(pBt, get4byte(pCell), fn, args); + if (rc) { + goto SCAN_PAGE_OUT; + } + } + pPage->xParseCell(pPage, pCell, &info); + if (info.nLocal < info.nPayload) { + rc = ScanOverflowPages(pPage, pCell, &info, fn, args); + if (rc) { + goto SCAN_PAGE_OUT; + } + } + } + if (!pPage->leaf) { + rc = ScanBtreePage(pBt, get4byte(&pPage->aData[hdr + 8]), fn, args); + if (rc) { + goto SCAN_PAGE_OUT; + } + } +SCAN_PAGE_OUT: + releasePage(pPage); + return rc; +} + +static inline int ScanMetaPages(Btree *pBt, ScanPages *pages) { + return ScanBtreePage(pBt->pBt, 1, GetBtreePageNo, pages); +} + +static int ReleaseMetaPages(ScanPages *pages) { + sqlite3_free(pages->pages); + pages->pages = NULL; + return SQLITE_OK; +} + +static void InitMetaHeader(MetaDwrHdr *hdr) { + (void)memset(hdr, 0, META_VERIFIED_HDR_LEN); + hdr->magic = META_DWR_MAGIC; + hdr->version = META_DWR_VERSION; + hdr->checkSum = META_DWR_MAGIC; +} + +static void MetaDwrReleaseHdr(MetaDwrHdr *hdr) { + if (!hdr) { + return; + } + sqlite3_free(hdr->zones); + sqlite3_free(hdr); +} + +static int ExpandMetaPageBuf(MetaDwrHdr *hdr, u32 minimalPageCnt, u32 bufHasData) { + if (minimalPageCnt < hdr->pageBufSize && hdr->zones != NULL) { + return SQLITE_OK; + } + int pageBufSz = ROUND8(MAX(hdr->pageCnt, minimalPageCnt)); + u8 *zones = (u8 *)sqlite3Malloc(pageBufSz * (sizeof(u8) + sizeof(Pgno))); + if (zones == NULL) { + return SQLITE_NOMEM_BKPT; + } + Pgno *pgnos = (Pgno *)(zones + pageBufSz); + if (hdr->zones != NULL) { + if (bufHasData && hdr->pageCnt > 0) { + (void)memcpy(zones, hdr->zones, hdr->pageCnt * sizeof(u8)); + (void)memcpy(pgnos, hdr->pages, hdr->pageCnt * sizeof(Pgno)); + } + sqlite3_free(hdr->zones); + } + hdr->pageBufSize = pageBufSz; + hdr->zones = zones; + hdr->pages = pgnos; + return SQLITE_OK; +} + +static MetaDwrHdr *AllocInitMetaHeaderDwr(Pager *pPager) { + MetaDwrHdr *hdr = sqlite3MallocZero(sizeof(MetaDwrHdr)); + if (hdr == NULL) { + return NULL; + } + InitMetaHeader(hdr); + int rc = ExpandMetaPageBuf(hdr, META_DWR_HEADER_DEFAULT_PAGE_CNT, 0); + if (rc != SQLITE_OK) { + MetaDwrReleaseHdr(hdr); + return NULL; + } + hdr->checkFileId = (pPager->pVfs != NULL && sqlite3_stricmp(pPager->pVfs->zName, "unix") == 0); + return hdr; +} + +static void MetaDwrCloseFile(Pager *pPager) { + if (!pPager->metaFd) { + return; + } +#if SQLITE_OS_UNIX + if (pPager->metaMapPage) { + osMunmap(pPager->metaMapPage, META_DWR_HEADER_PAGE_SIZE); + pPager->metaMapPage = NULL; + } +#endif + if (pPager->metaHdr && pPager->metaHdr->needSync > 0) { + (void)sqlite3OsSync(pPager->metaFd, SQLITE_SYNC_NORMAL); + } + sqlite3OsClose(pPager->metaFd); +} + +static void MetaDwrPagerRelease(Pager *pPager) { + MetaDwrCloseFile(pPager); + MetaDwrReleaseHdr(pPager->metaHdr); + pPager->metaHdr = NULL; + if (pPager->metaFd) { + sqlite3_free(pPager->metaFd); + pPager->metaFd = NULL; + } +} + +static inline int ReadFromHdrPage(Pager *pPager, void *data, int amt, i64 offset) { + if (pPager->metaMapPage) { + (void)memcpy(data, (u8 *)pPager->metaMapPage + offset, amt); + return SQLITE_OK; + } + return sqlite3OsRead(pPager->metaFd, data, amt, offset); +} + +static int MetaDwrReadHeader(Pager *pPager, MetaDwrHdr *hdr) { + i64 sz = 0; + int rc = sqlite3OsFileSize(pPager->metaFd, &sz); + if (rc != SQLITE_OK) { + sqlite3_log(rc, "Meta dwr file size go wrong"); + return rc; + } + if (sz <= META_DWR_HEADER_PAGE_SIZE) { + rc = SQLITE_IOERR_DATA; + goto READ_META_OUT; + } + rc = ReadFromHdrPage(pPager, hdr, META_VERIFIED_HDR_LEN, 0); + if (rc != SQLITE_OK) { + sqlite3_log(rc, "Meta dwr file header read wrong"); + goto READ_META_OUT; + } + rc = MetaDwrHeaderSimpleCheck(pPager, hdr); + if (rc != SQLITE_OK) { + goto READ_META_OUT; + } + // avoid realloc buffer if buf can't hold all pages + rc = ExpandMetaPageBuf(hdr, hdr->pageCnt, 0); + if (rc != SQLITE_OK) { + goto READ_META_OUT; + } + int zoneSize = hdr->pageCnt * sizeof(u8); + rc = ReadFromHdrPage(pPager, hdr->zones, zoneSize, META_VERIFIED_HDR_LEN); + if (rc != SQLITE_OK) { + goto READ_META_OUT; + } + rc = ReadFromHdrPage(pPager, hdr->pages, hdr->pageCnt * sizeof(Pgno), META_PAGE_NO_OFFSET); + if (rc != SQLITE_OK) { + goto READ_META_OUT; + } + for (u32 i = 0; i < hdr->pageCnt; i++) { + u8 zoneIdx = hdr->zones[i]; + if (zoneIdx != 0 && zoneIdx != 1 && zoneIdx != META_DWR_INVALID_ZONE) { + sqlite3_log(SQLITE_IOERR_DATA, "Invalid zoneIdx %d", zoneIdx); + rc = SQLITE_IOERR_DATA; + break; + } + } +READ_META_OUT: + if (rc == SQLITE_IOERR_DATA) { + InitMetaHeader(hdr); + rc = SQLITE_OK; + } + return rc; +} + +static inline u64 CaculateMetaDwrWriteOffset(int pageSz, u32 idx, u8 zone) { + // 1 header page, idx correspond 2 zone pages + return META_DWR_HEADER_PAGE_SIZE + pageSz * (idx * 2 + zone); +} + +static void MetaDwrUpdateHeaderDbInfo(BtShared *pBt) { + MetaDwrHdr *hdr = pBt->pPager->metaHdr; + // 28 offset: dbSize, freelist pageNo, freelist pages count, schema cookie + const u8 *dbHdrInfo = &pBt->pPage1->aData[28]; + hdr->dbSize = sqlite3Get4byte(dbHdrInfo); +#ifndef SQLITE_OMIT_WAL + if (pagerUseWal(pBt->pPager)) { + WalIndexHdr *pWalHdr = &pBt->pPager->pWal->hdr; + if (pWalHdr->isInit) { + hdr->mxFrameInWal = pWalHdr->mxFrame; + hdr->dbSize = pWalHdr->nPage; + } + } else { + hdr->mxFrameInWal = 0; + } +#endif +#if SQLITE_OS_UNIX + if (hdr->checkFileId) { + unixFile *fd = (unixFile *)pBt->pPager->fd; + if (fd == NULL || fd->pInode == NULL) { + sqlite3_log(SQLITE_WARNING_DUMP, "update meta header invalid fd"); + hdr->hdrValid = 0; + return; + } + hdr->dbFileInode = fd->pInode->fileId.ino; + } +#endif + hdr->freeListPageNo = sqlite3Get4byte(dbHdrInfo + 4); + hdr->freeListPageCnt = sqlite3Get4byte(dbHdrInfo + 8); + hdr->schemaCookie = sqlite3Get4byte(dbHdrInfo + 12); + hdr->hdrValid = 1; +} + +static inline int WriteToHdrPage(Pager *pPager, const void *data, int amt, i64 offset) { + if (pPager->metaMapPage) { + (void)memcpy((u8 *)pPager->metaMapPage + offset, data, amt); + return SQLITE_OK; + } + return sqlite3OsWrite(pPager->metaFd, data, amt, offset); +} + +static int MetaDwrWriteHeader(Pager *pPager, MetaDwrHdr *hdr) { + if (pPager->metaChanged == 0 || hdr == NULL || hdr->pageCnt == 0 || hdr->hdrValid == 0) { + return SQLITE_OK; + } + hdr->hdrValid = 0; + hdr->pageSz = pPager->pageSize; + hdr->dbSize = pPager->dbSize; + int rc = WriteToHdrPage(pPager, hdr, META_VERIFIED_HDR_LEN, 0); + if (rc != SQLITE_OK) { + sqlite3_log(rc, "update meta header write hdr %u wrong", META_VERIFIED_HDR_LEN); + return rc; + } + if (hdr->zones) { + int zoneSize = hdr->pageCnt * sizeof(u8); + rc = WriteToHdrPage(pPager, hdr->zones, zoneSize, META_VERIFIED_HDR_LEN); + if (rc != SQLITE_OK) { + sqlite3_log(rc, "update meta header write zonebuf %u wrong", zoneSize); + return rc; + } + } + if (hdr->pages) { + int pageBufSz = hdr->pageCnt * sizeof(Pgno); + rc = WriteToHdrPage(pPager, hdr->pages, pageBufSz, META_PAGE_NO_OFFSET); + if (rc != SQLITE_OK) { + sqlite3_log(rc, "update meta header write pagebuf %u wrong", pageBufSz); + } + } + if (rc == SQLITE_OK) { + u64 size = CaculateMetaDwrWriteOffset((int)pPager->pageSize, hdr->pageCnt, 0); + rc = sqlite3OsTruncate(pPager->metaFd, size); + if (rc != SQLITE_OK) { + sqlite3_log(rc, "update meta header truncate filesz %lu wrong", size); + } + i64 timeMs = 0; + sqlite3OsCurrentTimeInt64(pPager->pVfs, &timeMs); + if ((timeMs - hdr->lastSyncTime) > META_FILE_SYNC_TIMEOUT_MS || + hdr->needSync >= META_FILE_UPDATE_TIMES_PER_SYNC) { + rc = sqlite3OsSync(pPager->metaFd, SQLITE_SYNC_NORMAL); + if (rc != SQLITE_OK) { + sqlite3_log(rc, "update meta header sync filesz %lu wrong", size); + } + hdr->lastSyncTime = timeMs; + hdr->needSync = 0; + } else { + hdr->needSync++; + } + } + return rc; +} + +static int MetaDwrFindPageIdx(MetaDwrHdr *hdr, u32 pgno, u32 *idx) { + for (u32 i = 0; i < hdr->pageCnt && i < META_DWR_MAX_PAGES; i++) { + if (pgno == hdr->pages[i]) { + *idx = i; + return 1; + } + } + return 0; +} + +static int MetaDwrWriteOnePage(Btree *pBt, PgHdr *pPage, MetaDwrHdr *hdr, u8 curZones, u32 idx) { + int rc = SQLITE_OK; + u8 pageExpand = 0; + if (hdr->pageCnt <= idx) { + rc = ExpandMetaPageBuf(hdr, idx + 1, 1); + if (rc != SQLITE_OK) { + return rc; + } + pageExpand = 1; + } + Pager *pPager = pBt->pBt->pPager; + // asume zone 0 or 1 + u8 zone = 1 - curZones; + int pageSz = sqlite3BtreeGetPageSize(pBt); + u64 ofs = CaculateMetaDwrWriteOffset(pageSz, idx, zone); + void *pData; +#if defined(SQLITE_HAS_CODEC) + if ((pData = sqlite3PagerCodec(pPage)) == 0) + return SQLITE_NOMEM; +#else + pData = pPage->pData; +#endif + rc = sqlite3OsWrite(pPager->metaFd, pData, pageSz, ofs); + if (rc != SQLITE_OK) { + return rc; + } + hdr->zones[idx] = zone; + hdr->pages[idx] = pPage->pgno; + if (pageExpand) { + hdr->pageCnt++; + } + return SQLITE_OK; +} + +static int MetaDwrRestoreAllPages(Btree *pBt, const ScanPages *metaPages, MetaDwrHdr *hdr) { + u32 i = 0; + PgHdr *p = NULL; + int rc = SQLITE_OK; + for (i = 0; i < metaPages->pageCnt && i < META_DWR_MAX_PAGES; i++) { + Pgno pgno = metaPages->pages[i]; + if (pgno > btreePagecount(pBt->pBt)) { + sqlite3_log(SQLITE_WARNING_DUMP, "pageno %d overlimit", pgno); + return SQLITE_CORRUPT_BKPT; + } + rc = sqlite3PagerGet(pBt->pBt->pPager, pgno, &p, 0); + if (rc) { + return rc; + } + rc = MetaDwrWriteOnePage(pBt, p, hdr, 1, i); + sqlite3PagerUnref(p); + if (rc) { + return rc; + } + } + hdr->pageCnt = metaPages->pageCnt; + MetaDwrUpdateHeaderDbInfo(pBt->pBt); + return rc; +} + +static inline const char *GetMetaFilePath(Pager *pPager) +{ + return pPager->metaFd == NULL ? NULL : ((const char *)pPager->metaFd + ROUND8(pPager->pVfs->szOsFile)); +} + +static int MetaDwrOpenFile(Pager *pPager, u8 openCreate) { + if (pPager->metaFd || pPager->zFilename == NULL) { + return SQLITE_OK; + } + sqlite3BeginBenignMalloc(); + sqlite3_vfs *pVfs = pPager->pVfs; + int size = strlen(pPager->zFilename) + sizeof("-dwr"); + int szOsFile = ROUND8(pVfs->szOsFile); + sqlite3_file *metaFd = (sqlite3_file *)sqlite3MallocZero(szOsFile + size); + char *metaPath = (char *)metaFd + szOsFile; + if (metaFd == NULL) { + sqlite3EndBenignMalloc(); + sqlite3_log(SQLITE_NOMEM_BKPT, "sqlite alloc memsize %d go wrong", szOsFile + size); + return SQLITE_NOMEM_BKPT; + } + sqlite3_snprintf(size, metaPath, "%s-dwr", pPager->zFilename); + int exists = 0; + int rc = sqlite3OsAccess(pVfs, metaPath, SQLITE_ACCESS_EXISTS, &exists); + if (rc != SQLITE_OK) { + goto INIT_META_OUT; + } + if (!exists && !openCreate) { + sqlite3_free(metaFd); + goto INIT_META_OUT; + } + u32 flags = (SQLITE_OPEN_READWRITE | SQLITE_OPEN_SUPER_JOURNAL); + if (openCreate) { + flags |= SQLITE_OPEN_CREATE; + } + rc = sqlite3OsOpen(pVfs, metaPath, metaFd, (int)flags, 0); + if (rc != SQLITE_OK) { + goto INIT_META_OUT; + } +#if SQLITE_OS_UNIX + if (pPager->metaMapPage == NULL) { + sqlite3_int64 sz = META_DWR_HEADER_PAGE_SIZE; + sqlite3OsFileControlHint(metaFd, SQLITE_FCNTL_CHUNK_SIZE, &sz); + sqlite3OsFileControlHint(metaFd, SQLITE_FCNTL_SIZE_HINT, &sz); + void *page = osMmap(0, META_DWR_HEADER_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, + ((unixFile *)metaFd)->h, 0); + if (page != MAP_FAILED) { + pPager->metaMapPage = page; + } + } +#endif + pPager->metaFd = metaFd; +INIT_META_OUT: + sqlite3EndBenignMalloc(); + if (rc != SQLITE_OK && metaFd != NULL) { + sqlite3_free(metaFd); + } + return rc; +} + +void MetaDwrCheckVacuum(BtShared *pBt) { + if (!pBt || !pBt->pPager->metaFd) { + return; + } + if (pBt->nPage < pBt->maxMetaPage) { + pBt->pPager->metaChanged = META_SCHEMA_CHANGED; + } +} + +static inline u8 LocalMetaHdrValid(Pager *pPager) { + return pPager->metaMapPage != NULL && memcmp(pPager->metaMapPage, pPager->metaHdr, + META_VERIFIED_HDR_LEN) == 0; +} + +static int MetaDwrLoadHdr(Pager *pPager) { + if (!pPager->metaHdr) { + pPager->metaHdr = AllocInitMetaHeaderDwr(pPager); + if (pPager->metaHdr == NULL) { + return SQLITE_NOMEM_BKPT; + } + } + if (LocalMetaHdrValid(pPager)) { + return SQLITE_OK; + } + return MetaDwrReadHeader(pPager, pPager->metaHdr); +} + +static int MetaDwrLoadAndCheckMetaFile(BtShared *pBt, u8 reportErr) { + int rc = MetaDwrLoadHdr(pBt->pPager); + if (rc != SQLITE_OK) { + return rc; + } + MetaDwrHdr *hdr = pBt->pPager->metaHdr; + if (hdr->pageCnt == 0) { + return reportErr ? SQLITE_IOERR_DATA : SQLITE_OK; + } + // 28 offset: dbSize, freelist pageNo, freelist pages count, schema cookie + u8 *dbHdrInfo = &pBt->pPage1->aData[28]; + if (hdr->dbSize != pBt->pPager->dbSize || hdr->dbSize != sqlite3Get4byte(dbHdrInfo) || + hdr->freeListPageNo != sqlite3Get4byte(dbHdrInfo + 4) || + hdr->freeListPageCnt != sqlite3Get4byte(dbHdrInfo + 8) || + hdr->schemaCookie != sqlite3Get4byte(dbHdrInfo + 12)) { + sqlite3_log(SQLITE_IOERR_DATA, "Meta dwr file expect %u-%u-%u-%u-%u but gotton %u-%u-%u-%u-%u", + pBt->pPager->dbSize, hdr->dbSize, sqlite3Get4byte(dbHdrInfo), sqlite3Get4byte(dbHdrInfo + 4), + sqlite3Get4byte(dbHdrInfo + 8), sqlite3Get4byte(dbHdrInfo + 12), hdr->dbSize, hdr->freeListPageNo, + hdr->freeListPageCnt, hdr->schemaCookie); + // reinit + InitMetaHeader(hdr); + if (reportErr) { + return SQLITE_IOERR_DATA; + } + } + return SQLITE_OK; +} + +static int MetaDwrReadOnePage(Pager *pPager, MetaDwrHdr *hdr, int idx, u8 *pData) { + u64 ofs = CaculateMetaDwrWriteOffset(pPager->pageSize, idx, hdr->zones[idx]); + int rc = sqlite3OsRead(pPager->metaFd, pData, pPager->pageSize, ofs); + CODEC1(pPager, pData, hdr->pages[idx], 3, rc = SQLITE_NOMEM_BKPT); + return rc; +} + +static int MetaDwrRecoverHeadPage( + Pager *pPager, /* The pager open on the database file */ + Pgno pgno, /* Page number to fetch */ + DbPage **pDbPage, + int flag) { + if (pPager->metaFd == NULL) { + return pgno == 1 ? SQLITE_NOTADB : SQLITE_CORRUPT; + } + sqlite3_pcache_page *pCachePage = sqlite3PcacheFetch(pPager->pPCache, pgno, 3); + if (pCachePage == NULL) { + sqlite3_log(SQLITE_NOMEM_BKPT, "Get meta page wrong %d", pgno); + return SQLITE_NOMEM_BKPT; + } + DbPage *pPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pCachePage); + pPage->pPager = pPager; + assert(pCachePage != 0); + int rc = MetaDwrLoadHdr(pPager); + if (rc != SQLITE_OK) { + goto RELEASE_OUT; + } + MetaDwrHdr *hdr = pPager->metaHdr; + u8 walChecked = 0; +#ifndef SQLITE_OMIT_WAL + if (pagerUseWal(pPager)) { + WalIndexHdr *pWalHdr = &pPager->pWal->hdr; + if (pWalHdr->isInit && pWalHdr->mxFrame != 0) { + if (hdr->mxFrameInWal != pWalHdr->mxFrame || hdr->dbSize != pWalHdr->nPage) { + rc = SQLITE_NOTADB; + sqlite3_log(SQLITE_WARNING_DUMP, "Meta dwr wal hdr expect %u-%u but gotten %u-%u", + hdr->mxFrameInWal, hdr->dbSize, pWalHdr->mxFrame, pWalHdr->nPage); + goto RELEASE_OUT; + } else { + walChecked = 1; + } + } + } + if (walChecked == 0) { + i64 size = 0; + rc = sqlite3OsFileSize(pPager->fd, &size); + if (rc != SQLITE_OK) { + rc = SQLITE_NOTADB; + sqlite3_log(SQLITE_WARNING_DUMP, "Meta dwr get db file size go wrong"); + goto RELEASE_OUT; + } + i64 expectSz = (i64)hdr->dbSize * (i64)hdr->pageSz; + if (size != expectSz) { + rc = SQLITE_NOTADB; + sqlite3_log(SQLITE_WARNING_DUMP, "Meta dwr expect file size %lu but gotten size %llu", + expectSz, size); + goto RELEASE_OUT; + } + } +#endif + rc = SQLITE_NOTADB; + for (u32 i = 0; i < hdr->pageCnt; i++) { + if (hdr->pages[i] != pgno) { + continue; + } + rc = MetaDwrReadOnePage(pPager, hdr, i, sqlite3PagerGetData(pPage)); + if (rc == SQLITE_OK) { + *pDbPage = pPage; + if (pPage->pgno == 1) { + memcpy(&pPager->dbFileVers, &((u8 *)pPage->pData)[24], sizeof(pPager->dbFileVers)); + } + pager_set_pagehash(pPage); + } + break; + } +RELEASE_OUT: + if (rc != SQLITE_OK && pPage != NULL) { + sqlite3PcacheDrop(pPage); + } + return rc; +} + +static int MetaDwrRestoreChangedPages(Btree *pBt) { + Pager *pPager = pBt->pBt->pPager; + MetaDwrHdr *hdr = pPager->metaHdr; + u8 *zones = sqlite3MallocZero(hdr->pageBufSize * sizeof(u8)); + if (zones == NULL) { + sqlite3_log(SQLITE_NOMEM_BKPT, "Alloc zones buffer size %u go wrong", hdr->pageBufSize * sizeof(u8)); + return SQLITE_NOMEM_BKPT; + } + if (hdr->pageCnt > 0) { + memcpy(zones, hdr->zones, hdr->pageCnt * sizeof(u8)); + } + u32 idx = 0; + PgHdr *p = 0; + PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache); + int rc = SQLITE_OK; + for (p = pList; p; p = p->pDirty) { + if (MetaDwrFindPageIdx(hdr, p->pgno, &idx) == 0) { + continue; + } + rc = MetaDwrWriteOnePage(pBt, p, hdr, zones[idx], idx); + if (rc != SQLITE_OK) { + break; + } + } + if (rc == SQLITE_OK) { + MetaDwrUpdateHeaderDbInfo(pBt->pBt); + } + sqlite3_free(zones); + return rc; +} + +static int MetaDwrUpdateMetaPages(Btree *pBt) { + Pager *pPager = pBt->pBt->pPager; + if (!pPager || !pPager->metaFd || pPager->memDb || pPager->readOnly || pBt->pBt->pPage1 == NULL) { + return SQLITE_OK; + } + if (pPager->metaChanged == 0) { + if ((pBt->pBt->pPage1->pDbPage->flags & PGHDR_DIRTY) == 0) { + return SQLITE_OK; + } + pPager->metaChanged = META_HEADER_CHANGED; + } + sqlite3BeginBenignMalloc(); + int rc = MetaDwrLoadHdr(pPager); + if (rc != SQLITE_OK) { + goto UPDATE_OUT; + } + // only update header page + if (pPager->metaChanged == META_HEADER_CHANGED) { + rc = MetaDwrRestoreChangedPages(pBt); + goto UPDATE_OUT; + } + // update schema pages + ScanPages metaPages = {0}; + rc = ScanMetaPages(pBt, &metaPages); + if (rc != SQLITE_OK) { + goto UPDATE_OUT; + } + MetaDwrHdr *hdr = pPager->metaHdr; + // rewrite + if (hdr->pageCnt == 0 || hdr->pageCnt != metaPages.pageCnt || pBt->pBt->nPage > pBt->pBt->maxMetaPage || + memcmp(hdr->pages, metaPages.pages, hdr->pageCnt * sizeof(Pgno))) { + // if page numbers unorderred, restore all pages + rc = MetaDwrRestoreAllPages(pBt, &metaPages, hdr); + } else { + rc = MetaDwrRestoreChangedPages(pBt); + } + if (rc == SQLITE_OK) { + pBt->pBt->maxMetaPage = metaPages.maxPageNo; + } + ReleaseMetaPages(&metaPages); +UPDATE_OUT: + sqlite3EndBenignMalloc(); + return rc; +} + +static int MetaDwrRecoverSinglePage(Btree *pBt, int pgno, u8 *pData) { + if (pgno < 1 || pBt == NULL) { + return SQLITE_CORRUPT_BKPT; + } + Pager *pPager = sqlite3BtreePager(pBt); + DbPage *pDbPage = NULL; + int rc = sqlite3PagerGet(pPager, pgno, &pDbPage, 0); + if (rc) { + return rc; + } + if ((rc = sqlite3PagerWrite(pDbPage)) == SQLITE_OK) { + memcpy(sqlite3PagerGetData(pDbPage), pData, pPager->pageSize); + } else { + sqlite3_log(rc, "Dwr recoverwrite meta page %d failed", pgno); + } + sqlite3PagerUnref(pDbPage); + return rc; +} + +static int MetaDwrCheckMeta(Btree *pBt) { + int nErr = 0; + Pgno aRoot[2] = {0, 1}; // quick check and only check root btree + char *errStr = sqlite3BtreeIntegrityCheck(pBt->db, pBt, &aRoot[0], 2, SQLITE_INTEGRITY_CHECK_ERROR_MAX, + &nErr); + if (nErr == 0) { + assert(errStr == 0); + return SQLITE_OK; + } + if (errStr == 0) { + sqlite3_log(SQLITE_NOMEM, "Meta integrity check no mem"); + return SQLITE_NOMEM; + } + sqlite3_log(SQLITE_WARNING_DUMP, "Meta integrity check %s", errStr); + sqlite3DbFree(pBt->db, errStr); + return SQLITE_CORRUPT; +} + +static int MetaDwrBeginTrans(Btree *pBt, int wrflag) { + pBt->pBt->btsFlags &= ~BTS_READ_ONLY; + Pager *pPager = pBt->pBt->pPager; + void *xGetMethod = pPager->xGet; + pPager->xGetMethod = MetaDwrRecoverHeadPage; + pPager->xGet = MetaDwrRecoverHeadPage; + int rc = sqlite3BtreeBeginTrans(pBt, wrflag, 0); + pPager->xGet = xGetMethod; + pPager->xGetMethod = 0; + if (rc == SQLITE_OK) { + sqlite3PagerWrite(pBt->pBt->pPage1->pDbPage); + sqlite3_log(rc, "sqlite fix meta header"); + } + return rc; +} + +static int MetaDwrRecoverAndBeginTran(Btree *pBt, int wrflag, int *pSchemaVersion) +{ + Pager *pPager = pBt->pBt->pPager; + assert(sqlite3_mutex_held(pBt->pBt->mutex)); + if (!pPager->metaFd || pBt->pBt->metaRecoverStatus || pPager->readOnly || pPager->memDb) { + return SQLITE_NOTADB; + } + int rc = MetaDwrLoadHdr(pPager); + if (rc != SQLITE_OK) { + sqlite3_log(rc, "MetaDwr load header failed"); + return rc; + } + pBt->pBt->metaRecoverStatus = META_IN_RECOVERY; + rc = MetaDwrBeginTrans(pBt, 2); + if (rc != SQLITE_OK) { + return rc; + } + void *pData = NULL; + pPager->metaChanged = META_HEADER_CHANGED; + MetaDwrHdr *hdr = pPager->metaHdr; + sqlite3_log(SQLITE_WARNING_DUMP, "sqlite meta recover %u frames", hdr->pageCnt); + int szPage = sqlite3BtreeGetPageSize(pBt); + pData = sqlite3Malloc(szPage); + if (pData == NULL) { + rc = SQLITE_NOMEM; + sqlite3_log(rc, "Dwr malloc mem size %d failed", szPage); + goto DWR_RECOVER_OUT; + } + for (u32 i = 0; i < hdr->pageCnt; i++) { + rc = MetaDwrReadOnePage(pPager, hdr, i, pData); + if (rc != SQLITE_OK) { + sqlite3_log(rc, "Dwr read %d meta page failed ", i); + break; + } + rc = MetaDwrRecoverSinglePage(pBt, hdr->pages[i], pData); + if (rc != SQLITE_OK) { + sqlite3_log(rc, "Dwr recover %d meta page failed ", i); + break; + } + } +DWR_RECOVER_OUT: + /* Close the transaction, if one was opened. */ + if (rc == SQLITE_OK) { + sqlite3BtreeCommit(pBt); + } else { + (void)sqlite3BtreeRollback(pBt, SQLITE_ABORT_ROLLBACK, 0); + } + if (rc == SQLITE_OK) { + rc = sqlite3BtreeBeginTrans(pBt, wrflag, pSchemaVersion); + } + if (rc == SQLITE_OK) { + pBt->pBt->metaRecoverStatus = META_RECOVER_SUCCESS; + } + if (pData) { + sqlite3_free(pData); + } + return rc; +} + +static int Sqlite3MetaDwrCheckRestore(Btree *pBt) { + Pager *pPager = pBt->pBt->pPager; + int rc = MetaDwrOpenFile(pPager, 1); + if (rc != SQLITE_OK) { + return rc; + } + ScanPages metaPages = {0}; + rc = ScanMetaPages(pBt, &metaPages); + if (rc != SQLITE_OK || metaPages.pageCnt == 0) { + goto CHK_RESTORE_OUT; + } + rc = MetaDwrLoadAndCheckMetaFile(pBt->pBt, 0); + if (rc != SQLITE_OK) { + goto CHK_RESTORE_OUT; + } + MetaDwrHdr *hdr = pPager->metaHdr; + if (hdr->pageCnt == 0 || hdr->pageCnt != metaPages.pageCnt || + memcmp(hdr->pages, metaPages.pages, hdr->pageCnt * sizeof(Pgno))) { + sqlite3_log(SQLITE_WARNING_DUMP, "sqlite meta restore all"); + rc = MetaDwrRestoreAllPages(pBt, &metaPages, hdr); + if (rc == SQLITE_OK) { + pPager->metaChanged = META_SCHEMA_CHANGED; + rc = MetaDwrWriteHeader(pPager, hdr); + pPager->metaChanged = 0; + } + } + if (rc == SQLITE_OK) { + pBt->pBt->maxMetaPage = metaPages.maxPageNo; + } +CHK_RESTORE_OUT: + ReleaseMetaPages(&metaPages); + return rc; +} + +static inline u8 IsConnectionValidForCheck(Pager *pPager) +{ +#if SQLITE_OS_UNIX + unixFile *fd = (unixFile *)pPager->fd; + // unix and only one connection exist + if (fd == NULL || fd->pInode == NULL || pPager->pVfs == NULL || + sqlite3_stricmp(pPager->pVfs->zName, "unix") != 0 || fd->pInode->nRef != 1) { + return 0; + } + return 1; +#else + return 0; +#endif +} + +static int MetaDwrOpenAndCheck(Btree *pBt) +{ + Pager *pPager = pBt->pBt->pPager; + if (pPager->memDb || pPager->readOnly || !IsConnectionValidForCheck(pPager)) { + return SQLITE_OK; + } +#ifdef SQLITE_HAS_CODEC + // not support codec right now + if (pPager->xCodec) { + return SQLITE_OK; + } +#endif + sqlite3BtreeEnter(pBt); + int rc = SQLITE_OK; + int openedTransaction = 0; + int tnxState = sqlite3BtreeTxnState(pBt); + if (tnxState == SQLITE_TXN_NONE) { + rc = sqlite3BtreeBeginTrans(pBt, 0, 0); + if (rc != SQLITE_OK) { + goto DWR_OPEN_OUT; + } + openedTransaction = 1; + } + rc = MetaDwrCheckMeta(pBt); + if (rc == SQLITE_CORRUPT || rc == SQLITE_NOTADB) { + // keep txn status after recover + rc = MetaDwrRecoverAndBeginTran(pBt, tnxState == SQLITE_TXN_WRITE ? 1 : 0, 0); + goto DWR_OPEN_OUT; + } + rc = Sqlite3MetaDwrCheckRestore(pBt); +DWR_OPEN_OUT: + if (rc == SQLITE_OK && pBt->pBt->metaRecoverStatus == META_RECOVER_SUCCESS) { + rc = MetaDwrCheckMeta(pBt); + if (rc == SQLITE_OK) { + rc = SQLITE_META_RECOVERED; + } + } + /* Close the transaction, if one was opened. */ + if (openedTransaction) { + sqlite3BtreeCommit(pBt); + } + sqlite3BtreeLeave(pBt); + return rc; +} +static void MetaDwrDisable(Btree *pBt) +{ + Pager *pPager = pBt->pBt->pPager; + if (pPager->metaFd == NULL || pPager->memDb || pPager->readOnly || !IsConnectionValidForCheck(pPager)) { + return; + } +#ifdef SQLITE_HAS_CODEC + // not support codec right now + if (pPager->xCodec) { + return; + } +#endif + sqlite3BtreeEnter(pBt); + MetaDwrCloseFile(pPager); + MetaDwrReleaseHdr(pPager->metaHdr); + pPager->metaHdr = NULL; + const char *metaPath = GetMetaFilePath(pPager); + if (metaPath != NULL) { + (void)osUnlink(metaPath); + } + if (pPager->metaFd) { + sqlite3_free(pPager->metaFd); + pPager->metaFd = NULL; + } + sqlite3BtreeLeave(pBt); +} +#endif #if SQLITE_OS_UNIX #include #include -- Gitee From f79d3bcfd2d24256413ed95f65a0be7d2c77a6e1 Mon Sep 17 00:00:00 2001 From: wanghaishuo Date: Sat, 12 Apr 2025 10:09:45 +0800 Subject: [PATCH 5/9] add icu Signed-off-by: ryne3366 --- src/sqlite3.c | 1033 ++++------------------------------------------ src/sqlite3icu.c | 892 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 976 insertions(+), 949 deletions(-) create mode 100644 src/sqlite3icu.c diff --git a/src/sqlite3.c b/src/sqlite3.c index 71f902b..dd89c5a 100644 --- a/src/sqlite3.c +++ b/src/sqlite3.c @@ -2459,7 +2459,7 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ - +#define SQLITE_CONFIG_ENABLE_ICU 31 /* boolean */ /* ** CAPI3REF: Database Connection Configuration Options ** @@ -3193,6 +3193,17 @@ SQLITE_API int sqlite3_get_table( ); SQLITE_API void sqlite3_free_table(char **result); +// hw export the symbols +#ifdef SQLITE_EXPORT_SYMBOLS +#if defined(__GNUC__) +# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) +#elif defined(_MSC_VER) +# define EXPORT_SYMBOLS __declspec(dllexport) +#else +# define EXPORT_SYMBOLS +#endif +#endif // SQLITE_EXPORT_SYMBOLS + /* ** CAPI3REF: Formatted String Printing Functions ** @@ -173713,6 +173724,7 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db); /************** End of rtree.h ***********************************************/ /************** Continuing where we left off in main.c ***********************/ #endif +#include "sqlite3tokenizer.h" #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) /************** Include sqliteicu.h in the middle of main.c ******************/ /************** Begin file sqliteicu.h ***************************************/ @@ -173737,13 +173749,54 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db); extern "C" { #endif /* __cplusplus */ -SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db); +SQLITE_PRIVATE int sqlite3IcuInitInner(sqlite3 *db); #if 0 } /* extern "C" */ #endif /* __cplusplus */ /************** End of sqliteicu.h *******************************************/ +#ifndef _WIN32 +#include +#endif + +typedef void (*sqlite3Fts3IcuTokenizerModule_ptr)(sqlite3_tokenizer_module const** ppModule); +typedef int (*sqlite3IcuInit_ptr)(sqlite3 *db); +static sqlite3Fts3IcuTokenizerModule_ptr tokenModulePtr = NULL; +static sqlite3IcuInit_ptr icuInitPtr = NULL; +static u32 icuEnable = 0u; +static u32 icuInit = 0u; +static void *g_library = NULL; + +int sqlite3IcuModuleInit(){ + int rc = SQLITE_OK; + if( icuInit ){ + return rc; + } +#ifndef _WIN32 + g_library = dlopen("libsqliteicu.z.so", RTLD_LAZY); + if( g_library==NULL ){ + sqlite3_log(SQLITE_ERROR, "load icu so failed"); + return SQLITE_ERROR; + } + tokenModulePtr = (sqlite3Fts3IcuTokenizerModule_ptr)dlsym(g_library, "sqlite3Fts3IcuTokenizerModule"); + icuInitPtr = (sqlite3IcuInit_ptr)dlsym(g_library, "sqlite3IcuInit"); + if( tokenModulePtr==NULL || icuInitPtr==NULL ){ + sqlite3_log(SQLITE_ERROR, "load icu init function failed"); + return SQLITE_ERROR; + } + icuInit = 1u; +#endif + return rc; +} + +SQLITE_PRIVATE int sqlite3IcuInitInner(sqlite3 *db) +{ + if( !icuEnable ){ + return SQLITE_OK; + } + return icuInitPtr(db); +} /************** Continuing where we left off in main.c ***********************/ #endif @@ -173793,7 +173846,7 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = { sqlite3Fts5Init, #endif #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) - sqlite3IcuInit, + sqlite3IcuInitInner, #endif #ifdef SQLITE_ENABLE_RTREE sqlite3RtreeInit, @@ -174150,12 +174203,24 @@ SQLITE_API int sqlite3_shutdown(void){ SQLITE_API int sqlite3_config(int op, ...){ va_list ap; int rc = SQLITE_OK; + va_start(ap, op); + +#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) + if( op==SQLITE_CONFIG_ENABLE_ICU ){ + int iVal = va_arg(ap, int); + if( iVal==0 ){ + icuEnable = 0u; + }else{ + icuEnable = 1u; + } + return rc; + } +#endif /* SQLITE_ENABLE_ICU */ /* sqlite3_config() shall return SQLITE_MISUSE if it is invoked while ** the SQLite library is in use. */ if( sqlite3GlobalConfig.isInit ) return SQLITE_MISUSE_BKPT; - va_start(ap, op); switch( op ){ /* Mutex configuration options are only available in a threadsafe @@ -177223,6 +177288,12 @@ static int openDatabase( sqlite3RegisterPerConnectionBuiltinFunctions(db); rc = sqlite3_errcode(db); +#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) + if( icuEnable ){ + rc = sqlite3IcuModuleInit(); + if( rc!=SQLITE_OK ) return rc; + } +#endif /* Load compiled-in extensions */ for(i=0; rc==SQLITE_OK && i arg1 arg2) - ** - ** then argc is set to 2, and the argv[] array contains pointers - ** to the strings "arg1" and "arg2". - ** - ** This method should return either SQLITE_OK (0), or an SQLite error - ** code. If SQLITE_OK is returned, then *ppTokenizer should be set - ** to point at the newly created tokenizer structure. The generic - ** sqlite3_tokenizer.pModule variable should not be initialized by - ** this callback. The caller will do so. - */ - int (*xCreate)( - int argc, /* Size of argv array */ - const char *const*argv, /* Tokenizer argument strings */ - sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ - ); - - /* - ** Destroy an existing tokenizer. The fts3 module calls this method - ** exactly once for each successful call to xCreate(). - */ - int (*xDestroy)(sqlite3_tokenizer *pTokenizer); - - /* - ** Create a tokenizer cursor to tokenize an input buffer. The caller - ** is responsible for ensuring that the input buffer remains valid - ** until the cursor is closed (using the xClose() method). - */ - int (*xOpen)( - sqlite3_tokenizer *pTokenizer, /* Tokenizer object */ - const char *pInput, int nBytes, /* Input buffer */ - sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */ - ); - - /* - ** Destroy an existing tokenizer cursor. The fts3 module calls this - ** method exactly once for each successful call to xOpen(). - */ - int (*xClose)(sqlite3_tokenizer_cursor *pCursor); - - /* - ** Retrieve the next token from the tokenizer cursor pCursor. This - ** method should either return SQLITE_OK and set the values of the - ** "OUT" variables identified below, or SQLITE_DONE to indicate that - ** the end of the buffer has been reached, or an SQLite error code. - ** - ** *ppToken should be set to point at a buffer containing the - ** normalized version of the token (i.e. after any case-folding and/or - ** stemming has been performed). *pnBytes should be set to the length - ** of this buffer in bytes. The input text that generated the token is - ** identified by the byte offsets returned in *piStartOffset and - ** *piEndOffset. *piStartOffset should be set to the index of the first - ** byte of the token in the input buffer. *piEndOffset should be set - ** to the index of the first byte just past the end of the token in - ** the input buffer. - ** - ** The buffer *ppToken is set to point at is managed by the tokenizer - ** implementation. It is only required to be valid until the next call - ** to xNext() or xClose(). - */ - /* TODO(shess) current implementation requires pInput to be - ** nul-terminated. This should either be fixed, or pInput/nBytes - ** should be converted to zInput. - */ - int (*xNext)( - sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */ - const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */ - int *piStartOffset, /* OUT: Byte offset of token in input buffer */ - int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */ - int *piPosition /* OUT: Number of tokens returned before this one */ - ); - - /*********************************************************************** - ** Methods below this point are only available if iVersion>=1. - */ - - /* - ** Configure the language id of a tokenizer cursor. - */ - int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid); -}; - -struct sqlite3_tokenizer { - const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */ - /* Tokenizer implementations will typically add additional fields */ -}; - -struct sqlite3_tokenizer_cursor { - sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */ - /* Tokenizer implementations will typically add additional fields */ -}; int fts3_global_term_cnt(int iTerm, int iCol); int fts3_term_cnt(int iTerm, int iCol); @@ -183999,9 +183962,6 @@ SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(sqlite3_tokenizer_module co #ifndef SQLITE_DISABLE_FTS3_UNICODE SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const**ppModule); #endif -#ifdef SQLITE_ENABLE_ICU -SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); -#endif /* ** Initialize the fts3 extension. If this extension is built as part @@ -184020,7 +183980,14 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){ #ifdef SQLITE_ENABLE_ICU const sqlite3_tokenizer_module *pIcu = 0; - sqlite3Fts3IcuTokenizerModule(&pIcu); + if( icuEnable ){ + if( tokenModulePtr!=NULL ){ + tokenModulePtr(&pIcu); + }else{ + sqlite3_log(SQLITE_ERROR, "icu module ptr is null"); + return SQLITE_ERROR; + } + } #endif #ifndef SQLITE_DISABLE_FTS3_UNICODE @@ -184056,7 +184023,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){ || sqlite3Fts3HashInsert(&pHash->hash, "unicode61", 10, (void *)pUnicode) #endif #ifdef SQLITE_ENABLE_ICU - || (pIcu && sqlite3Fts3HashInsert(&pHash->hash, "icu", 4, (void *)pIcu)) + || (icuEnable && pIcu && sqlite3Fts3HashInsert(&pHash->hash, "icu", 4, (void *)pIcu)) #endif ){ rc = SQLITE_NOMEM; @@ -207668,829 +207635,6 @@ SQLITE_API int sqlite3_rtree_init( #endif /************** End of rtree.c ***********************************************/ -/************** Begin file icu.c *********************************************/ -/* -** 2007 May 6 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $ -** -** This file implements an integration between the ICU library -** ("International Components for Unicode", an open-source library -** for handling unicode data) and SQLite. The integration uses -** ICU to provide the following to SQLite: -** -** * An implementation of the SQL regexp() function (and hence REGEXP -** operator) using the ICU uregex_XX() APIs. -** -** * Implementations of the SQL scalar upper() and lower() functions -** for case mapping. -** -** * Integration of ICU and SQLite collation sequences. -** -** * An implementation of the LIKE operator that uses ICU to -** provide case-independent matching. -*/ - -#if !defined(SQLITE_CORE) \ - || defined(SQLITE_ENABLE_ICU) \ - || defined(SQLITE_ENABLE_ICU_COLLATIONS) - -/* Include ICU headers */ -#include -#include -#include -#include - -/* #include */ - -#ifndef SQLITE_CORE -/* #include "sqlite3ext.h" */ - SQLITE_EXTENSION_INIT1 -#else -/* #include "sqlite3.h" */ -#endif - -/* -** This function is called when an ICU function called from within -** the implementation of an SQL scalar function returns an error. -** -** The scalar function context passed as the first argument is -** loaded with an error message based on the following two args. -*/ -static void icuFunctionError( - sqlite3_context *pCtx, /* SQLite scalar function context */ - const char *zName, /* Name of ICU function that failed */ - UErrorCode e /* Error code returned by ICU function */ -){ - char zBuf[128]; - sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e)); - zBuf[127] = '\0'; - sqlite3_result_error(pCtx, zBuf, -1); -} - -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) - -/* -** Maximum length (in bytes) of the pattern in a LIKE or GLOB -** operator. -*/ -#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH -# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000 -#endif - -/* -** Version of sqlite3_free() that is always a function, never a macro. -*/ -static void xFree(void *p){ - sqlite3_free(p); -} - -/* -** This lookup table is used to help decode the first byte of -** a multi-byte UTF8 character. It is copied here from SQLite source -** code file utf8.c. -*/ -static const unsigned char icuUtf8Trans1[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, -}; - -#define SQLITE_ICU_READ_UTF8(zIn, c) \ - c = *(zIn++); \ - if( c>=0xc0 ){ \ - c = icuUtf8Trans1[c-0xc0]; \ - while( (*zIn & 0xc0)==0x80 ){ \ - c = (c<<6) + (0x3f & *(zIn++)); \ - } \ - } - -#define SQLITE_ICU_SKIP_UTF8(zIn) \ - assert( *zIn ); \ - if( *(zIn++)>=0xc0 ){ \ - while( (*zIn & 0xc0)==0x80 ){zIn++;} \ - } - - -/* -** Compare two UTF-8 strings for equality where the first string is -** a "LIKE" expression. Return true (1) if they are the same and -** false (0) if they are different. -*/ -static int icuLikeCompare( - const uint8_t *zPattern, /* LIKE pattern */ - const uint8_t *zString, /* The UTF-8 string to compare against */ - const UChar32 uEsc /* The escape character */ -){ - static const uint32_t MATCH_ONE = (uint32_t)'_'; - static const uint32_t MATCH_ALL = (uint32_t)'%'; - - int prevEscape = 0; /* True if the previous character was uEsc */ - - while( 1 ){ - - /* Read (and consume) the next character from the input pattern. */ - uint32_t uPattern; - SQLITE_ICU_READ_UTF8(zPattern, uPattern); - if( uPattern==0 ) break; - - /* There are now 4 possibilities: - ** - ** 1. uPattern is an unescaped match-all character "%", - ** 2. uPattern is an unescaped match-one character "_", - ** 3. uPattern is an unescaped escape character, or - ** 4. uPattern is to be handled as an ordinary character - */ - if( uPattern==MATCH_ALL && !prevEscape && uPattern!=(uint32_t)uEsc ){ - /* Case 1. */ - uint8_t c; - - /* Skip any MATCH_ALL or MATCH_ONE characters that follow a - ** MATCH_ALL. For each MATCH_ONE, skip one character in the - ** test string. - */ - while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){ - if( c==MATCH_ONE ){ - if( *zString==0 ) return 0; - SQLITE_ICU_SKIP_UTF8(zString); - } - zPattern++; - } - - if( *zPattern==0 ) return 1; - - while( *zString ){ - if( icuLikeCompare(zPattern, zString, uEsc) ){ - return 1; - } - SQLITE_ICU_SKIP_UTF8(zString); - } - return 0; - - }else if( uPattern==MATCH_ONE && !prevEscape && uPattern!=(uint32_t)uEsc ){ - /* Case 2. */ - if( *zString==0 ) return 0; - SQLITE_ICU_SKIP_UTF8(zString); - - }else if( uPattern==(uint32_t)uEsc && !prevEscape ){ - /* Case 3. */ - prevEscape = 1; - - }else{ - /* Case 4. */ - uint32_t uString; - SQLITE_ICU_READ_UTF8(zString, uString); - uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT); - uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT); - if( uString!=uPattern ){ - return 0; - } - prevEscape = 0; - } - } - - return *zString==0; -} - -/* -** Implementation of the like() SQL function. This function implements -** the build-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 -** -** is implemented as like(B, A). If there is an escape character E, -** -** A LIKE B ESCAPE E -** -** is mapped to like(B, A, E). -*/ -static void icuLikeFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - const unsigned char *zA = sqlite3_value_text(argv[0]); - const unsigned char *zB = sqlite3_value_text(argv[1]); - UChar32 uEsc = 0; - - /* Limit the length of the LIKE or GLOB pattern to avoid problems - ** of deep recursion and N*N behavior in patternCompare(). - */ - if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){ - sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); - return; - } - - - if( argc==3 ){ - /* The escape character string must consist of a single UTF-8 character. - ** Otherwise, return an error. - */ - int nE= sqlite3_value_bytes(argv[2]); - const unsigned char *zE = sqlite3_value_text(argv[2]); - int i = 0; - if( zE==0 ) return; - U8_NEXT(zE, i, nE, uEsc); - if( i!=nE){ - sqlite3_result_error(context, - "ESCAPE expression must be a single character", -1); - return; - } - } - - if( zA && zB ){ - sqlite3_result_int(context, icuLikeCompare(zA, zB, uEsc)); - } -} - -/* -** Function to delete compiled regexp objects. Registered as -** a destructor function with sqlite3_set_auxdata(). -*/ -static void icuRegexpDelete(void *p){ - URegularExpression *pExpr = (URegularExpression *)p; - uregex_close(pExpr); -} - -/* -** Implementation of SQLite REGEXP operator. This scalar function takes -** two arguments. The first is a regular expression pattern to compile -** the second is a string to match against that pattern. If either -** argument is an SQL NULL, then NULL Is returned. Otherwise, the result -** is 1 if the string matches the pattern, or 0 otherwise. -** -** SQLite maps the regexp() function to the regexp() operator such -** that the following two are equivalent: -** -** zString REGEXP zPattern -** regexp(zPattern, zString) -** -** Uses the following ICU regexp APIs: -** -** uregex_open() -** uregex_matches() -** uregex_close() -*/ -static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ - UErrorCode status = U_ZERO_ERROR; - URegularExpression *pExpr; - UBool res; - const UChar *zString = sqlite3_value_text16(apArg[1]); - - (void)nArg; /* Unused parameter */ - - /* If the left hand side of the regexp operator is NULL, - ** then the result is also NULL. - */ - if( !zString ){ - return; - } - - pExpr = sqlite3_get_auxdata(p, 0); - if( !pExpr ){ - const UChar *zPattern = sqlite3_value_text16(apArg[0]); - if( !zPattern ){ - return; - } - pExpr = uregex_open(zPattern, -1, 0, 0, &status); - - if( U_SUCCESS(status) ){ - sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete); - pExpr = sqlite3_get_auxdata(p, 0); - } - if( !pExpr ){ - icuFunctionError(p, "uregex_open", status); - return; - } - } - - /* Configure the text that the regular expression operates on. */ - uregex_setText(pExpr, zString, -1, &status); - if( !U_SUCCESS(status) ){ - icuFunctionError(p, "uregex_setText", status); - return; - } - - /* Attempt the match */ - res = uregex_matches(pExpr, 0, &status); - if( !U_SUCCESS(status) ){ - icuFunctionError(p, "uregex_matches", status); - return; - } - - /* Set the text that the regular expression operates on to a NULL - ** pointer. This is not really necessary, but it is tidier than - ** leaving the regular expression object configured with an invalid - ** pointer after this function returns. - */ - uregex_setText(pExpr, 0, 0, &status); - - /* Return 1 or 0. */ - sqlite3_result_int(p, res ? 1 : 0); -} - -/* -** Implementations of scalar functions for case mapping - upper() and -** lower(). Function upper() converts its input to upper-case (ABC). -** Function lower() converts to lower-case (abc). -** -** ICU provides two types of case mapping, "general" case mapping and -** "language specific". Refer to ICU documentation for the differences -** between the two. -** -** To utilise "general" case mapping, the upper() or lower() scalar -** functions are invoked with one argument: -** -** upper('ABC') -> 'abc' -** lower('abc') -> 'ABC' -** -** To access ICU "language specific" case mapping, upper() or lower() -** should be invoked with two arguments. The second argument is the name -** of the locale to use. Passing an empty string ("") or SQL NULL value -** as the second argument is the same as invoking the 1 argument version -** of upper() or lower(). -** -** lower('I', 'en_us') -> 'i' -** lower('I', 'tr_tr') -> '\u131' (small dotless i) -** -** http://www.icu-project.org/userguide/posix.html#case_mappings -*/ -static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ - const UChar *zInput; /* Pointer to input string */ - UChar *zOutput = 0; /* Pointer to output buffer */ - int nInput; /* Size of utf-16 input string in bytes */ - int nOut; /* Size of output buffer in bytes */ - int cnt; - int bToUpper; /* True for toupper(), false for tolower() */ - UErrorCode status; - const char *zLocale = 0; - - assert(nArg==1 || nArg==2); - bToUpper = (sqlite3_user_data(p)!=0); - if( nArg==2 ){ - zLocale = (const char *)sqlite3_value_text(apArg[1]); - } - - zInput = sqlite3_value_text16(apArg[0]); - if( !zInput ){ - return; - } - nOut = nInput = sqlite3_value_bytes16(apArg[0]); - if( nOut==0 ){ - sqlite3_result_text16(p, "", 0, SQLITE_STATIC); - return; - } - - for(cnt=0; cnt<2; cnt++){ - UChar *zNew = sqlite3_realloc(zOutput, nOut); - if( zNew==0 ){ - sqlite3_free(zOutput); - sqlite3_result_error_nomem(p); - return; - } - zOutput = zNew; - status = U_ZERO_ERROR; - if( bToUpper ){ - nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); - }else{ - nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); - } - - if( U_SUCCESS(status) ){ - sqlite3_result_text16(p, zOutput, nOut, xFree); - }else if( status==U_BUFFER_OVERFLOW_ERROR ){ - assert( cnt==0 ); - continue; - }else{ - icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status); - } - return; - } - assert( 0 ); /* Unreachable */ -} - -#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ - -/* -** Collation sequence destructor function. The pCtx argument points to -** a UCollator structure previously allocated using ucol_open(). -*/ -static void icuCollationDel(void *pCtx){ - UCollator *p = (UCollator *)pCtx; - ucol_close(p); -} - -/* -** Collation sequence comparison function. The pCtx argument points to -** a UCollator structure previously allocated using ucol_open(). -*/ -static int icuCollationColl( - void *pCtx, - int nLeft, - const void *zLeft, - int nRight, - const void *zRight -){ - UCollationResult res; - UCollator *p = (UCollator *)pCtx; - res = ucol_strcoll(p, (UChar *)zLeft, nLeft/2, (UChar *)zRight, nRight/2); - switch( res ){ - case UCOL_LESS: return -1; - case UCOL_GREATER: return +1; - case UCOL_EQUAL: return 0; - } - assert(!"Unexpected return value from ucol_strcoll()"); - return 0; -} - -/* -** Implementation of the scalar function icu_load_collation(). -** -** This scalar function is used to add ICU collation based collation -** types to an SQLite database connection. It is intended to be called -** as follows: -** -** SELECT icu_load_collation(, ); -** -** Where is a string containing an ICU locale identifier (i.e. -** "en_AU", "tr_TR" etc.) and is the name of the -** collation sequence to create. -*/ -static void icuLoadCollation( - sqlite3_context *p, - int nArg, - sqlite3_value **apArg -){ - sqlite3 *db = (sqlite3 *)sqlite3_user_data(p); - UErrorCode status = U_ZERO_ERROR; - const char *zLocale; /* Locale identifier - (eg. "jp_JP") */ - const char *zName; /* SQL Collation sequence name (eg. "japanese") */ - UCollator *pUCollator; /* ICU library collation object */ - int rc; /* Return code from sqlite3_create_collation_x() */ - - assert(nArg==2); - (void)nArg; /* Unused parameter */ - zLocale = (const char *)sqlite3_value_text(apArg[0]); - zName = (const char *)sqlite3_value_text(apArg[1]); - - if( !zLocale || !zName ){ - return; - } - - pUCollator = ucol_open(zLocale, &status); - if( !U_SUCCESS(status) ){ - icuFunctionError(p, "ucol_open", status); - return; - } - assert(p); - - rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator, - icuCollationColl, icuCollationDel - ); - if( rc!=SQLITE_OK ){ - ucol_close(pUCollator); - sqlite3_result_error(p, "Error registering collation function", -1); - } -} - -/* -** Register the ICU extension functions with database db. -*/ -SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){ -# define SQLITEICU_EXTRAFLAGS (SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS) - static const struct IcuScalar { - const char *zName; /* Function name */ - unsigned char nArg; /* Number of arguments */ - unsigned int enc; /* Optimal text encoding */ - unsigned char iContext; /* sqlite3_user_data() context */ - void (*xFunc)(sqlite3_context*,int,sqlite3_value**); - } scalars[] = { - {"icu_load_collation",2,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}, - {"lower", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, - {"upper", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, - {"upper", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, - {"lower", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, - {"lower", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, - {"upper", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, - {"upper", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, - {"like", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc}, - {"like", 3, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc}, -#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ - }; - int rc = SQLITE_OK; - int i; - - for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){ - const struct IcuScalar *p = &scalars[i]; - rc = sqlite3_create_function( - db, p->zName, p->nArg, p->enc, - p->iContext ? (void*)db : (void*)0, - p->xFunc, 0, 0 - ); - } - - return rc; -} - -#if !SQLITE_CORE -#ifdef _WIN32 -__declspec(dllexport) -#endif -SQLITE_API int sqlite3_icu_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi -){ - SQLITE_EXTENSION_INIT2(pApi) - return sqlite3IcuInit(db); -} -#endif - -#endif - -/************** End of icu.c *************************************************/ -/************** Begin file fts3_icu.c ****************************************/ -/* -** 2007 June 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** This file implements a tokenizer for fts3 based on the ICU library. -*/ -/* #include "fts3Int.h" */ -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) -#ifdef SQLITE_ENABLE_ICU - -/* #include */ -/* #include */ -/* #include "fts3_tokenizer.h" */ - -#include -/* #include */ -/* #include */ -#include - -typedef struct IcuTokenizer IcuTokenizer; -typedef struct IcuCursor IcuCursor; - -struct IcuTokenizer { - sqlite3_tokenizer base; - char *zLocale; -}; - -struct IcuCursor { - sqlite3_tokenizer_cursor base; - - UBreakIterator *pIter; /* ICU break-iterator object */ - int nChar; /* Number of UChar elements in pInput */ - UChar *aChar; /* Copy of input using utf-16 encoding */ - int *aOffset; /* Offsets of each character in utf-8 input */ - - int nBuffer; - char *zBuffer; - - int iToken; -}; - -/* -** Create a new tokenizer instance. -*/ -static int icuCreate( - int argc, /* Number of entries in argv[] */ - const char * const *argv, /* Tokenizer creation arguments */ - sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ -){ - IcuTokenizer *p; - int n = 0; - - if( argc>0 ){ - n = strlen(argv[0])+1; - } - p = (IcuTokenizer *)sqlite3_malloc64(sizeof(IcuTokenizer)+n); - if( !p ){ - return SQLITE_NOMEM; - } - memset(p, 0, sizeof(IcuTokenizer)); - - if( n ){ - p->zLocale = (char *)&p[1]; - memcpy(p->zLocale, argv[0], n); - } - - *ppTokenizer = (sqlite3_tokenizer *)p; - - return SQLITE_OK; -} - -/* -** Destroy a tokenizer -*/ -static int icuDestroy(sqlite3_tokenizer *pTokenizer){ - IcuTokenizer *p = (IcuTokenizer *)pTokenizer; - sqlite3_free(p); - return SQLITE_OK; -} - -/* -** Prepare to begin tokenizing a particular string. The input -** string to be tokenized is pInput[0..nBytes-1]. A cursor -** used to incrementally tokenize this string is returned in -** *ppCursor. -*/ -static int icuOpen( - sqlite3_tokenizer *pTokenizer, /* The tokenizer */ - const char *zInput, /* Input string */ - int nInput, /* Length of zInput in bytes */ - sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ -){ - IcuTokenizer *p = (IcuTokenizer *)pTokenizer; - IcuCursor *pCsr; - - const int32_t opt = U_FOLD_CASE_DEFAULT; - UErrorCode status = U_ZERO_ERROR; - int nChar; - - UChar32 c; - int iInput = 0; - int iOut = 0; - - *ppCursor = 0; - - if( zInput==0 ){ - nInput = 0; - zInput = ""; - }else if( nInput<0 ){ - nInput = strlen(zInput); - } - nChar = nInput+1; - pCsr = (IcuCursor *)sqlite3_malloc64( - sizeof(IcuCursor) + /* IcuCursor */ - ((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */ - (nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */ - ); - if( !pCsr ){ - return SQLITE_NOMEM; - } - memset(pCsr, 0, sizeof(IcuCursor)); - pCsr->aChar = (UChar *)&pCsr[1]; - pCsr->aOffset = (int *)&pCsr->aChar[(nChar+3)&~3]; - - pCsr->aOffset[iOut] = iInput; - U8_NEXT(zInput, iInput, nInput, c); - while( c>0 ){ - int isError = 0; - c = u_foldCase(c, opt); - U16_APPEND(pCsr->aChar, iOut, nChar, c, isError); - if( isError ){ - sqlite3_free(pCsr); - return SQLITE_ERROR; - } - pCsr->aOffset[iOut] = iInput; - - if( iInputpIter = ubrk_open(UBRK_WORD, p->zLocale, pCsr->aChar, iOut, &status); - if( !U_SUCCESS(status) ){ - sqlite3_free(pCsr); - return SQLITE_ERROR; - } - pCsr->nChar = iOut; - - ubrk_first(pCsr->pIter); - *ppCursor = (sqlite3_tokenizer_cursor *)pCsr; - return SQLITE_OK; -} - -/* -** Close a tokenization cursor previously opened by a call to icuOpen(). -*/ -static int icuClose(sqlite3_tokenizer_cursor *pCursor){ - IcuCursor *pCsr = (IcuCursor *)pCursor; - ubrk_close(pCsr->pIter); - sqlite3_free(pCsr->zBuffer); - sqlite3_free(pCsr); - return SQLITE_OK; -} - -/* -** Extract the next token from a tokenization cursor. -*/ -static int icuNext( - sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by simpleOpen */ - const char **ppToken, /* OUT: *ppToken is the token text */ - int *pnBytes, /* OUT: Number of bytes in token */ - int *piStartOffset, /* OUT: Starting offset of token */ - int *piEndOffset, /* OUT: Ending offset of token */ - int *piPosition /* OUT: Position integer of token */ -){ - IcuCursor *pCsr = (IcuCursor *)pCursor; - - int iStart = 0; - int iEnd = 0; - int nByte = 0; - - while( iStart==iEnd ){ - UChar32 c; - - iStart = ubrk_current(pCsr->pIter); - iEnd = ubrk_next(pCsr->pIter); - if( iEnd==UBRK_DONE ){ - return SQLITE_DONE; - } - - while( iStartaChar, iWhite, pCsr->nChar, c); - if( u_isspace(c) ){ - iStart = iWhite; - }else{ - break; - } - } - assert(iStart<=iEnd); - } - - do { - UErrorCode status = U_ZERO_ERROR; - if( nByte ){ - char *zNew = sqlite3_realloc(pCsr->zBuffer, nByte); - if( !zNew ){ - return SQLITE_NOMEM; - } - pCsr->zBuffer = zNew; - pCsr->nBuffer = nByte; - } - - u_strToUTF8( - pCsr->zBuffer, pCsr->nBuffer, &nByte, /* Output vars */ - &pCsr->aChar[iStart], iEnd-iStart, /* Input vars */ - &status /* Output success/failure */ - ); - } while( nByte>pCsr->nBuffer ); - - *ppToken = pCsr->zBuffer; - *pnBytes = nByte; - *piStartOffset = pCsr->aOffset[iStart]; - *piEndOffset = pCsr->aOffset[iEnd]; - *piPosition = pCsr->iToken++; - - return SQLITE_OK; -} - -/* -** The set of routines that implement the simple tokenizer -*/ -static const sqlite3_tokenizer_module icuTokenizerModule = { - 0, /* iVersion */ - icuCreate, /* xCreate */ - icuDestroy, /* xCreate */ - icuOpen, /* xOpen */ - icuClose, /* xClose */ - icuNext, /* xNext */ - 0, /* xLanguageid */ -}; - -/* -** Set *ppModule to point at the implementation of the ICU tokenizer. -*/ -SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( - sqlite3_tokenizer_module const**ppModule -){ - *ppModule = &icuTokenizerModule; -} - -#endif /* defined(SQLITE_ENABLE_ICU) */ -#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ - -/************** End of fts3_icu.c ********************************************/ /************** Begin file sqlite3rbu.c **************************************/ /* ** 2014 August 30 @@ -247837,15 +246981,6 @@ static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime #endif // hw export the symbols #ifdef SQLITE_EXPORT_SYMBOLS -/************** Begin hw export the symbols *****************************************/ -#if defined(__GNUC__) -# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) -#elif defined(_MSC_VER) -# define EXPORT_SYMBOLS __declspec(dllexport) -#else -# define EXPORT_SYMBOLS -#endif - struct sqlite3_api_routines_hw { int (*initialize)(); int (*config)(int,...); diff --git a/src/sqlite3icu.c b/src/sqlite3icu.c new file mode 100644 index 0000000..6a581fc --- /dev/null +++ b/src/sqlite3icu.c @@ -0,0 +1,892 @@ +/****************************************************************************** +** This file is an amalgamation of many separate C source files from SQLite +** version 3.40.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 +** of 5% or more are commonly seen when SQLite is compiled as a single +** translation unit. +** +** This file is all you need to compile SQLite. To use SQLite in other +** programs, you need this file and the "sqlite3.h" header file that defines +** the programming interface to the SQLite library. (If you do not have +** the "sqlite3.h" header file at hand, you will find a copy embedded within +** the text of this file. Search for "Begin file sqlite3.h" to find the start +** of the embedded sqlite3.h header file.) Additional code files may be needed +** if you want a wrapper to interface SQLite with your choice of programming +** language. The code for the "sqlite3" command-line shell is also in a +** separate file. This file contains only code for the core SQLite library. +*/ +/* +** 2019.09.02-Complete codec logic for encryption and decryption. +** Huawei Technologies Co, Ltd. +*/ +/************** Begin file icu.c *********************************************/ +/* +** 2007 May 6 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $ +** +** This file implements an integration between the ICU library +** ("International Components for Unicode", an open-source library +** for handling unicode data) and SQLite. The integration uses +** ICU to provide the following to SQLite: +** +** * An implementation of the SQL regexp() function (and hence REGEXP +** operator) using the ICU uregex_XX() APIs. +** +** * Implementations of the SQL scalar upper() and lower() functions +** for case mapping. +** +** * Integration of ICU and SQLite collation sequences. +** +** * An implementation of the LIKE operator that uses ICU to +** provide case-independent matching. +*/ +#include +#include +#include +#include +#include + +#include "sqlite3icu.h" +#include "sqlite3.h" + +#ifdef HARMONY_OS +#include "common/unicode/putil.h" +#endif + +#if !defined(SQLITE_CORE) \ + || defined(SQLITE_ENABLE_ICU) \ + || defined(SQLITE_ENABLE_ICU_COLLATIONS) + +/* Include ICU headers */ +#include +#include +#include +#include + +#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) + /* This case when the file really is being compiled as a loadable + ** extension */ +# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; +# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; +# define SQLITE_EXTENSION_INIT3 \ + extern const sqlite3_api_routines *sqlite3_api; +#else + /* 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 */ +# define SQLITE_EXTENSION_INIT3 /*no-op*/ +#endif + +/* #include */ + +#ifndef SQLITE_CORE +/* #include "sqlite3ext.h" */ + SQLITE_EXTENSION_INIT1 +#else +/* #include "sqlite3.h" */ +#endif + +// hw export the symbols +#ifdef SQLITE_EXPORT_SYMBOLS +#if defined(__GNUC__) +# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) +#elif defined(_MSC_VER) +# define EXPORT_SYMBOLS __declspec(dllexport) +#else +# define EXPORT_SYMBOLS +#endif +#endif + +EXPORT_SYMBOLS SQLITE_API int sqlite3IcuInit(sqlite3 *db); +#ifdef SQLITE_ENABLE_ICU +EXPORT_SYMBOLS SQLITE_API void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); +#endif +/* +** This function is called when an ICU function called from within +** the implementation of an SQL scalar function returns an error. +** +** The scalar function context passed as the first argument is +** loaded with an error message based on the following two args. +*/ +static void icuFunctionError( + sqlite3_context *pCtx, /* SQLite scalar function context */ + const char *zName, /* Name of ICU function that failed */ + UErrorCode e /* Error code returned by ICU function */ +){ + char zBuf[128]; + sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e)); + zBuf[127] = '\0'; + sqlite3_result_error(pCtx, zBuf, -1); +} + +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) + +/* +** Maximum length (in bytes) of the pattern in a LIKE or GLOB +** operator. +*/ +#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH +# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000 +#endif + +/* +** Version of sqlite3_free() that is always a function, never a macro. +*/ +static void xFree(void *p){ + sqlite3_free(p); +} + +/* +** This lookup table is used to help decode the first byte of +** a multi-byte UTF8 character. It is copied here from SQLite source +** code file utf8.c. +*/ +static const unsigned char icuUtf8Trans1[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, +}; + +#define SQLITE_ICU_READ_UTF8(zIn, c) \ + c = *(zIn++); \ + if( c>=0xc0 ){ \ + c = icuUtf8Trans1[c-0xc0]; \ + while( (*zIn & 0xc0)==0x80 ){ \ + c = (c<<6) + (0x3f & *(zIn++)); \ + } \ + } + +#define SQLITE_ICU_SKIP_UTF8(zIn) \ + assert( *zIn ); \ + if( *(zIn++)>=0xc0 ){ \ + while( (*zIn & 0xc0)==0x80 ){zIn++;} \ + } + + +/* +** Compare two UTF-8 strings for equality where the first string is +** a "LIKE" expression. Return true (1) if they are the same and +** false (0) if they are different. +*/ +static int icuLikeCompare( + const uint8_t *zPattern, /* LIKE pattern */ + const uint8_t *zString, /* The UTF-8 string to compare against */ + const UChar32 uEsc /* The escape character */ +){ + static const uint32_t MATCH_ONE = (uint32_t)'_'; + static const uint32_t MATCH_ALL = (uint32_t)'%'; + + int prevEscape = 0; /* True if the previous character was uEsc */ + + while( 1 ){ + + /* Read (and consume) the next character from the input pattern. */ + uint32_t uPattern; + SQLITE_ICU_READ_UTF8(zPattern, uPattern); + if( uPattern==0 ) break; + + /* There are now 4 possibilities: + ** + ** 1. uPattern is an unescaped match-all character "%", + ** 2. uPattern is an unescaped match-one character "_", + ** 3. uPattern is an unescaped escape character, or + ** 4. uPattern is to be handled as an ordinary character + */ + if( uPattern==MATCH_ALL && !prevEscape && uPattern!=(uint32_t)uEsc ){ + /* Case 1. */ + uint8_t c; + + /* Skip any MATCH_ALL or MATCH_ONE characters that follow a + ** MATCH_ALL. For each MATCH_ONE, skip one character in the + ** test string. + */ + while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){ + if( c==MATCH_ONE ){ + if( *zString==0 ) return 0; + SQLITE_ICU_SKIP_UTF8(zString); + } + zPattern++; + } + + if( *zPattern==0 ) return 1; + + while( *zString ){ + if( icuLikeCompare(zPattern, zString, uEsc) ){ + return 1; + } + SQLITE_ICU_SKIP_UTF8(zString); + } + return 0; + + }else if( uPattern==MATCH_ONE && !prevEscape && uPattern!=(uint32_t)uEsc ){ + /* Case 2. */ + if( *zString==0 ) return 0; + SQLITE_ICU_SKIP_UTF8(zString); + + }else if( uPattern==(uint32_t)uEsc && !prevEscape ){ + /* Case 3. */ + prevEscape = 1; + + }else{ + /* Case 4. */ + uint32_t uString; + SQLITE_ICU_READ_UTF8(zString, uString); + uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT); + uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT); + if( uString!=uPattern ){ + return 0; + } + prevEscape = 0; + } + } + + return *zString==0; +} + +/* +** Implementation of the like() SQL function. This function implements +** the build-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 +** +** is implemented as like(B, A). If there is an escape character E, +** +** A LIKE B ESCAPE E +** +** is mapped to like(B, A, E). +*/ +static void icuLikeFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const unsigned char *zA = sqlite3_value_text(argv[0]); + const unsigned char *zB = sqlite3_value_text(argv[1]); + UChar32 uEsc = 0; + + /* Limit the length of the LIKE or GLOB pattern to avoid problems + ** of deep recursion and N*N behavior in patternCompare(). + */ + if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){ + sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); + return; + } + + + if( argc==3 ){ + /* The escape character string must consist of a single UTF-8 character. + ** Otherwise, return an error. + */ + int nE= sqlite3_value_bytes(argv[2]); + const unsigned char *zE = sqlite3_value_text(argv[2]); + int i = 0; + if( zE==0 ) return; + U8_NEXT(zE, i, nE, uEsc); + if( i!=nE){ + sqlite3_result_error(context, + "ESCAPE expression must be a single character", -1); + return; + } + } + + if( zA && zB ){ + sqlite3_result_int(context, icuLikeCompare(zA, zB, uEsc)); + } +} + +/* +** Function to delete compiled regexp objects. Registered as +** a destructor function with sqlite3_set_auxdata(). +*/ +static void icuRegexpDelete(void *p){ + URegularExpression *pExpr = (URegularExpression *)p; + uregex_close(pExpr); +} + +/* +** Implementation of SQLite REGEXP operator. This scalar function takes +** two arguments. The first is a regular expression pattern to compile +** the second is a string to match against that pattern. If either +** argument is an SQL NULL, then NULL Is returned. Otherwise, the result +** is 1 if the string matches the pattern, or 0 otherwise. +** +** SQLite maps the regexp() function to the regexp() operator such +** that the following two are equivalent: +** +** zString REGEXP zPattern +** regexp(zPattern, zString) +** +** Uses the following ICU regexp APIs: +** +** uregex_open() +** uregex_matches() +** uregex_close() +*/ +static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ + UErrorCode status = U_ZERO_ERROR; + URegularExpression *pExpr; + UBool res; + const UChar *zString = sqlite3_value_text16(apArg[1]); + + (void)nArg; /* Unused parameter */ + + /* If the left hand side of the regexp operator is NULL, + ** then the result is also NULL. + */ + if( !zString ){ + return; + } + + pExpr = sqlite3_get_auxdata(p, 0); + if( !pExpr ){ + const UChar *zPattern = sqlite3_value_text16(apArg[0]); + if( !zPattern ){ + return; + } + pExpr = uregex_open(zPattern, -1, 0, 0, &status); + + if( U_SUCCESS(status) ){ + sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete); + pExpr = sqlite3_get_auxdata(p, 0); + } + if( !pExpr ){ + icuFunctionError(p, "uregex_open", status); + return; + } + } + + /* Configure the text that the regular expression operates on. */ + uregex_setText(pExpr, zString, -1, &status); + if( !U_SUCCESS(status) ){ + icuFunctionError(p, "uregex_setText", status); + return; + } + + /* Attempt the match */ + res = uregex_matches(pExpr, 0, &status); + if( !U_SUCCESS(status) ){ + icuFunctionError(p, "uregex_matches", status); + return; + } + + /* Set the text that the regular expression operates on to a NULL + ** pointer. This is not really necessary, but it is tidier than + ** leaving the regular expression object configured with an invalid + ** pointer after this function returns. + */ + uregex_setText(pExpr, 0, 0, &status); + + /* Return 1 or 0. */ + sqlite3_result_int(p, res ? 1 : 0); +} + +/* +** Implementations of scalar functions for case mapping - upper() and +** lower(). Function upper() converts its input to upper-case (ABC). +** Function lower() converts to lower-case (abc). +** +** ICU provides two types of case mapping, "general" case mapping and +** "language specific". Refer to ICU documentation for the differences +** between the two. +** +** To utilise "general" case mapping, the upper() or lower() scalar +** functions are invoked with one argument: +** +** upper('ABC') -> 'abc' +** lower('abc') -> 'ABC' +** +** To access ICU "language specific" case mapping, upper() or lower() +** should be invoked with two arguments. The second argument is the name +** of the locale to use. Passing an empty string ("") or SQL NULL value +** as the second argument is the same as invoking the 1 argument version +** of upper() or lower(). +** +** lower('I', 'en_us') -> 'i' +** lower('I', 'tr_tr') -> '\u131' (small dotless i) +** +** http://www.icu-project.org/userguide/posix.html#case_mappings +*/ +static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ + const UChar *zInput; /* Pointer to input string */ + UChar *zOutput = 0; /* Pointer to output buffer */ + int nInput; /* Size of utf-16 input string in bytes */ + int nOut; /* Size of output buffer in bytes */ + int cnt; + int bToUpper; /* True for toupper(), false for tolower() */ + UErrorCode status; + const char *zLocale = 0; + + assert(nArg==1 || nArg==2); + bToUpper = (sqlite3_user_data(p)!=0); + if( nArg==2 ){ + zLocale = (const char *)sqlite3_value_text(apArg[1]); + } + + zInput = sqlite3_value_text16(apArg[0]); + if( !zInput ){ + return; + } + nOut = nInput = sqlite3_value_bytes16(apArg[0]); + if( nOut==0 ){ + sqlite3_result_text16(p, "", 0, SQLITE_STATIC); + return; + } + + for(cnt=0; cnt<2; cnt++){ + UChar *zNew = sqlite3_realloc(zOutput, nOut); + if( zNew==0 ){ + sqlite3_free(zOutput); + sqlite3_result_error_nomem(p); + return; + } + zOutput = zNew; + status = U_ZERO_ERROR; + if( bToUpper ){ + nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); + }else{ + nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); + } + + if( U_SUCCESS(status) ){ + sqlite3_result_text16(p, zOutput, nOut, xFree); + }else if( status==U_BUFFER_OVERFLOW_ERROR ){ + assert( cnt==0 ); + continue; + }else{ + icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status); + } + return; + } + assert( 0 ); /* Unreachable */ +} + +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ + +/* +** Collation sequence destructor function. The pCtx argument points to +** a UCollator structure previously allocated using ucol_open(). +*/ +static void icuCollationDel(void *pCtx){ + UCollator *p = (UCollator *)pCtx; + ucol_close(p); +} + +/* +** Collation sequence comparison function. The pCtx argument points to +** a UCollator structure previously allocated using ucol_open(). +*/ +static int icuCollationColl( + void *pCtx, + int nLeft, + const void *zLeft, + int nRight, + const void *zRight +){ + UCollationResult res; + UCollator *p = (UCollator *)pCtx; + res = ucol_strcoll(p, (UChar *)zLeft, nLeft/2, (UChar *)zRight, nRight/2); + switch( res ){ + case UCOL_LESS: return -1; + case UCOL_GREATER: return +1; + case UCOL_EQUAL: return 0; + } + assert(!"Unexpected return value from ucol_strcoll()"); + return 0; +} + +/* +** Implementation of the scalar function icu_load_collation(). +** +** This scalar function is used to add ICU collation based collation +** types to an SQLite database connection. It is intended to be called +** as follows: +** +** SELECT icu_load_collation(, ); +** +** Where is a string containing an ICU locale identifier (i.e. +** "en_AU", "tr_TR" etc.) and is the name of the +** collation sequence to create. +*/ +static void icuLoadCollation( + sqlite3_context *p, + int nArg, + sqlite3_value **apArg +){ + sqlite3 *db = (sqlite3 *)sqlite3_user_data(p); + UErrorCode status = U_ZERO_ERROR; + const char *zLocale; /* Locale identifier - (eg. "jp_JP") */ + const char *zName; /* SQL Collation sequence name (eg. "japanese") */ + UCollator *pUCollator; /* ICU library collation object */ + int rc; /* Return code from sqlite3_create_collation_x() */ + + assert(nArg==2); + (void)nArg; /* Unused parameter */ + zLocale = (const char *)sqlite3_value_text(apArg[0]); + zName = (const char *)sqlite3_value_text(apArg[1]); + + if( !zLocale || !zName ){ + return; + } + + pUCollator = ucol_open(zLocale, &status); + if( !U_SUCCESS(status) ){ + icuFunctionError(p, "ucol_open", status); + return; + } + assert(p); + + rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator, + icuCollationColl, icuCollationDel + ); + if( rc!=SQLITE_OK ){ + ucol_close(pUCollator); + sqlite3_result_error(p, "Error registering collation function", -1); + } +} + +/* +** Register the ICU extension functions with database db. +*/ +EXPORT_SYMBOLS SQLITE_API int sqlite3IcuInit(sqlite3 *db){ +# define SQLITEICU_EXTRAFLAGS (SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS) + static const struct IcuScalar { + const char *zName; /* Function name */ + unsigned char nArg; /* Number of arguments */ + unsigned int enc; /* Optimal text encoding */ + unsigned char iContext; /* sqlite3_user_data() context */ + void (*xFunc)(sqlite3_context*,int,sqlite3_value**); + } scalars[] = { + {"icu_load_collation",2,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}, + {"lower", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, + {"upper", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, + {"upper", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, + {"lower", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, + {"lower", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, + {"upper", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, + {"upper", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, + {"like", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc}, + {"like", 3, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc}, +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ + }; +#ifdef HARMONY_OS + extern void SetOhosIcuDirectory(); + SetOhosIcuDirectory(); +#endif + int rc = SQLITE_OK; + int i; + + for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){ + const struct IcuScalar *p = &scalars[i]; + rc = sqlite3_create_function( + db, p->zName, p->nArg, p->enc, + p->iContext ? (void*)db : (void*)0, + p->xFunc, 0, 0 + ); + } + + return rc; +} + +#if !SQLITE_CORE +#ifdef _WIN32 +__declspec(dllexport) +#endif +SQLITE_API int sqlite3_icu_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + SQLITE_EXTENSION_INIT2(pApi) + return sqlite3IcuInit(db); +} +#endif + +#endif + +/************** End of icu.c *************************************************/ +/************** Begin file fts3_icu.c ****************************************/ +/* +** 2007 June 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file implements a tokenizer for fts3 based on the ICU library. +*/ +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) +#ifdef SQLITE_ENABLE_ICU + +/* #include */ +/* #include */ +/* #include "fts3_tokenizer.h" */ + +#include +/* #include */ +/* #include */ +#include + +typedef struct IcuTokenizer IcuTokenizer; +typedef struct IcuCursor IcuCursor; + +struct IcuTokenizer { + sqlite3_tokenizer base; + char *zLocale; +}; + +struct IcuCursor { + sqlite3_tokenizer_cursor base; + + UBreakIterator *pIter; /* ICU break-iterator object */ + int nChar; /* Number of UChar elements in pInput */ + UChar *aChar; /* Copy of input using utf-16 encoding */ + int *aOffset; /* Offsets of each character in utf-8 input */ + + int nBuffer; + char *zBuffer; + + int iToken; +}; + +/* +** Create a new tokenizer instance. +*/ +static int icuCreate( + int argc, /* Number of entries in argv[] */ + const char * const *argv, /* Tokenizer creation arguments */ + sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ +){ + IcuTokenizer *p; + int n = 0; + + if( argc>0 ){ + n = strlen(argv[0])+1; + } + p = (IcuTokenizer *)sqlite3_malloc64(sizeof(IcuTokenizer)+n); + if( !p ){ + return SQLITE_NOMEM; + } + memset(p, 0, sizeof(IcuTokenizer)); + + if( n ){ + p->zLocale = (char *)&p[1]; + memcpy(p->zLocale, argv[0], n); + } + + *ppTokenizer = (sqlite3_tokenizer *)p; + + return SQLITE_OK; +} + +/* +** Destroy a tokenizer +*/ +static int icuDestroy(sqlite3_tokenizer *pTokenizer){ + IcuTokenizer *p = (IcuTokenizer *)pTokenizer; + sqlite3_free(p); + return SQLITE_OK; +} + +/* +** Prepare to begin tokenizing a particular string. The input +** string to be tokenized is pInput[0..nBytes-1]. A cursor +** used to incrementally tokenize this string is returned in +** *ppCursor. +*/ +static int icuOpen( + sqlite3_tokenizer *pTokenizer, /* The tokenizer */ + const char *zInput, /* Input string */ + int nInput, /* Length of zInput in bytes */ + sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ +){ + IcuTokenizer *p = (IcuTokenizer *)pTokenizer; + IcuCursor *pCsr; + + const int32_t opt = U_FOLD_CASE_DEFAULT; + UErrorCode status = U_ZERO_ERROR; + int nChar; + + UChar32 c; + int iInput = 0; + int iOut = 0; + + *ppCursor = 0; + + if( zInput==0 ){ + nInput = 0; + zInput = ""; + }else if( nInput<0 ){ + nInput = strlen(zInput); + } + nChar = nInput+1; + pCsr = (IcuCursor *)sqlite3_malloc64( + sizeof(IcuCursor) + /* IcuCursor */ + ((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */ + (nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */ + ); + if( !pCsr ){ + return SQLITE_NOMEM; + } + memset(pCsr, 0, sizeof(IcuCursor)); + pCsr->aChar = (UChar *)&pCsr[1]; + pCsr->aOffset = (int *)&pCsr->aChar[(nChar+3)&~3]; + + pCsr->aOffset[iOut] = iInput; + U8_NEXT(zInput, iInput, nInput, c); + while( c>0 ){ + int isError = 0; + c = u_foldCase(c, opt); + U16_APPEND(pCsr->aChar, iOut, nChar, c, isError); + if( isError ){ + sqlite3_free(pCsr); + return SQLITE_ERROR; + } + pCsr->aOffset[iOut] = iInput; + + if( iInputpIter = ubrk_open(UBRK_WORD, p->zLocale, pCsr->aChar, iOut, &status); + if( !U_SUCCESS(status) ){ + sqlite3_free(pCsr); + return SQLITE_ERROR; + } + pCsr->nChar = iOut; + + ubrk_first(pCsr->pIter); + *ppCursor = (sqlite3_tokenizer_cursor *)pCsr; + return SQLITE_OK; +} + +/* +** Close a tokenization cursor previously opened by a call to icuOpen(). +*/ +static int icuClose(sqlite3_tokenizer_cursor *pCursor){ + IcuCursor *pCsr = (IcuCursor *)pCursor; + ubrk_close(pCsr->pIter); + sqlite3_free(pCsr->zBuffer); + sqlite3_free(pCsr); + return SQLITE_OK; +} + +/* +** Extract the next token from a tokenization cursor. +*/ +static int icuNext( + sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by simpleOpen */ + const char **ppToken, /* OUT: *ppToken is the token text */ + int *pnBytes, /* OUT: Number of bytes in token */ + int *piStartOffset, /* OUT: Starting offset of token */ + int *piEndOffset, /* OUT: Ending offset of token */ + int *piPosition /* OUT: Position integer of token */ +){ + IcuCursor *pCsr = (IcuCursor *)pCursor; + + int iStart = 0; + int iEnd = 0; + int nByte = 0; + + while( iStart==iEnd ){ + UChar32 c; + + iStart = ubrk_current(pCsr->pIter); + iEnd = ubrk_next(pCsr->pIter); + if( iEnd==UBRK_DONE ){ + return SQLITE_DONE; + } + + while( iStartaChar, iWhite, pCsr->nChar, c); + if( u_isspace(c) ){ + iStart = iWhite; + }else{ + break; + } + } + assert(iStart<=iEnd); + } + + do { + UErrorCode status = U_ZERO_ERROR; + if( nByte ){ + char *zNew = sqlite3_realloc(pCsr->zBuffer, nByte); + if( !zNew ){ + return SQLITE_NOMEM; + } + pCsr->zBuffer = zNew; + pCsr->nBuffer = nByte; + } + + u_strToUTF8( + pCsr->zBuffer, pCsr->nBuffer, &nByte, /* Output vars */ + &pCsr->aChar[iStart], iEnd-iStart, /* Input vars */ + &status /* Output success/failure */ + ); + } while( nByte>pCsr->nBuffer ); + + *ppToken = pCsr->zBuffer; + *pnBytes = nByte; + *piStartOffset = pCsr->aOffset[iStart]; + *piEndOffset = pCsr->aOffset[iEnd]; + *piPosition = pCsr->iToken++; + + return SQLITE_OK; +} + +/* +** The set of routines that implement the simple tokenizer +*/ +static const sqlite3_tokenizer_module icuTokenizerModule = { + 0, /* iVersion */ + icuCreate, /* xCreate */ + icuDestroy, /* xCreate */ + icuOpen, /* xOpen */ + icuClose, /* xClose */ + icuNext, /* xNext */ + 0, /* xLanguageid */ +}; + +/* +** Set *ppModule to point at the implementation of the ICU tokenizer. +*/ +EXPORT_SYMBOLS SQLITE_API void sqlite3Fts3IcuTokenizerModule( + sqlite3_tokenizer_module const**ppModule +){ + *ppModule = &icuTokenizerModule; +} + +#endif /* defined(SQLITE_ENABLE_ICU) */ +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + +/************** End of fts3_icu.c ********************************************/ -- Gitee From 5a74b245cf3fb022f165e4dcd2524f11fdd054b3 Mon Sep 17 00:00:00 2001 From: wanghaishuo Date: Sat, 12 Apr 2025 10:53:34 +0800 Subject: [PATCH 6/9] corrupt detect Signed-off-by: ryne3366 --- src/sqlite3.c | 649 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 563 insertions(+), 86 deletions(-) diff --git a/src/sqlite3.c b/src/sqlite3.c index dd89c5a..ad7ce74 100644 --- a/src/sqlite3.c +++ b/src/sqlite3.c @@ -2459,6 +2459,7 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ +#define SQLITE_CONFIG_CORRUPTION 30 /* xCorruption */ #define SQLITE_CONFIG_ENABLE_ICU 31 /* boolean */ /* ** CAPI3REF: Database Connection Configuration Options @@ -19554,6 +19555,8 @@ struct Sqlite3Config { int iOnceResetThreshold; /* When to reset OP_Once counters */ u32 szSorterRef; /* Min size in bytes to use sorter-refs */ unsigned int iPrngSeed; /* Alternative fixed seed for the PRNG */ + void (*xCorruption)(void *, const void *); + void *pCorruptionArg; /* vvvv--- must be last ---vvv */ #ifdef SQLITE_DEBUG sqlite3_int64 aTune[SQLITE_NTUNE]; /* Tuning parameters */ @@ -19805,6 +19808,57 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprLis } \ } +#define SQLITE_PRINT_CORRUPT_SIZE (SQLITE_PRINT_BUF_SIZE * 2) + +#define SQLITE_CORRUPT_CONTEXT(N,P,T,O,S,M,R) \ + { .nPage=(N), .pgno=(P), .type=(T), \ + .zoneRange={(O),(S)}, .zMsg=(M), .reservedArgs=(R) } + +typedef struct { + int offset; + size_t size; +}sqlite3CorruptRange; + +typedef enum { + CORRUPT_TYPE_PAGE_BTREE_LEAF, + CORRUPT_TYPE_PAGE_BTREE_INTERIOR, + CORRUPT_TYPE_PAGE_INDEX_LEAF, + CORRUPT_TYPE_PAGE_INDEX_INTERIOR, + CORRUPT_TYPE_PAGE_OVERFLOW, + CORRUPT_TYPE_PAGE_PTR_MAP, + CORRUPT_TYPE_PAGE_FREE_LIST, + CORRUPT_TYPE_FRAME_WAL, + CORRUPT_TYPE_ENTRY_JOURNAL, + CORRUPT_TYPE_VDBE, + CORRUPT_TYPE_FILE_HEADER, + CORRUPT_TYPE_UNKOWN, +} CorruptType; + +typedef struct { + size_t nPage; /* Number of pages */ + unsigned int pgno; /* Page number for corrupted page */ + CorruptType type; + sqlite3CorruptRange zoneRange; + const char *zMsg; + void *reservedArgs; +}sqlite3CorruptContext; + +// Encode buffer with base16, return size after encode +static size_t sqlite3base16Encode(const unsigned char *buffer, size_t bufSize, char *encodeBuf, size_t encodeBufSize) +{ + if (buffer == NULL || bufSize == 0 || encodeBuf == NULL || encodeBufSize == 0) { + return 0; + } + static const char base16Code[] = "0123456789ABCDEF"; + size_t i = 0; + for (; i < bufSize && (i * 2 < encodeBufSize - 1); i++) { + *encodeBuf++ = base16Code[(buffer[i] >> 4) & 0x0F]; + *encodeBuf++ = base16Code[buffer[i] & 0x0F]; + } + *encodeBuf = '\0'; + return i * 2; +} + /* ** The SQLITE_*_BKPT macros are substitutes for the error codes with ** the same name but without the _BKPT suffix. These macros invoke @@ -19813,10 +19867,11 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprLis ** to set a debugger breakpoint. */ SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType); -SQLITE_PRIVATE int sqlite3CorruptError(int); +SQLITE_PRIVATE int sqlite3CorruptError(int lineno, sqlite3CorruptContext *context); SQLITE_PRIVATE int sqlite3MisuseError(int); SQLITE_PRIVATE int sqlite3CantopenError(int); -#define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__) +#define SQLITE_CORRUPT_REPORT(context) sqlite3CorruptError(__LINE__,(context)) +#define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__,NULL) #define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__) #define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__) #ifdef SQLITE_DEBUG @@ -19828,12 +19883,13 @@ SQLITE_PRIVATE int sqlite3IoerrnomemError(int); # define SQLITE_NOMEM_BKPT SQLITE_NOMEM # define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM #endif -#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO) +#if (defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO)) SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno); -# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P)) +# define SQLITE_CORRUPT_PGNO(P,context) sqlite3CorruptPgnoError(__LINE__,(P)) #else -# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__) +# define SQLITE_CORRUPT_PGNO(P,context) sqlite3CorruptError(__LINE__,(context)) #endif +# define SQLITE_CORRUPT_REPORT_PGNO(context) SQLITE_CORRUPT_PGNO((context)->pgno,(context)) /* ** FTS3 and FTS4 both require virtual table support @@ -22312,6 +22368,8 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { 0x7ffffffe, /* iOnceResetThreshold */ SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */ 0, /* iPrngSeed */ + 0, /* xCorruption */ + 0, /* pCorruptionArg */ #ifdef SQLITE_DEBUG {0,0,0,0,0,0} /* aTune */ #endif @@ -58784,7 +58842,7 @@ static int readDbPage(PgHdr *pPg){ assert( isOpen(pPager->fd) ); if( pagerUseWal(pPager) ){ - rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); + rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); // find in wal-index if( rc ) return rc; } if( iFrame ){ @@ -61324,7 +61382,12 @@ static int getPageNormal( assert( assert_pager_state(pPager) ); assert( pPager->hasHeldSharedLock==1 ); - if( pgno==0 ) return SQLITE_CORRUPT_BKPT; + if( pgno==0 ) { + const char *zMsg = "pgno should not be 0"; + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, 0, CORRUPT_TYPE_UNKOWN, + -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_REPORT(&context); + } pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3); if( pBase==0 ){ pPg = 0; @@ -61356,7 +61419,11 @@ static int getPageNormal( ** (2) Never try to fetch the locking page */ if( pgno==PAGER_SJ_PGNO(pPager) ){ - rc = SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "try fetching the locking page(%u)", pgno); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, pgno, CORRUPT_TYPE_UNKOWN, + -1, 0, zMsg, NULL); + rc = SQLITE_CORRUPT_REPORT(&context); goto pager_acquire_err; } @@ -61438,7 +61505,10 @@ static int getPageMMap( ** test in the previous statement, and avoid testing pgno==0 in the ** common case where pgno is large. */ if( pgno<=1 && pgno==0 ){ - return SQLITE_CORRUPT_BKPT; + const char *zMsg = "pgno should not be 0"; + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, 0, CORRUPT_TYPE_UNKOWN, + -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_REPORT(&context); } assert( pPager->eState>=PAGER_READER ); assert( assert_pager_state(pPager) ); @@ -63024,7 +63094,11 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i if( pPgOld ){ if( NEVER(pPgOld->nRef>1) ){ sqlite3PagerUnrefNotNull(pPgOld); - return SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "page(%u) should be no references, ref cnt:%d", pgno, (int)pPgOld->nRef); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, pgno, CORRUPT_TYPE_UNKOWN, + -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_REPORT(&context); } pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); if( pPager->tempFile ){ @@ -64792,7 +64866,13 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ /* Write the aPgno[] array entry and the hash-table slot. */ nCollide = idx; for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ - if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT; + if( (nCollide--)==0 ){ + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "no place for page(%u) to map into WAL, idx:%d", iPage, idx); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, iPage, CORRUPT_TYPE_FRAME_WAL, + -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_REPORT(&context); + } } sLoc.aPgno[idx-1] = iPage; AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx); @@ -65745,7 +65825,13 @@ static int walCheckpoint( ** database plus the amount of data in the wal file, plus the ** maximum size of the pending-byte page (65536 bytes), then ** must be corruption somewhere. */ - rc = SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, + "final db size unexpected,nSize=%lld,mxFrame=%u,pageSize=%d,nReq=%lld", + nSize, pWal->hdr.mxFrame, szPage, nReq); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, 0, CORRUPT_TYPE_FRAME_WAL, + -1, 0, zMsg, NULL); + rc = SQLITE_CORRUPT_REPORT(&context); }else{ sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT,&nReq); } @@ -66856,7 +66942,11 @@ SQLITE_PRIVATE int sqlite3WalFindFrame( iRead = iFrame; } if( (nCollide--)==0 ){ - return SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "mis-match page(%u) to map into WAL", pgno); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, pgno, CORRUPT_TYPE_FRAME_WAL, + -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_REPORT(&context); } iKey = walNextHash(iKey); } @@ -67597,7 +67687,12 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( if( rc==SQLITE_OK ){ if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ - rc = SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "mis-match between pageSize=%d and bufferSize=%d, mxFrame=%u", + walPagesize(pWal),nBuf,pWal->hdr.mxFrame); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, 0, CORRUPT_TYPE_FRAME_WAL, + -1, 0, zMsg, NULL); + rc = SQLITE_CORRUPT_REPORT(&context); }else{ sqlite3_int64 startTime; sqlite3OsCurrentTimeInt64(db->pVfs, &startTime); @@ -69055,7 +69150,7 @@ static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf){ ** with the page number and filename associated with the (MemPage*). */ #ifdef SQLITE_DEBUG -int corruptPageError(int lineno, MemPage *p){ +int corruptPageError(int lineno, MemPage *p, sqlite3CorruptContext *context){ char *zMsg; sqlite3BeginBenignMalloc(); zMsg = sqlite3_mprintf("database corruption page %d of %s", @@ -69066,11 +69161,11 @@ int corruptPageError(int lineno, MemPage *p){ sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg); } sqlite3_free(zMsg); - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_REPORT(context); } -# define SQLITE_CORRUPT_PAGE(pMemPage) corruptPageError(__LINE__, pMemPage) +# define SQLITE_CORRUPT_PAGE(context,pMemPage) corruptPageError(__LINE__, (pMemPage),(context)) #else -# define SQLITE_CORRUPT_PAGE(pMemPage) SQLITE_CORRUPT_PGNO(pMemPage->pgno) +# define SQLITE_CORRUPT_PAGE(context,pMemPage) SQLITE_CORRUPT_PGNO((pMemPage)->pgno,(context)) #endif #ifndef SQLITE_OMIT_SHARED_CACHE @@ -69748,7 +69843,12 @@ static int btreeMoveto( if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT; sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey); if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){ - rc = SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpected fields in total:%u, should != 0 and < %u", + pIdxKey->nField,pKeyInfo->nAllField); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pCur->pBt->nPage, 0, CORRUPT_TYPE_PAGE_BTREE_LEAF, + -1, 0, zMsg, NULL); + rc = SQLITE_CORRUPT_REPORT(&context); }else{ rc = sqlite3BtreeIndexMoveto(pCur, pIdxKey, pRes); } @@ -69928,7 +70028,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) ); assert( pBt->autoVacuum ); - if( key==0 ){ + if( key==0 ){ // The pgno of each entry on ptrmap page starts from 3, an unexpected pgno indicates data corrupted *pRC = SQLITE_CORRUPT_BKPT; return; } @@ -69942,12 +70042,24 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ /* The first byte of the extra data is the MemPage.isInit byte. ** If that byte is set, it means this page is also being used ** as a btree page. */ - *pRC = SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode((unsigned char *)sqlite3PagerGetExtra(pDbPage), 8, xBuffer, sizeof(xBuffer)); + sqlite3_snprintf(sizeof(zMsg), zMsg, "page(%u) been initialized before as a btree page, base16:%s", + iPtrmap, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, + -1, 0, zMsg, NULL); + *pRC = SQLITE_CORRUPT_REPORT(&context); goto ptrmap_exit; } offset = PTRMAP_PTROFFSET(iPtrmap, key); if( offset<0 ){ - *pRC = SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpect offset in ptrmap page(%u), target:%u, page usableSize=%u", + iPtrmap, key, pBt->usableSize); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, + -1, 0, zMsg, NULL); + *pRC = SQLITE_CORRUPT_REPORT(&context); goto ptrmap_exit; } assert( offset <= (int)pBt->usableSize-5 ); @@ -69992,7 +70104,12 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ offset = PTRMAP_PTROFFSET(iPtrmap, key); if( offset<0 ){ sqlite3PagerUnref(pDbPage); - return SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpect offset in ptrmap page(%d), target:%u, page usableSize=%u", + iPtrmap, key, pBt->usableSize); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, + -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_REPORT(&context); } assert( offset <= (int)pBt->usableSize-5 ); assert( pEType!=0 ); @@ -70000,7 +70117,15 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); sqlite3PagerUnref(pDbPage); - if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_PGNO(iPtrmap); + if( *pEType<1 || *pEType>5 ){ + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; // 5 bytes for each entry on ptrmap page + (void)sqlite3base16Encode(pPtrmap, 5, xBuffer, sizeof(xBuffer)); + sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpect entry type:%d, base16:%s", (int)*pEType, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, + offset, 5, zMsg, NULL); + return SQLITE_CORRUPT_REPORT_PGNO(&context); + } return SQLITE_OK; } @@ -70392,7 +70517,14 @@ static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){ Pgno ovfl; if( SQLITE_WITHIN(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){ testcase( pSrc!=pPage ); - *pRC = SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; // Output cell header as much as possible, 4 bytes for overflow pgno + (void)sqlite3base16Encode(pCell, info.nSize - info.nLocal - 4, xBuffer, sizeof(xBuffer)); + sqlite3_snprintf(sizeof(zMsg), zMsg, "cell overflow, offset=%d, rest=%d, length=%u, base16:%s", + (int)(pCell - pPage->aData), (int)(pSrc->aDataEnd - pCell), info.nSize, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + pCell - pPage->aData, info.nSize, zMsg, NULL); + *pRC = SQLITE_CORRUPT_REPORT(&context); return; } ovfl = get4byte(&pCell[info.nSize-4]); @@ -70450,10 +70582,29 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ ** reconstruct the entire page. */ if( (int)data[hdr+7]<=nMaxFrag ){ int iFree = get2byte(&data[hdr+1]); - if( iFree>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); + if( iFree>usableSize-4 ){ + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Output first 8 bytes as it's page header + sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset=%d overflow, usableSize=%d, base16:%s", + iFree, usableSize, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + 0, 8, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); + } if( iFree ){ int iFree2 = get2byte(&data[iFree]); - if( iFree2>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); + if( iFree2>usableSize-4 ){ + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(data, 4, xBuffer, sizeof(xBuffer)); // Output first freeblock's header 4 bytes + sqlite3_snprintf(sizeof(zMsg), zMsg, + "1st freeblock's next pointer overflow, point:%d, usableSize=%d, base16:%s", + iFree2, usableSize, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + iFree, 4, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); + } if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){ u8 *pEnd = &data[cellOffset + nCell*2]; u8 *pAddr; @@ -70461,16 +70612,51 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ int sz = get2byte(&data[iFree+2]); int top = get2byte(&data[hdr+5]); if( top>=iFree ){ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Print first 8 bytes which is page header + sqlite3_snprintf(sizeof(zMsg), zMsg, + "1st freeblock's offset:%d should > CellContentArea's offset:%d, base16:%s", + iFree, top, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + iFree, 8, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } if( iFree2 ){ - if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PAGE(pPage); + if( iFree+sz>iFree2 ){ + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Print first 8 bytes which is page header + sqlite3_snprintf(sizeof(zMsg), zMsg, + "the 1st 2 freeblocks mis-order, 1st block offset:%d, size:%d, 2nd block offset:%d, base16:%s", + iFree, sz, iFree2, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + iFree, 4, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); + } sz2 = get2byte(&data[iFree2+2]); - if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage); + if( iFree2+sz2 > usableSize ){ + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(data + iFree2, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to 2nd block + sqlite3_snprintf(sizeof(zMsg), zMsg, + "the 2nd freeblock overflow, offset:%d, size:%d, usableSize:%d, base16:%s", + iFree2, sz2, usableSize, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + iFree2, 4, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); + } memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); sz += sz2; }else if( iFree+sz>usableSize ){ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(data + iFree, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to 1st block + sqlite3_snprintf(sizeof(zMsg), zMsg, + "the 1st freeblock overflow, offset:%d, size:%d, usableSize:%d, base16:%s", iFree, sz, usableSize, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + iFree, 4, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } cbrk = top+sz; @@ -70503,13 +70689,24 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ ** if PRAGMA cell_size_check=ON. */ if( pciCellLast ){ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; // Print 4 bytes belong to 1st block + (void)sqlite3base16Encode(data + cellOffset + i*2, 2, xBuffer, sizeof(xBuffer)); + sqlite3_snprintf(sizeof(zMsg), zMsg, "%d-th cell pointer:%d out of range[%d, %d], base16:%s", + i, pc, iCellStart, iCellLast, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + cellOffset + i*2, 2, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } assert( pc>=iCellStart && pc<=iCellLast ); size = pPage->xCellSize(pPage, &src[pc]); cbrk -= size; if( cbrkusableSize ){ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "move %d-th cell from %d using unexpected size:%d", i, pc, size); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } assert( cbrk+size<=usableSize && cbrk>=iCellStart ); testcase( cbrk+size==usableSize ); @@ -70523,7 +70720,13 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ defragment_out: assert( pPage->nFree>=0 ); if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, + "after defragment, free bytes should not change, fragment bytes:%d, free space:%d, total:%d", + (int)data[hdr+7], cbrk-iCellFirst, pPage->nFree); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } assert( cbrk>=iCellFirst ); put2byte(&data[hdr+5], cbrk); @@ -70548,7 +70751,7 @@ defragment_out: ** will be ignored if adding the extra space to the fragmentation count ** causes the fragmentation count to exceed 60. */ -static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ +static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ // search on B-tree page const int hdr = pPg->hdrOffset; /* Offset to page header */ u8 * const aData = pPg->aData; /* Page data */ int iAddr = hdr + 1; /* Address of ptr to pc */ @@ -70580,7 +70783,15 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ return &aData[pc]; }else if( x+pc > maxPC ){ /* This slot extends off the end of the usable part of the page */ - *pRc = SQLITE_CORRUPT_PAGE(pPg); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(aData + pc, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to free block + sqlite3_snprintf(sizeof(zMsg), zMsg, + "freeblock rest bytes:%d begin at %d which cost %d, still exceed usableSize:%u, base16:%s", + x, pc, nByte, pPg->pBt->usableSize, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPg->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + pc, 4, zMsg, NULL); + *pRc = SQLITE_CORRUPT_PAGE(&context, pPg); return 0; }else{ /* The slot remains on the free-list. Reduce its size to account @@ -70595,14 +70806,25 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ if( pc<=iAddr ){ if( pc ){ /* The next slot in the chain comes before the current slot */ - *pRc = SQLITE_CORRUPT_PAGE(pPg); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(pTmp, 2, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to free block + sqlite3_snprintf(sizeof(zMsg), zMsg, + "the next slot:%d in chain comes before current slot:%d, base16:%s", pc, iAddr, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPg->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + iAddr, 2, zMsg, NULL); + *pRc = SQLITE_CORRUPT_PAGE(&context, pPg); } return 0; } } if( pc>maxPC+nByte-4 ){ /* The free slot chain extends off the end of the page */ - *pRc = SQLITE_CORRUPT_PAGE(pPg); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "free slot:%d overflow, end:%d", pc, maxPC+nByte-4); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPg->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + -1, 0, zMsg, NULL); + *pRc = SQLITE_CORRUPT_PAGE(&context, pPg); } return 0; } @@ -70651,7 +70873,13 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ if( top==0 && pPage->pBt->usableSize==65536 ){ top = 65536; }else{ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Print 8 bytes belong to page header + sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpected cellContentArea offset:%d, base16:%s", top, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } } @@ -70669,7 +70897,11 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ assert( pSpace+nByte<=data+pPage->pBt->usableSize ); *pIdx = g2 = (int)(pSpace-data); if( g2<=gap ){ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "cellpointers(end:%d) overlap with freeblock(%d)", gap, g2); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); }else{ return SQLITE_OK; } @@ -70748,12 +70980,23 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ while( (iFreeBlk = get2byte(&data[iPtr]))pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } iPtr = iFreeBlk; } if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(data + iPtr, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to freeblock + sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset:%d overflow, base16:%s", (int)iFreeBlk, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, iPtr, 4, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } assert( iFreeBlk>iPtr || iFreeBlk==0 || CORRUPT_DB ); @@ -70765,10 +71008,24 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ */ if( iFreeBlk && iEnd+3>=iFreeBlk ){ nFrag = iFreeBlk - iEnd; - if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage); + if( iEnd>iFreeBlk ){ + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset:%d overlaps with pre block's end:%u", + (int)iFreeBlk, iEnd); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); + } iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]); if( iEnd > pPage->pBt->usableSize ){ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(data + iFreeBlk, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to freeblock + sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset:%d, end:%u overflow, usableSize:%u, base16:%s", + (int)iFreeBlk, iEnd, pPage->pBt->usableSize, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, iFreeBlk, 4, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } iSize = iEnd - iStart; iFreeBlk = get2byte(&data[iFreeBlk]); @@ -70781,13 +71038,27 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ if( iPtr>hdr+1 ){ int iPtrEnd = iPtr + get2byte(&data[iPtr+2]); if( iPtrEnd+3>=iStart ){ - if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PAGE(pPage); + if( iPtrEnd>iStart ){ + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "check pre freeblock end:%d overlaps with the pending free block:%d", + iPtrEnd, (int)iStart); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, iPtr, iPtrEnd - iPtr, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); + } nFrag += iStart - iPtrEnd; iSize = iEnd - iPtr; iStart = iPtr; } } - if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage); + if( nFrag>data[hdr+7] ){ + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "fragment free bytes:%d increase unexpectly, should be %d", + (int)nFrag, (int)data[hdr+7]); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); + } data[hdr+7] -= nFrag; } pTmp = &data[hdr+5]; @@ -70796,8 +71067,21 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ /* The new freeblock is at the beginning of the cell content area, ** so just extend the cell content area rather than create another ** freelist entry */ - if( iStart= the beginning of the CellContentArea:%d", (int)x, (int)iStart); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); + } + if( iPtr!=hdr+1 ){ + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "1st freeblock's pos incorrect, hdr:%d, iPtr:%d", (int)hdr, (int)iPtr); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); + } put2byte(&data[hdr+1], iFreeBlk); put2byte(&data[hdr+5], iEnd); }else{ @@ -70882,7 +71166,13 @@ static int decodeFlags(MemPage *pPage, int flagByte){ pPage->pgno, flagByte, pPage->isInit, pPage->intKey, pPage->intKeyLeaf, pPage->leaf, pPage->childPtrSize, pPage->cellOffset, pPage->nCell, pPage->hdrOffset, pPage->minLocal, pPage->maxLocal, g_lastCkptTime); #endif /* LOG_DUMP */ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(pPage->aData, 8, xBuffer, sizeof(xBuffer)); + sqlite3_snprintf(sizeof(zMsg), zMsg, "unrecognized flag:%d, base16:%s", flagByte, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } pPage->max1bytePayload = pBt->max1bytePayload; return SQLITE_OK; @@ -70933,12 +71223,20 @@ static int btreeComputeFreeSpace(MemPage *pPage){ /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will ** always be at least one cell before the first freeblock. */ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "the 1st freeblock:%d before all cells:%d", pc, top); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } while( 1 ){ if( pc>iCellLast ){ /* Freeblock off the end of the page */ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock end:%d out of page range:%d", pc, iCellLast); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } next = get2byte(&data[pc]); size = get2byte(&data[pc+2]); @@ -70948,11 +71246,19 @@ static int btreeComputeFreeSpace(MemPage *pPage){ } if( next>0 ){ /* Freeblock not in ascending order */ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "all freeblocks should order by asc, pre:%d, cur:%u", pc, next); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } if( pc+size>(unsigned int)usableSize ){ /* Last freeblock extends past page end */ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "last freeblock overflow, offset:%d, size:%u", pc, size); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } } @@ -70964,7 +71270,13 @@ static int btreeComputeFreeSpace(MemPage *pPage){ ** area, according to the page header, lies within the page. */ if( nFree>usableSize || nFreepBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } pPage->nFree = (u16)(nFree - iCellFirst); return SQLITE_OK; @@ -70995,12 +71307,20 @@ static SQLITE_NOINLINE int btreeCellSizeCheck(MemPage *pPage){ testcase( pc==iCellFirst ); testcase( pc==iCellLast ); if( pciCellLast ){ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "cell pointer:%d indicate out of range:[%d, %d]", pc, iCellFirst, iCellLast); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } sz = pPage->xCellSize(pPage, &data[pc]); testcase( pc+sz==usableSize ); if( pc+sz>usableSize ){ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpected cell size:%d,offset:%d, out of range:%d", sz, pc, usableSize); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } } return SQLITE_OK; @@ -71032,7 +71352,7 @@ static int btreeInitPage(MemPage *pPage){ /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating ** the b-tree page type. */ if( decodeFlags(pPage, data[0]) ){ - return SQLITE_CORRUPT_PAGE(pPage); + return SQLITE_CORRUPT_PAGE(NULL, pPage); } assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); pPage->maskPage = (u16)(pBt->pageSize - 1); @@ -71046,7 +71366,12 @@ static int btreeInitPage(MemPage *pPage){ pPage->nCell = get2byte(&data[3]); if( pPage->nCell>MX_CELL(pBt) ){ /* To many cells for a single page. The page must be corrupt */ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "too many cells(%d) for the page:%u, offset:%d, out of range:%u", + (int)pPage->nCell, pPage->pgno, (int)pPage->hdrOffset + 3, MX_CELL(pBt)); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } testcase( pPage->nCell==MX_CELL(pBt) ); /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only @@ -71201,7 +71526,11 @@ static int getAndInitPage( assert( pCur==0 || pCur->iPage>0 ); if( pgno>btreePagecount(pBt) ){ - rc = SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "page number(%u) > db file size(%u)", pgno, btreePagecount(pBt)); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + -1, 0, zMsg, NULL); + rc = SQLITE_CORRUPT_REPORT(&context); goto getAndInitPage_error1; } rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly); @@ -71222,7 +71551,12 @@ static int getAndInitPage( /* 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); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "check btree page, nCell:%u, intKey:%u, cursor->curIntKey:%u", + (*ppPage)->nCell, (*ppPage)->intKey, pCur->curIntKey); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + -1, 0, zMsg, NULL); + rc = SQLITE_CORRUPT_REPORT_PGNO(&context); goto getAndInitPage_error2; } return SQLITE_OK; @@ -72656,7 +72990,12 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ if( eType==PTRMAP_OVERFLOW2 ){ /* The pointer is always the first 4 bytes of the page in this case. */ if( get4byte(pPage->aData)!=iFrom ){ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "1st 4 bytes of ovrflow page(%u) point to next(%u), should be %u", + pPage->pgno, get4byte(pPage->aData), iFrom); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_PTR_MAP, + 0, 4, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } put4byte(pPage->aData, iTo); }else{ @@ -72675,7 +73014,13 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ pPage->xParseCell(pPage, pCell, &info); if( info.nLocal pPage->aData+pPage->pBt->usableSize ){ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, + "btree cell contain ovrflow pointer overflow, offset:%d, size:%u, usableSize:%u", + (int)(pCell - pPage->aData), info.nSize, pPage->pBt->usableSize); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_PTR_MAP, pCell - pPage->aData, info.nSize, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } if( iFrom==get4byte(pCell+info.nSize-4) ){ put4byte(pCell+info.nSize-4, iTo); @@ -72684,7 +73029,13 @@ 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); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, + "btree cell contain child pointer overflow, offset:%d, size:4, usableSize:%u", + (int)(pCell - pPage->aData), pPage->pBt->usableSize); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_PTR_MAP, pCell - pPage->aData, 4, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } if( get4byte(pCell)==iFrom ){ put4byte(pCell, iTo); @@ -72696,7 +73047,11 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ if( i==nCell ){ if( eType!=PTRMAP_BTREE || get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "missing pointer point to overflow page on btree page(%u)", pPage->pgno); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } put4byte(&pPage->aData[pPage->hdrOffset+8], iTo); } @@ -72829,7 +73184,11 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){ return rc; } if( eType==PTRMAP_ROOTPAGE ){ - return SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "try vacuum root page(%u), should not happened", nFin); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, PTRMAP_PAGENO(pBt, iLastPg), + CORRUPT_TYPE_PAGE_PTR_MAP, -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_REPORT(&context); } if( eType==PTRMAP_FREEPAGE ){ @@ -73907,7 +74266,12 @@ static int accessPayload( assert( eOp==0 || eOp==1 ); assert( pCur->eState==CURSOR_VALID ); if( pCur->ix>=pPage->nCell ){ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "cell index:%u exceed limit:%u on the page:%u", + pCur->ix, pPage->nCell, pPage->pgno); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } assert( cursorHoldsMutex(pCur) ); @@ -73922,7 +74286,12 @@ static int accessPayload( ** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ** but is recast into its current form to avoid integer overflow problems */ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "base on payload size:%u, the max offset(%d) should > %d", + pCur->info.nLocal, (int)(aPayload - pPage->aData), (int)(pBt->usableSize - pCur->info.nLocal)); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + 0, 8, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } /* Check if data must be read/written to/from the btree page itself. */ @@ -73984,7 +74353,16 @@ static int accessPayload( assert( rc==SQLITE_OK && amt>0 ); while( nextPage ){ /* If required, populate the overflow page-list cache. */ - if( nextPage > pBt->nPage ) return SQLITE_CORRUPT_BKPT; + if( nextPage > pBt->nPage ){ + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(aPayload + pCur->info.nLocal, 4, xBuffer, sizeof(xBuffer)); + sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow page:%u should not exceed the size of database file, base16:%s", + nextPage, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + aPayload - pPage->aData + pCur->info.nLocal, 4, zMsg, NULL); + return SQLITE_CORRUPT_REPORT(&context); + } assert( pCur->aOverflow[iIdx]==0 || pCur->aOverflow[iIdx]==nextPage || CORRUPT_DB ); @@ -74069,7 +74447,11 @@ static int accessPayload( if( rc==SQLITE_OK && amt>0 ){ /* Overflow chain ends prematurely */ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow chain ends prematurely, rest:%d", amt); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } return rc; } @@ -74345,7 +74727,12 @@ static int moveToRoot(BtCursor *pCur){ ** (or the freelist). */ assert( pRoot->intKey==1 || pRoot->intKey==0 ); if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){ - return SQLITE_CORRUPT_PAGE(pCur->pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "the page(%u) state illegal, isInit:%u, pKeyInfo%s0, intKey:%u", + pRoot->pgno, pRoot->isInit, ((pCur->pKeyInfo==0)?"==":"!="), pRoot->intKey); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pCur->pBt->nPage, pRoot->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pCur->pPage); } skip_init: @@ -74599,7 +74986,11 @@ SQLITE_PRIVATE int sqlite3BtreeTableMoveto( if( pPage->intKeyLeaf ){ while( 0x80 <= *(pCell++) ){ if( pCell>=pPage->aDataEnd ){ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "cell idx(%d) point to a cell should not out of page", idx); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } } } @@ -74882,7 +75273,12 @@ bypass_moveto_root: testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */ testcase( nCell==2 ); /* Minimum legal index key size */ if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){ - rc = SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "nCell:%d illegal, usableSize:%u, nPage:%u", + nCell, pCur->pBt->usableSize, pCur->pBt->nPage); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); + rc = SQLITE_CORRUPT_PAGE(&context, pPage); goto moveto_index_finish; } pCellKey = sqlite3Malloc( nCell+nOverrun ); @@ -75210,7 +75606,13 @@ static int allocateBtreePage( n = get4byte(&pPage1->aData[36]); testcase( n==mxPage-1 ); if( n>=mxPage ){ - return SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE*3] = {0}; + (void)sqlite3base16Encode(pPage1->aData, 100, xBuffer, sizeof(xBuffer)); + sqlite3_snprintf(sizeof(zMsg), zMsg, + "total pages(%u) in freelist should not over the total size of db file(%u), base16:%s", n, mxPage, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, 1, CORRUPT_TYPE_FILE_HEADER, 36, 4, zMsg, NULL); + return SQLITE_CORRUPT_REPORT(&context); } if( n>0 ){ /* There are pages on the freelist. Reuse one of those pages. */ @@ -75266,7 +75668,12 @@ static int allocateBtreePage( } testcase( iTrunk==mxPage ); if( iTrunk>mxPage || nSearch++ > n ){ - rc = SQLITE_CORRUPT_PGNO(pPrevTrunk ? pPrevTrunk->pgno : 1); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "freelist trunk page(%u) should <= the size of db(%u)", + iTrunk, mxPage); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, (pPrevTrunk ? pPrevTrunk->pgno : 1), + CORRUPT_TYPE_PAGE_FREE_LIST, -1, 0, zMsg, NULL); + rc = SQLITE_CORRUPT_REPORT_PGNO(&context); }else{ rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0); } @@ -75295,7 +75702,14 @@ static int allocateBtreePage( TRACE(("ALLOCATE: %d trunk - %d 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); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(pTrunk->aData, 8, xBuffer, sizeof(xBuffer)); + sqlite3_snprintf(sizeof(zMsg), zMsg, "total leaf pages(%u) on trunk page over limit(%u), base16:%s", + k, (u32)(pBt->usableSize/4 - 2), xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, + 0, 8, zMsg, NULL); + rc = SQLITE_CORRUPT_REPORT_PGNO(&context); goto end_allocate_page; #ifndef SQLITE_OMIT_AUTOVACUUM }else if( searchList @@ -75329,7 +75743,14 @@ static int allocateBtreePage( MemPage *pNewTrunk; Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); if( iNewTrunk>mxPage ){ - rc = SQLITE_CORRUPT_PGNO(iTrunk); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(pTrunk->aData, 12, xBuffer, sizeof(xBuffer)); + sqlite3_snprintf(sizeof(zMsg), zMsg, + "leaf page's pgno(%u) on trunk page exceed db file size(%u), base16:%s", iNewTrunk, mxPage, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, + 8, 4, zMsg, NULL); + rc = SQLITE_CORRUPT_REPORT_PGNO(&context); goto end_allocate_page; } testcase( iNewTrunk==mxPage ); @@ -75394,7 +75815,14 @@ static int allocateBtreePage( iPage = get4byte(&aData[8+closest*4]); testcase( iPage==mxPage ); if( iPage>mxPage || iPage<2 ){ - rc = SQLITE_CORRUPT_PGNO(iTrunk); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(aData+8+closest*4, 4, xBuffer, sizeof(xBuffer)); + sqlite3_snprintf(sizeof(zMsg), zMsg, "leaf page's pgno(%u) out of range:[3, %d], base16:%s", + iPage, mxPage, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, + 8+closest*4, 4, zMsg, NULL); + rc = SQLITE_CORRUPT_REPORT_PGNO(&context); goto end_allocate_page; } testcase( iPage==mxPage ); @@ -75579,7 +76007,14 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ nLeaf = get4byte(&pTrunk->aData[4]); assert( pBt->usableSize>32 ); if( nLeaf > (u32)pBt->usableSize/4 - 2 ){ - rc = SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(pTrunk->aData, 4, xBuffer, sizeof(xBuffer)); + sqlite3_snprintf(sizeof(zMsg), zMsg, "the number of leaf page(%u) on trunk page(%d) exceed limit, base16:%s", + nLeaf, iTrunk, xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, + 0, 4, zMsg, NULL); + rc = SQLITE_CORRUPT_REPORT(&context); goto freepage_out; } if( nLeaf < (u32)pBt->usableSize/4 - 8 ){ @@ -75668,7 +76103,12 @@ static SQLITE_NOINLINE int clearCellOverflow( testcase( pCell + (pInfo->nSize-1) == pPage->aDataEnd ); if( pCell + pInfo->nSize > pPage->aDataEnd ){ /* Cell extends past end of page */ - return SQLITE_CORRUPT_PAGE(pPage); + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow end of page, pgno:%u, offset:%d, size:%u, usableSize:%u", + pPage->pgno, (int)(pCell - pPage->aData), pInfo->nSize, pPage->pBt->usableSize); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(btreePagecount(pPage->pBt), pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_PAGE(&context, pPage); } ovflPgno = get4byte(pCell + pInfo->nSize - 4); pBt = pPage->pBt; @@ -75685,7 +76125,14 @@ static SQLITE_NOINLINE int clearCellOverflow( /* 0 is not a legal page number and page 1 cannot be an ** overflow page. Therefore if ovflPgno<2 or past the end of the ** file the database must be corrupt. */ - return SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; + (void)sqlite3base16Encode(pCell + pInfo->nSize - 4, 4, xBuffer, sizeof(xBuffer)); + sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow page's pgno(%u) illegal, out of range:[2, %u], base16:%s", + ovflPgno, btreePagecount(pBt), xBuffer); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(btreePagecount(pBt), pPage->pgno, + CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_REPORT(&context); } if( nOvfl ){ rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext); @@ -75958,7 +76405,12 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ testcase( pc==(u32)get2byte(&data[hdr+5]) ); testcase( pc+sz==pPage->pBt->usableSize ); if( pc+sz > pPage->pBt->usableSize ){ - *pRC = SQLITE_CORRUPT_BKPT; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, "cell offset:%u size:%d, idx:%d overflow, usableSize:%u", + pc, sz, idx, pPage->pBt->usableSize); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + -1, 0, zMsg, NULL); + *pRC = SQLITE_CORRUPT_REPORT(&context); return; } rc = freeSpace(pPage, pc, sz); @@ -77868,7 +78320,14 @@ 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; + char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; + sqlite3_snprintf(sizeof(zMsg), zMsg, + "cell payload cursor point to(%d), size:%u overlaps with non-cell content area:[%u, %d]", + (int)(pCur->info.pPayload - pPage->aData), pCur->info.nLocal, pPage->cellOffset, + (int)(pPage->aDataEnd - pPage->aData)); + sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, + -1, 0, zMsg, NULL); + return SQLITE_CORRUPT_REPORT(&context); } /* Overwrite the local portion first */ rc = btreeOverwriteContent(pPage, pCur->info.pPayload, pX, @@ -83064,7 +83523,7 @@ static int growOpArray(Vdbe *v, int nOp){ ** ** Other useful labels for breakpoints include: ** test_trace_breakpoint(pc,pOp) -** sqlite3CorruptError(lineno) +** sqlite3CorruptError(lineno,context) ** sqlite3MisuseError(lineno) ** sqlite3CantopenError(lineno) */ @@ -90722,7 +91181,7 @@ SQLITE_API int sqlite3_found_count = 0; ** ** Other useful labels for breakpoints include: ** test_addop_breakpoint(pc,pOp) -** sqlite3CorruptError(lineno) +** sqlite3CorruptError(lineno,context) ** sqlite3MisuseError(lineno) ** sqlite3CantopenError(lineno) */ @@ -174509,6 +174968,12 @@ SQLITE_API int sqlite3_config(int op, ...){ break; } #endif /* SQLITE_OMIT_DESERIALIZE */ + case SQLITE_CONFIG_CORRUPTION: { + typedef void(*CORRUPTION_FUNC_t)(void*, const void*); + sqlite3GlobalConfig.xCorruption = va_arg(ap, CORRUPTION_FUNC_t); + sqlite3GlobalConfig.pCorruptionArg = va_arg(ap, void*); + break; + } default: { rc = SQLITE_ERROR; @@ -177587,9 +178052,21 @@ SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType){ zType, lineno, 20+sqlite3_sourceid()); return iErr; } -SQLITE_PRIVATE int sqlite3CorruptError(int lineno){ +SQLITE_PRIVATE int sqlite3CorruptError(int lineno, sqlite3CorruptContext *context){ testcase( sqlite3GlobalConfig.xLog!=0 ); - return sqlite3ReportError(SQLITE_CORRUPT, lineno, "database corruption"); + if (context!=NULL && sqlite3GlobalConfig.xCorruption != 0) { + char zMsg[SQLITE_PRINT_BUF_SIZE] = {0}; /* Complete corruption log message */ + sqlite3_snprintf(sizeof(zMsg), zMsg, "pgno:%u,type:%d,range:{%d,%d},line:%d", + context->pgno, (int)context->type, (int)context->zoneRange.offset, (int)context->zoneRange.size, lineno); + sqlite3GlobalConfig.xCorruption(sqlite3GlobalConfig.pCorruptionArg, zMsg); + } + char zCorruptMsg[SQLITE_PRINT_BUF_SIZE * 10] = {0}; + if (context!=NULL && context->zMsg != NULL){ + sqlite3_snprintf(sizeof(zCorruptMsg), zCorruptMsg, "database corruption, %s", context->zMsg); + } else { + sqlite3_snprintf(sizeof(zCorruptMsg), zCorruptMsg, "database corruption"); + } + return sqlite3ReportError(SQLITE_CORRUPT, lineno, zCorruptMsg); } SQLITE_PRIVATE int sqlite3MisuseError(int lineno){ testcase( sqlite3GlobalConfig.xLog!=0 ); -- Gitee From c55af5823f6913cb4a5534f4319b6d22d4e51135 Mon Sep 17 00:00:00 2001 From: wanghaishuo Date: Sat, 12 Apr 2025 10:59:29 +0800 Subject: [PATCH 7/9] support check pages Signed-off-by: ryne3366 --- ext/misc/cksumvfs.c | 916 ++++++++++++++++++++++++++++++++++++++++++++ src/sqlite3.c | 99 ++++- 2 files changed, 1008 insertions(+), 7 deletions(-) create mode 100644 ext/misc/cksumvfs.c diff --git a/ext/misc/cksumvfs.c b/ext/misc/cksumvfs.c new file mode 100644 index 0000000..6f4c55c --- /dev/null +++ b/ext/misc/cksumvfs.c @@ -0,0 +1,916 @@ +/* +** 2020-04-20 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file implements a VFS shim that writes a checksum on each page +** of an SQLite database file. When reading pages, the checksum is verified +** and an error is raised if the checksum is incorrect. +** +** COMPILING +** +** This extension requires SQLite 3.32.0 or later. It uses the +** sqlite3_database_file_object() interface which was added in +** version 3.32.0, so it will not link with an earlier version of +** SQLite. +** +** To build this extension as a separately loaded shared library or +** DLL, use compiler command-lines similar to the following: +** +** (linux) gcc -fPIC -shared cksumvfs.c -o cksumvfs.so +** (mac) clang -fPIC -dynamiclib cksumvfs.c -o cksumvfs.dylib +** (windows) cl cksumvfs.c -link -dll -out:cksumvfs.dll +** +** You may want to add additional compiler options, of course, +** according to the needs of your project. +** +** If you want to statically link this extension with your product, +** then compile it like any other C-language module but add the +** "-DSQLITE_CKSUMVFS_STATIC" option so that this module knows that +** it is being statically linked rather than dynamically linked +** +** LOADING +** +** To load this extension as a shared library, you first have to +** bring up a dummy SQLite database connection to use as the argument +** to the sqlite3_load_extension() API call. Then you invoke the +** sqlite3_load_extension() API and shutdown the dummy database +** connection. All subsequent database connections that are opened +** will include this extension. For example: +** +** sqlite3 *db; +** sqlite3_open(":memory:", &db); +** sqlite3_load_extension(db, "./cksumvfs"); +** sqlite3_close(db); +** +** If this extension is compiled with -DSQLITE_CKSUMVFS_STATIC and +** statically linked against the application, initialize it using +** a single API call as follows: +** +** sqlite3_register_cksumvfs(); +** +** Cksumvfs is a VFS Shim. When loaded, "cksmvfs" becomes the new +** default VFS and it uses the prior default VFS as the next VFS +** down in the stack. This is normally what you want. However, in +** complex situations where multiple VFS shims are being loaded, +** it might be important to ensure that cksumvfs is loaded in the +** correct order so that it sequences itself into the default VFS +** Shim stack in the right order. +** +** USING +** +** Open database connections using the sqlite3_open() or +** sqlite3_open_v2() interfaces, as normal. Ordinary database files +** (without a checksum) will operate normally. Databases with +** checksums will return an SQLITE_IOERR_DATA error if a page is +** encountered that contains an invalid checksum. +** +** Checksumming only works on databases that have a reserve-bytes +** value of exactly 8. The default value for reserve-bytes is 0. +** Hence, newly created database files will omit the checksum by +** default. To create a database that includes a checksum, change +** the reserve-bytes value to 8 by runing: +** +** int n = 8; +** sqlite3_file_control(db, 0, SQLITE_FCNTL_RESERVE_BYTES, &n); +** +** If you do this immediately after creating a new database file, +** before anything else has been written into the file, then that +** might be all that you need to do. Otherwise, the API call +** above should be followed by: +** +** sqlite3_exec(db, "VACUUM", 0, 0, 0); +** +** It never hurts to run the VACUUM, even if you don't need it. +** If the database is in WAL mode, you should shutdown and +** reopen all database connections before continuing. +** +** From the CLI, use the ".filectrl reserve_bytes 8" command, +** followed by "VACUUM;". +** +** Note that SQLite allows the number of reserve-bytes to be +** increased but not decreased. So if a database file already +** has a reserve-bytes value greater than 8, there is no way to +** activate checksumming on that database, other than to dump +** and restore the database file. Note also that other extensions +** might also make use of the reserve-bytes. Checksumming will +** be incompatible with those other extensions. +** +** VERIFICATION OF CHECKSUMS +** +** If any checksum is incorrect, the "PRAGMA quick_check" command +** will find it. To verify that checksums are actually enabled +** and running, use the following query: +** +** SELECT count(*), verify_checksum(data) +** FROM sqlite_dbpage +** GROUP BY 2; +** +** There are three possible outputs form the verify_checksum() +** function: 1, 0, and NULL. 1 is returned if the checksum is +** correct. 0 is returned if the checksum is incorrect. NULL +** is returned if the page is unreadable. If checksumming is +** enabled, the read will fail if the checksum is wrong, so the +** usual result from verify_checksum() on a bad checksum is NULL. +** +** If everything is OK, the query above should return a single +** row where the second column is 1. Any other result indicates +** either that there is a checksum error, or checksum validation +** is disabled. +** +** CONTROLLING CHECKSUM VERIFICATION +** +** The cksumvfs extension implements a new PRAGMA statement that can +** be used to disable, re-enable, or query the status of checksum +** verification: +** +** PRAGMA checksum_verification; -- query status +** PRAGMA checksum_verification=OFF; -- disable verification +** PRAGMA checksum_verification=ON; -- re-enable verification +** +** The "checksum_verification" pragma will return "1" (true) or "0" +** (false) if checksum verification is enabled or disabled, respectively. +** "Verification" in this context means the feature that causes +** SQLITE_IOERR_DATA errors if a checksum mismatch is detected while +** reading. Checksums are always kept up-to-date as long as the +** reserve-bytes value of the database is 8, regardless of the setting +** of this pragma. Checksum verification can be disabled (for example) +** to do forensic analysis of a database that has previously reported +** a checksum error. +** +** The "checksum_verification" pragma will always respond with "0" if +** the database file does not have a reserve-bytes value of 8. The +** pragma will return no rows at all if the cksumvfs extension is +** not loaded. +** +** IMPLEMENTATION NOTES +** +** The checksum is stored in the last 8 bytes of each page. This +** module only operates if the "bytes of reserved space on each page" +** value at offset 20 the SQLite database header is exactly 8. If +** the reserved-space value is not 8, this module is a no-op. +*/ +#if defined(SQLITE_AMALGAMATION) && !defined(SQLITE_CKSUMVFS_STATIC) +# define SQLITE_CKSUMVFS_STATIC +#endif +#ifdef SQLITE_CKSUMVFS_STATIC +# include "sqlite3.h" +#else +# include "sqlite3ext.h" + SQLITE_EXTENSION_INIT1 +#endif +#include +#include + +// hw export the symbols +#ifdef SQLITE_EXPORT_SYMBOLS +#if defined(__GNUC__) +# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) +#elif defined(_MSC_VER) +# define EXPORT_SYMBOLS __declspec(dllexport) +#else +# define EXPORT_SYMBOLS +#endif +#endif + +/* +** Forward declaration of objects used by this utility +*/ +typedef struct sqlite3_vfs CksmVfs; +typedef struct CksmFile CksmFile; + +/* +** Useful datatype abbreviations +*/ +#if !defined(SQLITE_AMALGAMATION) + typedef unsigned char u8; + typedef unsigned int u32; +#endif + +/* Access to a lower-level VFS that (might) implement dynamic loading, +** access to randomness, etc. +*/ +#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) +#define ORIGFILE(p) ((sqlite3_file*)(((CksmFile*)(p))+1)) + +/* An open file */ +struct CksmFile { + sqlite3_file base; /* IO methods */ + const char *zFName; /* Original name of the file */ + char computeCksm; /* True to compute checksums. + ** Always true if reserve size is 8. */ + char verifyCksm; /* True to verify checksums */ + char isWal; /* True if processing a WAL file */ + char inCkpt; /* Currently doing a checkpoint */ + CksmFile *pPartner; /* Ptr from WAL to main-db, or from main-db to WAL */ +}; + +/* +** Methods for CksmFile +*/ +static int cksmClose(sqlite3_file*); +static int cksmRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); +static int cksmWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); +static int cksmTruncate(sqlite3_file*, sqlite3_int64 size); +static int cksmSync(sqlite3_file*, int flags); +static int cksmFileSize(sqlite3_file*, sqlite3_int64 *pSize); +static int cksmLock(sqlite3_file*, int); +static int cksmUnlock(sqlite3_file*, int); +static int cksmCheckReservedLock(sqlite3_file*, int *pResOut); +static int cksmFileControl(sqlite3_file*, int op, void *pArg); +static int cksmSectorSize(sqlite3_file*); +static int cksmDeviceCharacteristics(sqlite3_file*); +static int cksmShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**); +static int cksmShmLock(sqlite3_file*, int offset, int n, int flags); +static void cksmShmBarrier(sqlite3_file*); +static int cksmShmUnmap(sqlite3_file*, int deleteFlag); +static int cksmFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); +static int cksmUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p); + +/* +** Methods for CksmVfs +*/ +static int cksmOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); +static int cksmDelete(sqlite3_vfs*, const char *zName, int syncDir); +static int cksmAccess(sqlite3_vfs*, const char *zName, int flags, int *); +static int cksmFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); +static void *cksmDlOpen(sqlite3_vfs*, const char *zFilename); +static void cksmDlError(sqlite3_vfs*, int nByte, char *zErrMsg); +static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void); +static void cksmDlClose(sqlite3_vfs*, void*); +static int cksmRandomness(sqlite3_vfs*, int nByte, char *zOut); +static int cksmSleep(sqlite3_vfs*, int microseconds); +static int cksmCurrentTime(sqlite3_vfs*, double*); +static int cksmGetLastError(sqlite3_vfs*, int, char *); +static int cksmCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); +static int cksmSetSystemCall(sqlite3_vfs*, const char*,sqlite3_syscall_ptr); +static sqlite3_syscall_ptr cksmGetSystemCall(sqlite3_vfs*, const char *z); +static const char *cksmNextSystemCall(sqlite3_vfs*, const char *zName); + +static sqlite3_vfs cksm_vfs = { + 3, /* iVersion (set when registered) */ + 0, /* szOsFile (set when registered) */ + 1024, /* mxPathname */ + 0, /* pNext */ + "cksmvfs", /* zName */ + 0, /* pAppData (set when registered) */ + cksmOpen, /* xOpen */ + cksmDelete, /* xDelete */ + cksmAccess, /* xAccess */ + cksmFullPathname, /* xFullPathname */ + cksmDlOpen, /* xDlOpen */ + cksmDlError, /* xDlError */ + cksmDlSym, /* xDlSym */ + cksmDlClose, /* xDlClose */ + cksmRandomness, /* xRandomness */ + cksmSleep, /* xSleep */ + cksmCurrentTime, /* xCurrentTime */ + cksmGetLastError, /* xGetLastError */ + cksmCurrentTimeInt64, /* xCurrentTimeInt64 */ + cksmSetSystemCall, /* xSetSystemCall */ + cksmGetSystemCall, /* xGetSystemCall */ + cksmNextSystemCall /* xNextSystemCall */ +}; + +static const sqlite3_io_methods cksm_io_methods = { + 3, /* iVersion */ + cksmClose, /* xClose */ + cksmRead, /* xRead */ + cksmWrite, /* xWrite */ + cksmTruncate, /* xTruncate */ + cksmSync, /* xSync */ + cksmFileSize, /* xFileSize */ + cksmLock, /* xLock */ + cksmUnlock, /* xUnlock */ + cksmCheckReservedLock, /* xCheckReservedLock */ + cksmFileControl, /* xFileControl */ + cksmSectorSize, /* xSectorSize */ + cksmDeviceCharacteristics, /* xDeviceCharacteristics */ + cksmShmMap, /* xShmMap */ + cksmShmLock, /* xShmLock */ + cksmShmBarrier, /* xShmBarrier */ + cksmShmUnmap, /* xShmUnmap */ + cksmFetch, /* xFetch */ + cksmUnfetch /* xUnfetch */ +}; + +/* Do byte swapping on a unsigned 32-bit integer */ +#define BYTESWAP32(x) ( \ + (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \ + + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \ +) + +/* Compute a checksum on a buffer */ +static void cksmCompute( + u8 *a, /* Content to be checksummed */ + int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */ + u8 *aOut /* OUT: Final 8-byte checksum value output */ +){ + u32 s1 = 0, s2 = 0; + u32 *aData = (u32*)a; + u32 *aEnd = (u32*)&a[nByte]; + u32 x = 1; + + assert( nByte>=8 ); + assert( (nByte&0x00000007)==0 ); + assert( nByte<=65536 ); + + if( 1 == *(u8*)&x ){ + /* Little-endian */ + do { + s1 += *aData++ + s2; + s2 += *aData++ + s1; + }while( aData65536 || (nByte & (nByte-1))!=0 ) return; + cksmCompute(data, nByte-8, cksum); + sqlite3_result_int(context, memcmp(data+nByte-8,cksum,8)==0); +} + +#ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME +/* +** SQL function: initialize_cksumvfs(SCHEMANAME) +** +** This SQL functions (whose name is actually determined at compile-time +** by the value of the SQLITE_CKSUMVFS_INIT_FUNCNAME macro) invokes: +** +** sqlite3_file_control(db, SCHEMANAME, SQLITE_FCNTL_RESERVE_BYTE, &n); +** +** In order to set the reserve bytes value to 8, so that cksumvfs will +** operation. This feature is provided (if and only if the +** SQLITE_CKSUMVFS_INIT_FUNCNAME compile-time option is set to a string +** which is the name of the SQL function) so as to provide the ability +** to invoke the file-control in programming languages that lack +** direct access to the sqlite3_file_control() interface (ex: Java). +** +** This interface is undocumented, apart from this comment. Usage +** example: +** +** 1. Compile with -DSQLITE_CKSUMVFS_INIT_FUNCNAME="ckvfs_init" +** 2. Run: "SELECT cksum_init('main'); VACUUM;" +*/ +static void cksmInitFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + int nByte = 8; + const char *zSchemaName = (const char*)sqlite3_value_text(argv[0]); + sqlite3 *db = sqlite3_context_db_handle(context); + sqlite3_file_control(db, zSchemaName, SQLITE_FCNTL_RESERVE_BYTES, &nByte); + /* Return NULL */ +} +#endif /* SQLITE_CKSUMBFS_INIT_FUNCNAME */ + +/* +** Close a cksm-file. +*/ +static int cksmClose(sqlite3_file *pFile){ + CksmFile *p = (CksmFile *)pFile; + if( p->pPartner ){ + assert( p->pPartner->pPartner==p ); + p->pPartner->pPartner = 0; + p->pPartner = 0; + } + pFile = ORIGFILE(pFile); + return pFile->pMethods->xClose(pFile); +} + +/* +** Set the computeCkSm and verifyCksm flags, if they need to be +** changed. +*/ +static void cksmSetFlags(CksmFile *p, int hasCorrectReserveSize){ + if( hasCorrectReserveSize!=p->computeCksm ){ + p->computeCksm = p->verifyCksm = hasCorrectReserveSize; + if( p->pPartner ){ + p->pPartner->verifyCksm = hasCorrectReserveSize; + p->pPartner->computeCksm = hasCorrectReserveSize; + } + } +} + +static void EncodeReservedBytesIntoBase16(const u8 *reserved, int len, char *encodeStr, int maxLen){ + static const char baseCode[] = "0123456789ABCDEF"; + for(int i=0; i> 4) & 0x0F]; + *encodeStr++ = baseCode[reserved[i] & 0x0F]; + } + *encodeStr = '0'; +} + +/* +** Read data from a cksm-file. +*/ +static int cksmRead( + sqlite3_file *pFile, + void *zBuf, + int iAmt, + sqlite_int64 iOfst +){ + int rc; + CksmFile *p = (CksmFile *)pFile; + pFile = ORIGFILE(pFile); + rc = pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst); + if( rc==SQLITE_OK ){ + if( iOfst==0 && iAmt>=100 && ( + memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0 + )){ + u8 *d = (u8*)zBuf; + char hasCorrectReserveSize = (d[20]==8); + cksmSetFlags(p, hasCorrectReserveSize); + } + /* Verify the checksum if + ** (1) the size indicates that we are dealing with a complete + ** database page, only support pageSize:4K + ** (2) checksum verification is enabled + ** (3) we are not in the middle of checkpoint + */ + if( iAmt==4096 /* (1) */ + && p->verifyCksm /* (2) */ + && !p->inCkpt /* (3) */ + ){ + u8 cksum[8]; + cksmCompute((u8*)zBuf, iAmt-8, cksum); + if( memcmp((u8*)zBuf+iAmt-8, cksum, 8)!=0 ){ + char expect[18] = {0}; + char actual[18] = {0}; + EncodeReservedBytesIntoBase16((u8 *)zBuf+iAmt-8, 8, expect, 18); + EncodeReservedBytesIntoBase16(cksum, 8, actual, 18); + sqlite3_log(SQLITE_IOERR_DATA, "checksum fault offset %lld of \"%s\", amt:%d, expect:%s, actual:%s", + iOfst, p->zFName, iAmt, expect, actual); + rc = SQLITE_IOERR_DATA; + } + } + } + return rc; +} + +/* +** Write data to a cksm-file. +*/ +static int cksmWrite( + sqlite3_file *pFile, + const void *zBuf, + int iAmt, + sqlite_int64 iOfst +){ + CksmFile *p = (CksmFile *)pFile; + pFile = ORIGFILE(pFile); + if( iOfst==0 && iAmt>=100 && ( + memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0 + )){ + u8 *d = (u8*)zBuf; + char hasCorrectReserveSize = (d[20]==8); + cksmSetFlags(p, hasCorrectReserveSize); + } + /* If the write size is appropriate for a database page and if + ** checksums where ever enabled, then it will be safe to compute + ** the checksums. The reserve byte size might have increased, but + ** it will never decrease. And because it cannot decrease, the + ** checksum will not overwrite anything. + */ + if( iAmt==4096 + && p->computeCksm + && !p->inCkpt + ){ + cksmCompute((u8*)zBuf, iAmt-8, ((u8*)zBuf)+iAmt-8); + } + return pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst); +} + +/* +** Truncate a cksm-file. +*/ +static int cksmTruncate(sqlite3_file *pFile, sqlite_int64 size){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xTruncate(pFile, size); +} + +/* +** Sync a cksm-file. +*/ +static int cksmSync(sqlite3_file *pFile, int flags){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xSync(pFile, flags); +} + +/* +** Return the current file-size of a cksm-file. +*/ +static int cksmFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ + CksmFile *p = (CksmFile *)pFile; + pFile = ORIGFILE(p); + return pFile->pMethods->xFileSize(pFile, pSize); +} + +/* +** Lock a cksm-file. +*/ +static int cksmLock(sqlite3_file *pFile, int eLock){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xLock(pFile, eLock); +} + +/* +** Unlock a cksm-file. +*/ +static int cksmUnlock(sqlite3_file *pFile, int eLock){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xUnlock(pFile, eLock); +} + +/* +** Check if another file-handle holds a RESERVED lock on a cksm-file. +*/ +static int cksmCheckReservedLock(sqlite3_file *pFile, int *pResOut){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xCheckReservedLock(pFile, pResOut); +} + +/* +** File control method. For custom operations on a cksm-file. +*/ +static int cksmFileControl(sqlite3_file *pFile, int op, void *pArg){ + int rc; + CksmFile *p = (CksmFile*)pFile; + pFile = ORIGFILE(pFile); + if( op==SQLITE_FCNTL_PRAGMA ){ + char **azArg = (char**)pArg; + assert( azArg[1]!=0 ); + if( sqlite3_stricmp(azArg[1],"checksum_verification")==0 ){ + char *zArg = azArg[2]; + if( zArg!=0 ){ + if( (zArg[0]>='1' && zArg[0]<='9') + || sqlite3_strlike("enable%",zArg,0)==0 + || sqlite3_stricmp("yes",zArg)==0 + || sqlite3_stricmp("on",zArg)==0 + ){ + p->verifyCksm = p->computeCksm; + }else{ + p->verifyCksm = 0; + } + if( p->pPartner ) p->pPartner->verifyCksm = p->verifyCksm; + } + azArg[0] = sqlite3_mprintf("%d",p->verifyCksm); + return SQLITE_OK; + }else if( p->computeCksm && azArg[2]!=0 + && sqlite3_stricmp(azArg[1], "page_size")==0 ){ + /* Do not allow page size changes on a checksum database */ + return SQLITE_OK; + } + }else if( op==SQLITE_FCNTL_CKPT_START || op==SQLITE_FCNTL_CKPT_DONE ){ + p->inCkpt = op==SQLITE_FCNTL_CKPT_START; + if( p->pPartner ) p->pPartner->inCkpt = p->inCkpt; + }else if( op==SQLITE_FCNTL_CKSM_FILE ){ + /* This VFS needs to obtain a pointer to the corresponding database + ** file handle from within xOpen() calls to open wal files. To do this, + ** it uses the sqlite3_database_file_object() API to obtain a pointer + ** to the file-handle used by SQLite to access the db file. This is + ** fine if cksmvfs happens to be the top-level VFS, but not if there + ** are one or more wrapper VFS. To handle this case, this file-control + ** is used to extract the cksmvfs file-handle from any wrapper file + ** handle. */ + sqlite3_file **ppFile = (sqlite3_file**)pArg; + *ppFile = (sqlite3_file*)p; + return SQLITE_OK; + } + rc = pFile->pMethods->xFileControl(pFile, op, pArg); + if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){ + *(char**)pArg = sqlite3_mprintf("cksm/%z", *(char**)pArg); + } + return rc; +} + +/* +** Return the sector-size in bytes for a cksm-file. +*/ +static int cksmSectorSize(sqlite3_file *pFile){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xSectorSize(pFile); +} + +/* +** Return the device characteristic flags supported by a cksm-file. +*/ +static int cksmDeviceCharacteristics(sqlite3_file *pFile){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xDeviceCharacteristics(pFile); +} + +/* Create a shared memory file mapping */ +static int cksmShmMap( + sqlite3_file *pFile, + int iPg, + int pgsz, + int bExtend, + void volatile **pp +){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp); +} + +/* Perform locking on a shared-memory segment */ +static int cksmShmLock(sqlite3_file *pFile, int offset, int n, int flags){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xShmLock(pFile,offset,n,flags); +} + +/* Memory barrier operation on shared memory */ +static void cksmShmBarrier(sqlite3_file *pFile){ + pFile = ORIGFILE(pFile); + pFile->pMethods->xShmBarrier(pFile); +} + +/* Unmap a shared memory segment */ +static int cksmShmUnmap(sqlite3_file *pFile, int deleteFlag){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xShmUnmap(pFile,deleteFlag); +} + +/* Fetch a page of a memory-mapped file */ +static int cksmFetch( + sqlite3_file *pFile, + sqlite3_int64 iOfst, + int iAmt, + void **pp +){ + CksmFile *p = (CksmFile *)pFile; + if( p->computeCksm ){ + *pp = 0; + return SQLITE_OK; + } + pFile = ORIGFILE(pFile); + if( pFile->pMethods->iVersion>2 && pFile->pMethods->xFetch ){ + return pFile->pMethods->xFetch(pFile, iOfst, iAmt, pp); + } + *pp = 0; + return SQLITE_OK; +} + +/* Release a memory-mapped page */ +static int cksmUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ + pFile = ORIGFILE(pFile); + if( pFile->pMethods->iVersion>2 && pFile->pMethods->xUnfetch ){ + return pFile->pMethods->xUnfetch(pFile, iOfst, pPage); + } + return SQLITE_OK; +} + +/* +** Open a cksm file handle. +*/ +static int cksmOpen( + sqlite3_vfs *pVfs, + const char *zName, + sqlite3_file *pFile, + int flags, + int *pOutFlags +){ + CksmFile *p; + sqlite3_file *pSubFile; + sqlite3_vfs *pSubVfs; + int rc; + pSubVfs = ORIGVFS(pVfs); + if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){ + return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags); + } + p = (CksmFile*)pFile; + memset(p, 0, sizeof(*p)); + pSubFile = ORIGFILE(pFile); + pFile->pMethods = &cksm_io_methods; + rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags); + if( rc ) goto cksm_open_done; + if( flags & SQLITE_OPEN_WAL ){ + sqlite3_file *pDb = sqlite3_database_file_object(zName); + rc = pDb->pMethods->xFileControl(pDb, SQLITE_FCNTL_CKSM_FILE, (void*)&pDb); + assert( rc==SQLITE_OK ); + p->pPartner = (CksmFile*)pDb; + assert( p->pPartner->pPartner==0 ); + p->pPartner->pPartner = p; + p->isWal = 1; + p->computeCksm = p->pPartner->computeCksm; + }else{ + p->isWal = 0; + p->computeCksm = 0; + } + p->zFName = zName; +cksm_open_done: + if( rc ) pFile->pMethods = 0; + return rc; +} + +/* +** All other VFS methods are pass-thrus. +*/ +static int cksmDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ + return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync); +} +static int cksmAccess( + sqlite3_vfs *pVfs, + const char *zPath, + int flags, + int *pResOut +){ + return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut); +} +static int cksmFullPathname( + sqlite3_vfs *pVfs, + const char *zPath, + int nOut, + char *zOut +){ + return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut); +} +static void *cksmDlOpen(sqlite3_vfs *pVfs, const char *zPath){ + return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath); +} +static void cksmDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ + ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg); +} +static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ + return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym); +} +static void cksmDlClose(sqlite3_vfs *pVfs, void *pHandle){ + ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle); +} +static int cksmRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ + return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut); +} +static int cksmSleep(sqlite3_vfs *pVfs, int nMicro){ + return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro); +} +static int cksmCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ + return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut); +} +static int cksmGetLastError(sqlite3_vfs *pVfs, int a, char *b){ + return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b); +} +static int cksmCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){ + sqlite3_vfs *pOrig = ORIGVFS(pVfs); + int rc; + assert( pOrig->iVersion>=2 ); + if( pOrig->xCurrentTimeInt64 ){ + rc = pOrig->xCurrentTimeInt64(pOrig, p); + }else{ + double r; + rc = pOrig->xCurrentTime(pOrig, &r); + *p = (sqlite3_int64)(r*86400000.0); + } + return rc; +} +static int cksmSetSystemCall( + sqlite3_vfs *pVfs, + const char *zName, + sqlite3_syscall_ptr pCall +){ + return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall); +} +static sqlite3_syscall_ptr cksmGetSystemCall( + sqlite3_vfs *pVfs, + const char *zName +){ + return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName); +} +static const char *cksmNextSystemCall(sqlite3_vfs *pVfs, const char *zName){ + return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName); +} + +/* Register the verify_checksum() SQL function. +*/ +static int cksmRegisterFunc( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + int rc; + if( db==0 ) return SQLITE_OK; + rc = sqlite3_create_function(db, "verify_checksum", 1, + SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, + 0, cksmVerifyFunc, 0, 0); +#ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME + (void)sqlite3_create_function(db, SQLITE_CKSUMVFS_INIT_FUNCNAME, 1, + SQLITE_UTF8|SQLITE_DIRECTONLY, + 0, cksmInitFunc, 0, 0); +#endif + return rc; +} + +/* +** Register the cksum VFS as the default VFS for the system. +** Also make arrangements to automatically register the "verify_checksum()" +** SQL function on each new database connection. +*/ +static int cksmRegisterVfs(void){ + int rc = SQLITE_OK; + sqlite3_vfs *pOrig; + if( sqlite3_vfs_find("cksmvfs")!=0 ) return SQLITE_OK; + pOrig = sqlite3_vfs_find(0); + if( pOrig==0 ) return SQLITE_ERROR; + cksm_vfs.iVersion = pOrig->iVersion; + cksm_vfs.pAppData = pOrig; + cksm_vfs.szOsFile = pOrig->szOsFile + sizeof(CksmFile); + rc = sqlite3_vfs_register(&cksm_vfs, 1); + if( rc==SQLITE_OK ){ + rc = sqlite3_auto_extension((void(*)(void))cksmRegisterFunc); + } + return rc; +} + +#if defined(SQLITE_CKSUMVFS_STATIC) +/* This variant of the initializer runs when the extension is +** statically linked. +*/ +int sqlite3_register_cksumvfs(const char *NotUsed){ + (void)NotUsed; + return cksmRegisterVfs(); +} +int sqlite3_unregister_cksumvfs(void){ + if( sqlite3_vfs_find("cksmvfs") ){ + sqlite3_vfs_unregister(&cksm_vfs); + sqlite3_cancel_auto_extension((void(*)(void))cksmRegisterFunc); + } + return SQLITE_OK; +} +#endif /* defined(SQLITE_CKSUMVFS_STATIC */ + +#if !defined(SQLITE_CKSUMVFS_STATIC) +/* This variant of the initializer function is used when the +** extension is shared library to be loaded at run-time. +*/ +#ifdef _WIN32 +__declspec(dllexport) +#endif +/* +** This routine is called by sqlite3_load_extension() when the +** extension is first loaded. +***/ +int sqlite3_cksumvfs_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + int rc; + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* not used */ + rc = cksmRegisterFunc(db, 0, 0); + if( rc==SQLITE_OK ){ + rc = cksmRegisterVfs(); + } + if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; + return rc; +} +#endif /* !defined(SQLITE_CKSUMVFS_STATIC) */ + +#ifdef SQLITE_CKSUMVFS_STATIC +struct sqlite3_api_routines_cksumvfs { + int (*register_cksumvfs)(const char *); + int (*unregister_cksumvfs)(); +}; +typedef struct sqlite3_api_routines_cksumvfs sqlite3_api_routines_cksumvfs; +static const sqlite3_api_routines_cksumvfs sqlite3CksumvfsApis = { + sqlite3_register_cksumvfs, + sqlite3_unregister_cksumvfs +}; + +EXPORT_SYMBOLS const sqlite3_api_routines_cksumvfs *sqlite3_export_cksumvfs_symbols = &sqlite3CksumvfsApis; +#endif diff --git a/src/sqlite3.c b/src/sqlite3.c index ad7ce74..f59ac55 100644 --- a/src/sqlite3.c +++ b/src/sqlite3.c @@ -57046,17 +57046,70 @@ static int jrnlBufferSize(Pager *pPager){ ** and debugging only. */ #ifdef SQLITE_CHECK_PAGES -/* -** Return a 32-bit hash of the page data for pPage. -*/ -static u32 pager_datahash(int nByte, unsigned char *pData){ +#if defined (__arm__) || defined (__aarch64__) +#include +u32 deep_fast_hash_arm(void *src, int srcLen){ + uint16_t chunkSize = srcLen/4; + uint8_t *u8p_src = (uint8_t *)src; + uint16x8_t m_prime = vdupq_n_u16(44497); + uint16x8_t m_res0 = vdupq_n_u16(0); + uint16x8_t m_res1 = vdupq_n_u16(0); + uint16x8_t m_res2 = vdupq_n_u16(0); + uint16x8_t m_res3 = vdupq_n_u16(0); + uint16x8_t m_res4 = vdupq_n_u16(0); + uint16x8_t m_res5 = vdupq_n_u16(0); + uint16x8_t m_res6 = vdupq_n_u16(0); + uint16x8_t m_res7 = vdupq_n_u16(0); + + for(int i=0; ipPager->pageSize, (unsigned char *)pPage->pData); } @@ -57072,8 +57125,15 @@ static void pager_set_pagehash(PgHdr *pPage){ #define CHECK_PAGE(x) checkPage(x) static void checkPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; - assert( pPager->eState!=PAGER_ERROR ); - assert( (pPg->flags&PGHDR_DIRTY) || pPg->pageHash==pager_pagehash(pPg) ); + if( pPager->eState==PAGER_ERROR ){ + return; + } + if( pPg->flags&PGHDR_DIRTY ) { + return; + } + if( pPg->pgno!=1 && pPg->pageHash!=pager_pagehash(pPg) ){ + sqlite3_log(SQLITE_CORRUPT, "cache corruption occurs through checking page(%u)", pPg->pgno); + } } #else @@ -178288,12 +178348,16 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager); rc = SQLITE_OK; }else if( op==SQLITE_FCNTL_RESERVE_BYTES ){ +#ifndef SQLITE_CKSUMVFS_STATIC + rc = SQLITE_OK; +#else int iNew = *(int*)pArg; *(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree); if( iNew>=0 && iNew<=255 ){ sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0); } rc = SQLITE_OK; +#endif }else if( op==SQLITE_FCNTL_RESET_CACHE ){ sqlite3BtreeClearCache(pBtree); rc = SQLITE_OK; @@ -247458,6 +247522,27 @@ static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime #endif // hw export the symbols #ifdef SQLITE_EXPORT_SYMBOLS +#ifndef SQLITE_CKSUMVFS_STATIC +int sqlite3_register_cksumvfs(const char *NotUsed){ + return SQLITE_MISUSE; +} +int sqlite3_unregister_cksumvfs(void){ + return SQLITE_MISUSE; +} + +struct sqlite3_api_routines_cksumvfs { + int (*register_cksumvfs)(const char *); + int (*unregister_cksumvfs)(); +}; +typedef struct sqlite3_api_routines_cksumvfs sqlite3_api_routines_cksumvfs; +static const sqlite3_api_routines_cksumvfs sqlite3CksumvfsApis = { + sqlite3_register_cksumvfs, + sqlite3_unregister_cksumvfs +}; + +EXPORT_SYMBOLS const sqlite3_api_routines_cksumvfs *sqlite3_export_cksumvfs_symbols = &sqlite3CksumvfsApis; +#endif + struct sqlite3_api_routines_hw { int (*initialize)(); int (*config)(int,...); -- Gitee From 064dc5a3f136f5135b3ae9d07a1662a2a569d98a Mon Sep 17 00:00:00 2001 From: wanghaishuo Date: Sat, 12 Apr 2025 11:13:36 +0800 Subject: [PATCH 8/9] current bugs fixes Signed-off-by: ryne3366 --- src/sqlite3.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/sqlite3.c b/src/sqlite3.c index f59ac55..fedd390 100644 --- a/src/sqlite3.c +++ b/src/sqlite3.c @@ -43267,6 +43267,9 @@ static int unixOpen( flags |= SQLITE_OPEN_READONLY; openFlags |= O_RDONLY; isReadonly = 1; +#ifdef LOG_DUMP + sqlite3_log(SQLITE_WARNING, "Try open file readonly sysno %d", errno); +#endif fd = robust_open(zName, openFlags, openMode); } } @@ -246320,7 +246323,7 @@ static int PragmaMetaDoubleWrie(sqlite3 *db, int iDb, Parse *parse, const char * sqlite3_mutex_enter(db->mutex); // only support enabled meta double write int rc = MetaDwrOpenAndCheck(pBt); - if (rc != SQLITE_OK) { + if (rc != SQLITE_OK && rc != SQLITE_PERM) { parse->nErr++; parse->rc = rc; } @@ -246776,6 +246779,29 @@ static inline const char *GetMetaFilePath(Pager *pPager) return pPager->metaFd == NULL ? NULL : ((const char *)pPager->metaFd + ROUND8(pPager->pVfs->szOsFile)); } +static int MetaDwrCheckPerm(sqlite3_vfs *pVfs, u8 openCreate, char *metaPath) { + int exists = 0; + int rc = sqlite3OsAccess(pVfs, metaPath, SQLITE_ACCESS_EXISTS, &exists); + if (rc != SQLITE_OK) { + return rc; + } + if (!exists && !openCreate) { + return SQLITE_PERM; + } +#ifdef HARMONY_OS + // check if the path have enough permission + rc = osAccess(metaPath, W_OK|R_OK); + if (rc == 0 || errno == ENOENT) { + return SQLITE_OK; + } + rc = SQLITE_PERM; + if (openCreate) { + sqlite3_log(SQLITE_WARNING_DUMP, "Meta double write disabled, sysno %d", errno); + } +#endif + return rc; +} + static int MetaDwrOpenFile(Pager *pPager, u8 openCreate) { if (pPager->metaFd || pPager->zFilename == NULL) { return SQLITE_OK; @@ -246792,15 +246818,10 @@ static int MetaDwrOpenFile(Pager *pPager, u8 openCreate) { return SQLITE_NOMEM_BKPT; } sqlite3_snprintf(size, metaPath, "%s-dwr", pPager->zFilename); - int exists = 0; - int rc = sqlite3OsAccess(pVfs, metaPath, SQLITE_ACCESS_EXISTS, &exists); + int rc = MetaDwrCheckPerm(pVfs, openCreate, metaPath); if (rc != SQLITE_OK) { goto INIT_META_OUT; } - if (!exists && !openCreate) { - sqlite3_free(metaFd); - goto INIT_META_OUT; - } u32 flags = (SQLITE_OPEN_READWRITE | SQLITE_OPEN_SUPER_JOURNAL); if (openCreate) { flags |= SQLITE_OPEN_CREATE; -- Gitee From 019bf2a885bb461738a0f912b9b684f9db698026 Mon Sep 17 00:00:00 2001 From: wanghaishuo Date: Sat, 12 Apr 2025 17:20:28 +0800 Subject: [PATCH 9/9] format patchs base on 3.40.1 Signed-off-by: ryne3366 --- ext/misc/cksumvfs.c | 916 --- ...ery-sharedmemory-drop-table-callback.patch | 3681 ++++++++++ patch/0002-add-busy-debug.patch | 818 +++ patch/0003-add-meta-dwr.patch | 1336 ++++ patch/0004-add-icu.patch | 2052 ++++++ patch/0005-corrupt-detect.patch | 1216 ++++ patch/0006-support-check-pages.patch | 1080 +++ patch/0007-current-bugs-fixes.patch | 83 + src/sqlite3.c | 6166 +++-------------- src/sqlite3icu.c | 892 --- 10 files changed, 11359 insertions(+), 6881 deletions(-) delete mode 100644 ext/misc/cksumvfs.c create mode 100644 patch/0001-codec-query-sharedmemory-drop-table-callback.patch create mode 100644 patch/0002-add-busy-debug.patch create mode 100644 patch/0003-add-meta-dwr.patch create mode 100644 patch/0004-add-icu.patch create mode 100644 patch/0005-corrupt-detect.patch create mode 100644 patch/0006-support-check-pages.patch create mode 100644 patch/0007-current-bugs-fixes.patch delete mode 100644 src/sqlite3icu.c diff --git a/ext/misc/cksumvfs.c b/ext/misc/cksumvfs.c deleted file mode 100644 index 6f4c55c..0000000 --- a/ext/misc/cksumvfs.c +++ /dev/null @@ -1,916 +0,0 @@ -/* -** 2020-04-20 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file implements a VFS shim that writes a checksum on each page -** of an SQLite database file. When reading pages, the checksum is verified -** and an error is raised if the checksum is incorrect. -** -** COMPILING -** -** This extension requires SQLite 3.32.0 or later. It uses the -** sqlite3_database_file_object() interface which was added in -** version 3.32.0, so it will not link with an earlier version of -** SQLite. -** -** To build this extension as a separately loaded shared library or -** DLL, use compiler command-lines similar to the following: -** -** (linux) gcc -fPIC -shared cksumvfs.c -o cksumvfs.so -** (mac) clang -fPIC -dynamiclib cksumvfs.c -o cksumvfs.dylib -** (windows) cl cksumvfs.c -link -dll -out:cksumvfs.dll -** -** You may want to add additional compiler options, of course, -** according to the needs of your project. -** -** If you want to statically link this extension with your product, -** then compile it like any other C-language module but add the -** "-DSQLITE_CKSUMVFS_STATIC" option so that this module knows that -** it is being statically linked rather than dynamically linked -** -** LOADING -** -** To load this extension as a shared library, you first have to -** bring up a dummy SQLite database connection to use as the argument -** to the sqlite3_load_extension() API call. Then you invoke the -** sqlite3_load_extension() API and shutdown the dummy database -** connection. All subsequent database connections that are opened -** will include this extension. For example: -** -** sqlite3 *db; -** sqlite3_open(":memory:", &db); -** sqlite3_load_extension(db, "./cksumvfs"); -** sqlite3_close(db); -** -** If this extension is compiled with -DSQLITE_CKSUMVFS_STATIC and -** statically linked against the application, initialize it using -** a single API call as follows: -** -** sqlite3_register_cksumvfs(); -** -** Cksumvfs is a VFS Shim. When loaded, "cksmvfs" becomes the new -** default VFS and it uses the prior default VFS as the next VFS -** down in the stack. This is normally what you want. However, in -** complex situations where multiple VFS shims are being loaded, -** it might be important to ensure that cksumvfs is loaded in the -** correct order so that it sequences itself into the default VFS -** Shim stack in the right order. -** -** USING -** -** Open database connections using the sqlite3_open() or -** sqlite3_open_v2() interfaces, as normal. Ordinary database files -** (without a checksum) will operate normally. Databases with -** checksums will return an SQLITE_IOERR_DATA error if a page is -** encountered that contains an invalid checksum. -** -** Checksumming only works on databases that have a reserve-bytes -** value of exactly 8. The default value for reserve-bytes is 0. -** Hence, newly created database files will omit the checksum by -** default. To create a database that includes a checksum, change -** the reserve-bytes value to 8 by runing: -** -** int n = 8; -** sqlite3_file_control(db, 0, SQLITE_FCNTL_RESERVE_BYTES, &n); -** -** If you do this immediately after creating a new database file, -** before anything else has been written into the file, then that -** might be all that you need to do. Otherwise, the API call -** above should be followed by: -** -** sqlite3_exec(db, "VACUUM", 0, 0, 0); -** -** It never hurts to run the VACUUM, even if you don't need it. -** If the database is in WAL mode, you should shutdown and -** reopen all database connections before continuing. -** -** From the CLI, use the ".filectrl reserve_bytes 8" command, -** followed by "VACUUM;". -** -** Note that SQLite allows the number of reserve-bytes to be -** increased but not decreased. So if a database file already -** has a reserve-bytes value greater than 8, there is no way to -** activate checksumming on that database, other than to dump -** and restore the database file. Note also that other extensions -** might also make use of the reserve-bytes. Checksumming will -** be incompatible with those other extensions. -** -** VERIFICATION OF CHECKSUMS -** -** If any checksum is incorrect, the "PRAGMA quick_check" command -** will find it. To verify that checksums are actually enabled -** and running, use the following query: -** -** SELECT count(*), verify_checksum(data) -** FROM sqlite_dbpage -** GROUP BY 2; -** -** There are three possible outputs form the verify_checksum() -** function: 1, 0, and NULL. 1 is returned if the checksum is -** correct. 0 is returned if the checksum is incorrect. NULL -** is returned if the page is unreadable. If checksumming is -** enabled, the read will fail if the checksum is wrong, so the -** usual result from verify_checksum() on a bad checksum is NULL. -** -** If everything is OK, the query above should return a single -** row where the second column is 1. Any other result indicates -** either that there is a checksum error, or checksum validation -** is disabled. -** -** CONTROLLING CHECKSUM VERIFICATION -** -** The cksumvfs extension implements a new PRAGMA statement that can -** be used to disable, re-enable, or query the status of checksum -** verification: -** -** PRAGMA checksum_verification; -- query status -** PRAGMA checksum_verification=OFF; -- disable verification -** PRAGMA checksum_verification=ON; -- re-enable verification -** -** The "checksum_verification" pragma will return "1" (true) or "0" -** (false) if checksum verification is enabled or disabled, respectively. -** "Verification" in this context means the feature that causes -** SQLITE_IOERR_DATA errors if a checksum mismatch is detected while -** reading. Checksums are always kept up-to-date as long as the -** reserve-bytes value of the database is 8, regardless of the setting -** of this pragma. Checksum verification can be disabled (for example) -** to do forensic analysis of a database that has previously reported -** a checksum error. -** -** The "checksum_verification" pragma will always respond with "0" if -** the database file does not have a reserve-bytes value of 8. The -** pragma will return no rows at all if the cksumvfs extension is -** not loaded. -** -** IMPLEMENTATION NOTES -** -** The checksum is stored in the last 8 bytes of each page. This -** module only operates if the "bytes of reserved space on each page" -** value at offset 20 the SQLite database header is exactly 8. If -** the reserved-space value is not 8, this module is a no-op. -*/ -#if defined(SQLITE_AMALGAMATION) && !defined(SQLITE_CKSUMVFS_STATIC) -# define SQLITE_CKSUMVFS_STATIC -#endif -#ifdef SQLITE_CKSUMVFS_STATIC -# include "sqlite3.h" -#else -# include "sqlite3ext.h" - SQLITE_EXTENSION_INIT1 -#endif -#include -#include - -// hw export the symbols -#ifdef SQLITE_EXPORT_SYMBOLS -#if defined(__GNUC__) -# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) -#elif defined(_MSC_VER) -# define EXPORT_SYMBOLS __declspec(dllexport) -#else -# define EXPORT_SYMBOLS -#endif -#endif - -/* -** Forward declaration of objects used by this utility -*/ -typedef struct sqlite3_vfs CksmVfs; -typedef struct CksmFile CksmFile; - -/* -** Useful datatype abbreviations -*/ -#if !defined(SQLITE_AMALGAMATION) - typedef unsigned char u8; - typedef unsigned int u32; -#endif - -/* Access to a lower-level VFS that (might) implement dynamic loading, -** access to randomness, etc. -*/ -#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) -#define ORIGFILE(p) ((sqlite3_file*)(((CksmFile*)(p))+1)) - -/* An open file */ -struct CksmFile { - sqlite3_file base; /* IO methods */ - const char *zFName; /* Original name of the file */ - char computeCksm; /* True to compute checksums. - ** Always true if reserve size is 8. */ - char verifyCksm; /* True to verify checksums */ - char isWal; /* True if processing a WAL file */ - char inCkpt; /* Currently doing a checkpoint */ - CksmFile *pPartner; /* Ptr from WAL to main-db, or from main-db to WAL */ -}; - -/* -** Methods for CksmFile -*/ -static int cksmClose(sqlite3_file*); -static int cksmRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); -static int cksmWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); -static int cksmTruncate(sqlite3_file*, sqlite3_int64 size); -static int cksmSync(sqlite3_file*, int flags); -static int cksmFileSize(sqlite3_file*, sqlite3_int64 *pSize); -static int cksmLock(sqlite3_file*, int); -static int cksmUnlock(sqlite3_file*, int); -static int cksmCheckReservedLock(sqlite3_file*, int *pResOut); -static int cksmFileControl(sqlite3_file*, int op, void *pArg); -static int cksmSectorSize(sqlite3_file*); -static int cksmDeviceCharacteristics(sqlite3_file*); -static int cksmShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**); -static int cksmShmLock(sqlite3_file*, int offset, int n, int flags); -static void cksmShmBarrier(sqlite3_file*); -static int cksmShmUnmap(sqlite3_file*, int deleteFlag); -static int cksmFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); -static int cksmUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p); - -/* -** Methods for CksmVfs -*/ -static int cksmOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); -static int cksmDelete(sqlite3_vfs*, const char *zName, int syncDir); -static int cksmAccess(sqlite3_vfs*, const char *zName, int flags, int *); -static int cksmFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); -static void *cksmDlOpen(sqlite3_vfs*, const char *zFilename); -static void cksmDlError(sqlite3_vfs*, int nByte, char *zErrMsg); -static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void); -static void cksmDlClose(sqlite3_vfs*, void*); -static int cksmRandomness(sqlite3_vfs*, int nByte, char *zOut); -static int cksmSleep(sqlite3_vfs*, int microseconds); -static int cksmCurrentTime(sqlite3_vfs*, double*); -static int cksmGetLastError(sqlite3_vfs*, int, char *); -static int cksmCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); -static int cksmSetSystemCall(sqlite3_vfs*, const char*,sqlite3_syscall_ptr); -static sqlite3_syscall_ptr cksmGetSystemCall(sqlite3_vfs*, const char *z); -static const char *cksmNextSystemCall(sqlite3_vfs*, const char *zName); - -static sqlite3_vfs cksm_vfs = { - 3, /* iVersion (set when registered) */ - 0, /* szOsFile (set when registered) */ - 1024, /* mxPathname */ - 0, /* pNext */ - "cksmvfs", /* zName */ - 0, /* pAppData (set when registered) */ - cksmOpen, /* xOpen */ - cksmDelete, /* xDelete */ - cksmAccess, /* xAccess */ - cksmFullPathname, /* xFullPathname */ - cksmDlOpen, /* xDlOpen */ - cksmDlError, /* xDlError */ - cksmDlSym, /* xDlSym */ - cksmDlClose, /* xDlClose */ - cksmRandomness, /* xRandomness */ - cksmSleep, /* xSleep */ - cksmCurrentTime, /* xCurrentTime */ - cksmGetLastError, /* xGetLastError */ - cksmCurrentTimeInt64, /* xCurrentTimeInt64 */ - cksmSetSystemCall, /* xSetSystemCall */ - cksmGetSystemCall, /* xGetSystemCall */ - cksmNextSystemCall /* xNextSystemCall */ -}; - -static const sqlite3_io_methods cksm_io_methods = { - 3, /* iVersion */ - cksmClose, /* xClose */ - cksmRead, /* xRead */ - cksmWrite, /* xWrite */ - cksmTruncate, /* xTruncate */ - cksmSync, /* xSync */ - cksmFileSize, /* xFileSize */ - cksmLock, /* xLock */ - cksmUnlock, /* xUnlock */ - cksmCheckReservedLock, /* xCheckReservedLock */ - cksmFileControl, /* xFileControl */ - cksmSectorSize, /* xSectorSize */ - cksmDeviceCharacteristics, /* xDeviceCharacteristics */ - cksmShmMap, /* xShmMap */ - cksmShmLock, /* xShmLock */ - cksmShmBarrier, /* xShmBarrier */ - cksmShmUnmap, /* xShmUnmap */ - cksmFetch, /* xFetch */ - cksmUnfetch /* xUnfetch */ -}; - -/* Do byte swapping on a unsigned 32-bit integer */ -#define BYTESWAP32(x) ( \ - (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \ - + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \ -) - -/* Compute a checksum on a buffer */ -static void cksmCompute( - u8 *a, /* Content to be checksummed */ - int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */ - u8 *aOut /* OUT: Final 8-byte checksum value output */ -){ - u32 s1 = 0, s2 = 0; - u32 *aData = (u32*)a; - u32 *aEnd = (u32*)&a[nByte]; - u32 x = 1; - - assert( nByte>=8 ); - assert( (nByte&0x00000007)==0 ); - assert( nByte<=65536 ); - - if( 1 == *(u8*)&x ){ - /* Little-endian */ - do { - s1 += *aData++ + s2; - s2 += *aData++ + s1; - }while( aData65536 || (nByte & (nByte-1))!=0 ) return; - cksmCompute(data, nByte-8, cksum); - sqlite3_result_int(context, memcmp(data+nByte-8,cksum,8)==0); -} - -#ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME -/* -** SQL function: initialize_cksumvfs(SCHEMANAME) -** -** This SQL functions (whose name is actually determined at compile-time -** by the value of the SQLITE_CKSUMVFS_INIT_FUNCNAME macro) invokes: -** -** sqlite3_file_control(db, SCHEMANAME, SQLITE_FCNTL_RESERVE_BYTE, &n); -** -** In order to set the reserve bytes value to 8, so that cksumvfs will -** operation. This feature is provided (if and only if the -** SQLITE_CKSUMVFS_INIT_FUNCNAME compile-time option is set to a string -** which is the name of the SQL function) so as to provide the ability -** to invoke the file-control in programming languages that lack -** direct access to the sqlite3_file_control() interface (ex: Java). -** -** This interface is undocumented, apart from this comment. Usage -** example: -** -** 1. Compile with -DSQLITE_CKSUMVFS_INIT_FUNCNAME="ckvfs_init" -** 2. Run: "SELECT cksum_init('main'); VACUUM;" -*/ -static void cksmInitFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - int nByte = 8; - const char *zSchemaName = (const char*)sqlite3_value_text(argv[0]); - sqlite3 *db = sqlite3_context_db_handle(context); - sqlite3_file_control(db, zSchemaName, SQLITE_FCNTL_RESERVE_BYTES, &nByte); - /* Return NULL */ -} -#endif /* SQLITE_CKSUMBFS_INIT_FUNCNAME */ - -/* -** Close a cksm-file. -*/ -static int cksmClose(sqlite3_file *pFile){ - CksmFile *p = (CksmFile *)pFile; - if( p->pPartner ){ - assert( p->pPartner->pPartner==p ); - p->pPartner->pPartner = 0; - p->pPartner = 0; - } - pFile = ORIGFILE(pFile); - return pFile->pMethods->xClose(pFile); -} - -/* -** Set the computeCkSm and verifyCksm flags, if they need to be -** changed. -*/ -static void cksmSetFlags(CksmFile *p, int hasCorrectReserveSize){ - if( hasCorrectReserveSize!=p->computeCksm ){ - p->computeCksm = p->verifyCksm = hasCorrectReserveSize; - if( p->pPartner ){ - p->pPartner->verifyCksm = hasCorrectReserveSize; - p->pPartner->computeCksm = hasCorrectReserveSize; - } - } -} - -static void EncodeReservedBytesIntoBase16(const u8 *reserved, int len, char *encodeStr, int maxLen){ - static const char baseCode[] = "0123456789ABCDEF"; - for(int i=0; i> 4) & 0x0F]; - *encodeStr++ = baseCode[reserved[i] & 0x0F]; - } - *encodeStr = '0'; -} - -/* -** Read data from a cksm-file. -*/ -static int cksmRead( - sqlite3_file *pFile, - void *zBuf, - int iAmt, - sqlite_int64 iOfst -){ - int rc; - CksmFile *p = (CksmFile *)pFile; - pFile = ORIGFILE(pFile); - rc = pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst); - if( rc==SQLITE_OK ){ - if( iOfst==0 && iAmt>=100 && ( - memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0 - )){ - u8 *d = (u8*)zBuf; - char hasCorrectReserveSize = (d[20]==8); - cksmSetFlags(p, hasCorrectReserveSize); - } - /* Verify the checksum if - ** (1) the size indicates that we are dealing with a complete - ** database page, only support pageSize:4K - ** (2) checksum verification is enabled - ** (3) we are not in the middle of checkpoint - */ - if( iAmt==4096 /* (1) */ - && p->verifyCksm /* (2) */ - && !p->inCkpt /* (3) */ - ){ - u8 cksum[8]; - cksmCompute((u8*)zBuf, iAmt-8, cksum); - if( memcmp((u8*)zBuf+iAmt-8, cksum, 8)!=0 ){ - char expect[18] = {0}; - char actual[18] = {0}; - EncodeReservedBytesIntoBase16((u8 *)zBuf+iAmt-8, 8, expect, 18); - EncodeReservedBytesIntoBase16(cksum, 8, actual, 18); - sqlite3_log(SQLITE_IOERR_DATA, "checksum fault offset %lld of \"%s\", amt:%d, expect:%s, actual:%s", - iOfst, p->zFName, iAmt, expect, actual); - rc = SQLITE_IOERR_DATA; - } - } - } - return rc; -} - -/* -** Write data to a cksm-file. -*/ -static int cksmWrite( - sqlite3_file *pFile, - const void *zBuf, - int iAmt, - sqlite_int64 iOfst -){ - CksmFile *p = (CksmFile *)pFile; - pFile = ORIGFILE(pFile); - if( iOfst==0 && iAmt>=100 && ( - memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0 - )){ - u8 *d = (u8*)zBuf; - char hasCorrectReserveSize = (d[20]==8); - cksmSetFlags(p, hasCorrectReserveSize); - } - /* If the write size is appropriate for a database page and if - ** checksums where ever enabled, then it will be safe to compute - ** the checksums. The reserve byte size might have increased, but - ** it will never decrease. And because it cannot decrease, the - ** checksum will not overwrite anything. - */ - if( iAmt==4096 - && p->computeCksm - && !p->inCkpt - ){ - cksmCompute((u8*)zBuf, iAmt-8, ((u8*)zBuf)+iAmt-8); - } - return pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst); -} - -/* -** Truncate a cksm-file. -*/ -static int cksmTruncate(sqlite3_file *pFile, sqlite_int64 size){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xTruncate(pFile, size); -} - -/* -** Sync a cksm-file. -*/ -static int cksmSync(sqlite3_file *pFile, int flags){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xSync(pFile, flags); -} - -/* -** Return the current file-size of a cksm-file. -*/ -static int cksmFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ - CksmFile *p = (CksmFile *)pFile; - pFile = ORIGFILE(p); - return pFile->pMethods->xFileSize(pFile, pSize); -} - -/* -** Lock a cksm-file. -*/ -static int cksmLock(sqlite3_file *pFile, int eLock){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xLock(pFile, eLock); -} - -/* -** Unlock a cksm-file. -*/ -static int cksmUnlock(sqlite3_file *pFile, int eLock){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xUnlock(pFile, eLock); -} - -/* -** Check if another file-handle holds a RESERVED lock on a cksm-file. -*/ -static int cksmCheckReservedLock(sqlite3_file *pFile, int *pResOut){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xCheckReservedLock(pFile, pResOut); -} - -/* -** File control method. For custom operations on a cksm-file. -*/ -static int cksmFileControl(sqlite3_file *pFile, int op, void *pArg){ - int rc; - CksmFile *p = (CksmFile*)pFile; - pFile = ORIGFILE(pFile); - if( op==SQLITE_FCNTL_PRAGMA ){ - char **azArg = (char**)pArg; - assert( azArg[1]!=0 ); - if( sqlite3_stricmp(azArg[1],"checksum_verification")==0 ){ - char *zArg = azArg[2]; - if( zArg!=0 ){ - if( (zArg[0]>='1' && zArg[0]<='9') - || sqlite3_strlike("enable%",zArg,0)==0 - || sqlite3_stricmp("yes",zArg)==0 - || sqlite3_stricmp("on",zArg)==0 - ){ - p->verifyCksm = p->computeCksm; - }else{ - p->verifyCksm = 0; - } - if( p->pPartner ) p->pPartner->verifyCksm = p->verifyCksm; - } - azArg[0] = sqlite3_mprintf("%d",p->verifyCksm); - return SQLITE_OK; - }else if( p->computeCksm && azArg[2]!=0 - && sqlite3_stricmp(azArg[1], "page_size")==0 ){ - /* Do not allow page size changes on a checksum database */ - return SQLITE_OK; - } - }else if( op==SQLITE_FCNTL_CKPT_START || op==SQLITE_FCNTL_CKPT_DONE ){ - p->inCkpt = op==SQLITE_FCNTL_CKPT_START; - if( p->pPartner ) p->pPartner->inCkpt = p->inCkpt; - }else if( op==SQLITE_FCNTL_CKSM_FILE ){ - /* This VFS needs to obtain a pointer to the corresponding database - ** file handle from within xOpen() calls to open wal files. To do this, - ** it uses the sqlite3_database_file_object() API to obtain a pointer - ** to the file-handle used by SQLite to access the db file. This is - ** fine if cksmvfs happens to be the top-level VFS, but not if there - ** are one or more wrapper VFS. To handle this case, this file-control - ** is used to extract the cksmvfs file-handle from any wrapper file - ** handle. */ - sqlite3_file **ppFile = (sqlite3_file**)pArg; - *ppFile = (sqlite3_file*)p; - return SQLITE_OK; - } - rc = pFile->pMethods->xFileControl(pFile, op, pArg); - if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){ - *(char**)pArg = sqlite3_mprintf("cksm/%z", *(char**)pArg); - } - return rc; -} - -/* -** Return the sector-size in bytes for a cksm-file. -*/ -static int cksmSectorSize(sqlite3_file *pFile){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xSectorSize(pFile); -} - -/* -** Return the device characteristic flags supported by a cksm-file. -*/ -static int cksmDeviceCharacteristics(sqlite3_file *pFile){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xDeviceCharacteristics(pFile); -} - -/* Create a shared memory file mapping */ -static int cksmShmMap( - sqlite3_file *pFile, - int iPg, - int pgsz, - int bExtend, - void volatile **pp -){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp); -} - -/* Perform locking on a shared-memory segment */ -static int cksmShmLock(sqlite3_file *pFile, int offset, int n, int flags){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xShmLock(pFile,offset,n,flags); -} - -/* Memory barrier operation on shared memory */ -static void cksmShmBarrier(sqlite3_file *pFile){ - pFile = ORIGFILE(pFile); - pFile->pMethods->xShmBarrier(pFile); -} - -/* Unmap a shared memory segment */ -static int cksmShmUnmap(sqlite3_file *pFile, int deleteFlag){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xShmUnmap(pFile,deleteFlag); -} - -/* Fetch a page of a memory-mapped file */ -static int cksmFetch( - sqlite3_file *pFile, - sqlite3_int64 iOfst, - int iAmt, - void **pp -){ - CksmFile *p = (CksmFile *)pFile; - if( p->computeCksm ){ - *pp = 0; - return SQLITE_OK; - } - pFile = ORIGFILE(pFile); - if( pFile->pMethods->iVersion>2 && pFile->pMethods->xFetch ){ - return pFile->pMethods->xFetch(pFile, iOfst, iAmt, pp); - } - *pp = 0; - return SQLITE_OK; -} - -/* Release a memory-mapped page */ -static int cksmUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ - pFile = ORIGFILE(pFile); - if( pFile->pMethods->iVersion>2 && pFile->pMethods->xUnfetch ){ - return pFile->pMethods->xUnfetch(pFile, iOfst, pPage); - } - return SQLITE_OK; -} - -/* -** Open a cksm file handle. -*/ -static int cksmOpen( - sqlite3_vfs *pVfs, - const char *zName, - sqlite3_file *pFile, - int flags, - int *pOutFlags -){ - CksmFile *p; - sqlite3_file *pSubFile; - sqlite3_vfs *pSubVfs; - int rc; - pSubVfs = ORIGVFS(pVfs); - if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){ - return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags); - } - p = (CksmFile*)pFile; - memset(p, 0, sizeof(*p)); - pSubFile = ORIGFILE(pFile); - pFile->pMethods = &cksm_io_methods; - rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags); - if( rc ) goto cksm_open_done; - if( flags & SQLITE_OPEN_WAL ){ - sqlite3_file *pDb = sqlite3_database_file_object(zName); - rc = pDb->pMethods->xFileControl(pDb, SQLITE_FCNTL_CKSM_FILE, (void*)&pDb); - assert( rc==SQLITE_OK ); - p->pPartner = (CksmFile*)pDb; - assert( p->pPartner->pPartner==0 ); - p->pPartner->pPartner = p; - p->isWal = 1; - p->computeCksm = p->pPartner->computeCksm; - }else{ - p->isWal = 0; - p->computeCksm = 0; - } - p->zFName = zName; -cksm_open_done: - if( rc ) pFile->pMethods = 0; - return rc; -} - -/* -** All other VFS methods are pass-thrus. -*/ -static int cksmDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ - return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync); -} -static int cksmAccess( - sqlite3_vfs *pVfs, - const char *zPath, - int flags, - int *pResOut -){ - return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut); -} -static int cksmFullPathname( - sqlite3_vfs *pVfs, - const char *zPath, - int nOut, - char *zOut -){ - return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut); -} -static void *cksmDlOpen(sqlite3_vfs *pVfs, const char *zPath){ - return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath); -} -static void cksmDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ - ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg); -} -static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ - return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym); -} -static void cksmDlClose(sqlite3_vfs *pVfs, void *pHandle){ - ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle); -} -static int cksmRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ - return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut); -} -static int cksmSleep(sqlite3_vfs *pVfs, int nMicro){ - return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro); -} -static int cksmCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ - return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut); -} -static int cksmGetLastError(sqlite3_vfs *pVfs, int a, char *b){ - return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b); -} -static int cksmCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){ - sqlite3_vfs *pOrig = ORIGVFS(pVfs); - int rc; - assert( pOrig->iVersion>=2 ); - if( pOrig->xCurrentTimeInt64 ){ - rc = pOrig->xCurrentTimeInt64(pOrig, p); - }else{ - double r; - rc = pOrig->xCurrentTime(pOrig, &r); - *p = (sqlite3_int64)(r*86400000.0); - } - return rc; -} -static int cksmSetSystemCall( - sqlite3_vfs *pVfs, - const char *zName, - sqlite3_syscall_ptr pCall -){ - return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall); -} -static sqlite3_syscall_ptr cksmGetSystemCall( - sqlite3_vfs *pVfs, - const char *zName -){ - return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName); -} -static const char *cksmNextSystemCall(sqlite3_vfs *pVfs, const char *zName){ - return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName); -} - -/* Register the verify_checksum() SQL function. -*/ -static int cksmRegisterFunc( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi -){ - int rc; - if( db==0 ) return SQLITE_OK; - rc = sqlite3_create_function(db, "verify_checksum", 1, - SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, - 0, cksmVerifyFunc, 0, 0); -#ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME - (void)sqlite3_create_function(db, SQLITE_CKSUMVFS_INIT_FUNCNAME, 1, - SQLITE_UTF8|SQLITE_DIRECTONLY, - 0, cksmInitFunc, 0, 0); -#endif - return rc; -} - -/* -** Register the cksum VFS as the default VFS for the system. -** Also make arrangements to automatically register the "verify_checksum()" -** SQL function on each new database connection. -*/ -static int cksmRegisterVfs(void){ - int rc = SQLITE_OK; - sqlite3_vfs *pOrig; - if( sqlite3_vfs_find("cksmvfs")!=0 ) return SQLITE_OK; - pOrig = sqlite3_vfs_find(0); - if( pOrig==0 ) return SQLITE_ERROR; - cksm_vfs.iVersion = pOrig->iVersion; - cksm_vfs.pAppData = pOrig; - cksm_vfs.szOsFile = pOrig->szOsFile + sizeof(CksmFile); - rc = sqlite3_vfs_register(&cksm_vfs, 1); - if( rc==SQLITE_OK ){ - rc = sqlite3_auto_extension((void(*)(void))cksmRegisterFunc); - } - return rc; -} - -#if defined(SQLITE_CKSUMVFS_STATIC) -/* This variant of the initializer runs when the extension is -** statically linked. -*/ -int sqlite3_register_cksumvfs(const char *NotUsed){ - (void)NotUsed; - return cksmRegisterVfs(); -} -int sqlite3_unregister_cksumvfs(void){ - if( sqlite3_vfs_find("cksmvfs") ){ - sqlite3_vfs_unregister(&cksm_vfs); - sqlite3_cancel_auto_extension((void(*)(void))cksmRegisterFunc); - } - return SQLITE_OK; -} -#endif /* defined(SQLITE_CKSUMVFS_STATIC */ - -#if !defined(SQLITE_CKSUMVFS_STATIC) -/* This variant of the initializer function is used when the -** extension is shared library to be loaded at run-time. -*/ -#ifdef _WIN32 -__declspec(dllexport) -#endif -/* -** This routine is called by sqlite3_load_extension() when the -** extension is first loaded. -***/ -int sqlite3_cksumvfs_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi -){ - int rc; - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErrMsg; /* not used */ - rc = cksmRegisterFunc(db, 0, 0); - if( rc==SQLITE_OK ){ - rc = cksmRegisterVfs(); - } - if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; - return rc; -} -#endif /* !defined(SQLITE_CKSUMVFS_STATIC) */ - -#ifdef SQLITE_CKSUMVFS_STATIC -struct sqlite3_api_routines_cksumvfs { - int (*register_cksumvfs)(const char *); - int (*unregister_cksumvfs)(); -}; -typedef struct sqlite3_api_routines_cksumvfs sqlite3_api_routines_cksumvfs; -static const sqlite3_api_routines_cksumvfs sqlite3CksumvfsApis = { - sqlite3_register_cksumvfs, - sqlite3_unregister_cksumvfs -}; - -EXPORT_SYMBOLS const sqlite3_api_routines_cksumvfs *sqlite3_export_cksumvfs_symbols = &sqlite3CksumvfsApis; -#endif diff --git a/patch/0001-codec-query-sharedmemory-drop-table-callback.patch b/patch/0001-codec-query-sharedmemory-drop-table-callback.patch new file mode 100644 index 0000000..70cf888 --- /dev/null +++ b/patch/0001-codec-query-sharedmemory-drop-table-callback.patch @@ -0,0 +1,3681 @@ +From 696890a3d2abf7f83afcdb35661e0abca916ffd3 Mon Sep 17 00:00:00 2001 +From: wanghaishuo +Date: Fri, 11 Apr 2025 17:36:47 +0800 +Subject: [PATCH 1/7] codec, query sharedmemory, drop table callback + + Signed-off-by: ryne3366 +--- + src/sqlite3.c | 2863 ++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 2823 insertions(+), 40 deletions(-) + +diff --git a/src/sqlite3.c b/src/sqlite3.c +index 3469f92..a935685 100644 +--- a/src/sqlite3.c ++++ b/src/sqlite3.c +@@ -870,6 +870,7 @@ SQLITE_API int sqlite3_exec( + #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) + #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) + #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) ++#define SQLITE_WARNING_DUMP (SQLITE_WARNING | (2<<8)) + #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) + #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) + #define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */ +@@ -2832,6 +2833,11 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); + */ + SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); + ++#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION ++#define SQLITE_DBCONFIG_SET_SHAREDBLOCK 2004 ++#define SQLITE_DBCONFIG_USE_SHAREDBLOCK 2005 ++#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ ++ + /* + ** CAPI3REF: Set the Last Insert Rowid value. + ** METHOD: sqlite3 +@@ -5174,6 +5180,10 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); + */ + SQLITE_API int sqlite3_step(sqlite3_stmt*); + ++#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK ++SQLITE_API int sqlite3_set_droptable_handle(sqlite3*, void (*xFunc)(sqlite3*,const char*,const char*)); ++#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ ++ + /* + ** CAPI3REF: Number of columns in a result set + ** METHOD: sqlite3_stmt +@@ -6439,6 +6449,44 @@ SQLITE_API int sqlite3_collation_needed16( + void(*)(void*,sqlite3*,int eTextRep,const void*) + ); + ++#ifdef SQLITE_HAS_CODEC ++/* ++** Specify the key for an encrypted database. This routine should be ++** called right after sqlite3_open(). ++** ++** The code to implement this API is not available in the public release ++** of SQLite. ++*/ ++SQLITE_API int sqlite3_key( ++ sqlite3 *db, /* Database to be rekeyed */ ++ const void *pKey, int nKey /* The key */ ++); ++SQLITE_API int sqlite3_key_v2( ++ sqlite3 *db, /* Database to be rekeyed */ ++ const char *zDbName, /* Name of the database */ ++ const void *pKey, int nKey /* The key */ ++); ++ ++/* ++** Change the key on an open database. If the current database is not ++** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the ++** database is decrypted. ++** ++** The code to implement this API is not available in the public release ++** of SQLite. ++*/ ++SQLITE_API int sqlite3_rekey( ++ sqlite3 *db, /* Database to be rekeyed */ ++ const void *pKey, int nKey /* The new key */ ++); ++SQLITE_API int sqlite3_rekey_v2( ++ sqlite3 *db, /* Database to be rekeyed */ ++ const char *zDbName, /* Name of the database */ ++ const void *pKey, int nKey /* The new key */ ++); ++ ++#endif /* SQLITE_HAS_CODEC */ ++ + #ifdef SQLITE_ENABLE_CEROD + /* + ** Specify the activation key for a CEROD database. Unless +@@ -9872,6 +9920,27 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); + */ + SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); + ++#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION ++typedef struct Sqlite3SharedBlockMethods Sqlite3SharedBlockMethods; ++struct Sqlite3SharedBlockMethods { ++ int iVersion; ++ void* pContext; ++ int countAllRows; ++ int startPos; ++ int requiredPos; ++ int (*xAddRow)(void* pCtx, int addedRows); ++ int (*xReset)(void* pCtx, int startPos); ++ int (*xFinish)(void* pCtx, int addedRows, int totalRows); ++ int (*xPutString)(void *pCtx, int addedRows, int column, const char* text, int len); ++ int (*xPutLong)(void *pCtx, int addedRows, int column, sqlite3_int64 value); ++ int (*xPutDouble)(void *pCtx, int addedRows, int column, double value); ++ int (*xPutBlob)(void *pCtx, int addedRows, int column, const void* blob, int len); ++ int (*xPutNull)(void *pCtx, int addedRows, int column); ++ int (*xPutOther)(void *pCtx, int addedRows, int column); ++ /* Additional methods may be added in future releases */ ++}; ++#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ ++ + /* + ** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE + ** +@@ -14914,13 +14983,6 @@ typedef int VList; + # 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 + */ +@@ -15234,6 +15296,9 @@ SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); + /* Functions used to configure a Pager object. */ + SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *); + SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int); ++#ifdef SQLITE_HAS_CODEC ++SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager*, Pager*); ++#endif /* SQLITE_HAS_CODEC */ + SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager*, Pgno); + SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int); + SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int); +@@ -15330,6 +15395,10 @@ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno); + + SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16); + ++#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) ++SQLITE_PRIVATE void *sqlite3PagerCodec(DbPage *); ++#endif /* defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) */ ++ + /* Functions to support testing and debugging. */ + #if !defined(NDEBUG) || defined(SQLITE_TEST) + SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*); +@@ -16933,6 +17002,21 @@ SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**); + */ + #define SQLITE_MAX_DB (SQLITE_MAX_ATTACHED+2) + ++#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK ++typedef void (*sqlite3_xDropTableHandle)(sqlite3*, const char*, const char*); ++#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ ++ ++#if defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) ++typedef struct CodecParameter { ++ int kdfIter; ++ int pageSize; ++ u8 cipher; ++ u8 hmacAlgo; ++ u8 kdfAlgo; ++ u8 reserved; ++} CodecParameter; ++#endif /* defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) */ ++ + /* + ** Each database connection is an instance of the following structure. + */ +@@ -17076,6 +17160,15 @@ struct sqlite3 { + #ifdef SQLITE_USER_AUTHENTICATION + sqlite3_userauth auth; /* User authentication information */ + #endif ++#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK ++ unsigned int isDropTable; ++ char *mDropTableName; ++ char *mDropSchemaName; ++ sqlite3_xDropTableHandle xDropTableHandle; /* User drop table callback */ ++#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ ++#if defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) ++ CodecParameter codecParm; ++#endif /* defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) */ + }; + + /* +@@ -20046,7 +20139,14 @@ SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u32,Select*); + SQLITE_PRIVATE void sqlite3AddReturning(Parse*,ExprList*); + SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*, + sqlite3_vfs**,char**,char **); +-#define sqlite3CodecQueryParameters(A,B,C) 0 ++#ifdef SQLITE_HAS_CODEC ++SQLITE_PRIVATE int sqlite3CodecQueryParameters(sqlite3*,const char*,const char*); ++#else ++# define sqlite3CodecQueryParameters(A,B,C) 0 ++#endif /* SQLITE_HAS_CODEC */ ++#if defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) ++SQLITE_PRIVATE void sqlite3CodecResetParameters(CodecParameter *p); ++#endif /* defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) */ + SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*); + + #ifdef SQLITE_UNTESTABLE +@@ -21098,6 +21198,10 @@ SQLITE_API extern int sqlite3_open_file_count; + #define OpenCounter(X) + #endif /* defined(SQLITE_TEST) */ + ++#ifdef FDSAN_ENABLE ++#define SQLITE_FDSAN_TAG 5351 ++#endif /* FDSAN_ENABLE */ ++ + #endif /* !defined(_OS_COMMON_H_) */ + + /************** End of os_common.h *******************************************/ +@@ -21480,6 +21584,9 @@ static const char * const sqlite3azCompileOpt[] = { + #ifdef SQLITE_FTS5_NO_WITHOUT_ROWID + "FTS5_NO_WITHOUT_ROWID", + #endif ++#if SQLITE_HAS_CODEC ++ "HAS_CODEC", ++#endif + #if HAVE_ISNAN || SQLITE_HAVE_ISNAN + "HAVE_ISNAN", + #endif +@@ -21488,6 +21595,9 @@ static const char * const sqlite3azCompileOpt[] = { + "HOMEGROWN_RECURSIVE_MUTEX=" CTIMEOPT_VAL(SQLITE_HOMEGROWN_RECURSIVE_MUTEX), + # endif + #endif ++#if SQLITE_SHARED_BLOCK_OPTIMIZATION ++ "SHARED_BLOCK_OPTIMIZATION", ++#endif + #ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS + "IGNORE_AFP_LOCK_ERRORS", + #endif +@@ -22057,9 +22167,16 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { + ** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally + ** disabled. The default value may be changed by compiling with the + ** SQLITE_USE_URI symbol defined. ++** ++** URI filenames are enabled by default if SQLITE_HAS_CODEC is ++** enabled. + */ + #ifndef SQLITE_USE_URI +-# define SQLITE_USE_URI 0 ++# ifdef SQLITE_HAS_CODEC ++# define SQLITE_USE_URI 1 ++# else ++# define SQLITE_USE_URI 0 ++# endif /* SQLITE_HAS_CODEC */ + #endif + + /* EVIDENCE-OF: R-38720-18127 The default setting is determined by the +@@ -22797,6 +22914,13 @@ struct Vdbe { + int nScan; /* Entries in aScan[] */ + ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */ + #endif ++#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION ++ Sqlite3SharedBlockMethods *pSharedBlock; ++ int totalRows; ++ int blockFull; ++ int startPos; ++ int addedRows; ++#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ + }; + + /* +@@ -31163,7 +31287,11 @@ SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ + */ + static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ + StrAccum acc; /* String accumulator */ ++#ifndef LOG_DUMP + char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ ++#else ++ char zMsg[SQLITE_PRINT_BUF_SIZE*10]; /* Complete log message */ ++#endif /* !LOG_DUMP */ + + sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); + sqlite3_str_vappendf(&acc, zFormat, ap); +@@ -34841,7 +34969,7 @@ SQLITE_PRIVATE u8 sqlite3HexToInt(int h){ + return (u8)(h & 0xf); + } + +-#if !defined(SQLITE_OMIT_BLOB_LITERAL) ++#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) + /* + ** Convert a BLOB literal of the form "x'hhhhhh'" into its binary + ** value. Return a pointer to its binary value. Space to hold the +@@ -34862,7 +34990,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){ + } + return zBlob; + } +-#endif /* !SQLITE_OMIT_BLOB_LITERAL */ ++#endif /* !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) */ + + /* + ** Log an error that is an API call on a connection pointer that should +@@ -37023,6 +37151,29 @@ static pid_t randomnessPid = 0; + #define F2FS_FEATURE_ATOMIC_WRITE 0x0004 + #endif /* __linux__ */ + ++#ifdef HARMONY_OS ++#define HMFS_MONITOR_FL 0x00000002 ++#define HMFS_IOCTL_HW_GET_FLAGS _IOR(0xf5, 70, unsigned int) ++#define HMFS_IOCTL_HW_SET_FLAGS _IOR(0xf5, 71, unsigned int) ++ ++static void enableDbFileDelMonitor(int32_t fd) ++{ ++ unsigned int flags = 0; ++ int ret = ioctl(fd, HMFS_IOCTL_HW_GET_FLAGS, &flags); ++ if (ret < 0) { ++ return; ++ } ++ if (flags & HMFS_MONITOR_FL) { ++ return; ++ } ++ flags |= HMFS_MONITOR_FL; ++ ret = ioctl(fd, HMFS_IOCTL_HW_SET_FLAGS, &flags); ++ if (ret < 0) { ++ sqlite3_log(SQLITE_WARNING, "Fd %d enable del monitor go wrong, errno = %d", fd, errno); ++ } ++} ++ ++#endif /* HARMONY_OS */ + + /* + ** Different Unix systems declare open() in different ways. Same use +@@ -37033,7 +37184,29 @@ static pid_t randomnessPid = 0; + ** which always has the same well-defined interface. + */ + static int posixOpen(const char *zFile, int flags, int mode){ +- return open(zFile, flags, mode); ++ int fd = open(zFile, flags, mode); ++#ifdef FDSAN_ENABLE ++ if( fd >= 0 ){ ++ fdsan_exchange_owner_tag(fd, 0, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, SQLITE_FDSAN_TAG)); ++ } ++#endif /* FDSAN_ENABLE */ ++#ifdef HARMONY_OS ++ if( fd >= 0 ){ ++ enableDbFileDelMonitor(fd); ++ } ++#endif /* HARMONY_OS */ ++ return fd; ++} ++ ++/* ++** Change close to posixClose, use fdsan_close_with_tag when fdsan enable. ++*/ ++static int posixClose(int fd) { ++#ifdef FDSAN_ENABLE ++ return fdsan_close_with_tag(fd, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, SQLITE_FDSAN_TAG)); ++#else ++ return close(fd); ++#endif /* FDSAN_ENABLE */ + } + + /* Forward reference */ +@@ -37054,7 +37227,7 @@ static struct unix_syscall { + { "open", (sqlite3_syscall_ptr)posixOpen, 0 }, + #define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent) + +- { "close", (sqlite3_syscall_ptr)close, 0 }, ++ { "close", (sqlite3_syscall_ptr)posixClose, 0 }, + #define osClose ((int(*)(int))aSyscall[1].pCurrent) + + { "access", (sqlite3_syscall_ptr)access, 0 }, +@@ -38048,6 +38221,9 @@ static int findInodeInfo( + #if defined(EOVERFLOW) && defined(SQLITE_DISABLE_LFS) + if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS; + #endif ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_IOERR, "findInodeInfo-osFstat, fd[%d], errno[%d], osFstat[%d]", fd, errno, rc); ++#endif /* LOG_DUMP */ + return SQLITE_IOERR; + } + +@@ -38066,11 +38242,17 @@ static int findInodeInfo( + do{ rc = osWrite(fd, "S", 1); }while( rc<0 && errno==EINTR ); + if( rc!=1 ){ + storeLastErrno(pFile, errno); ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_IOERR, "findInodeInfo-osWrite, fd[%d], errno[%d], osFstat[%d]", fd, errno, rc); ++#endif /* LOG_DUMP */ + return SQLITE_IOERR; + } + rc = osFstat(fd, &statbuf); + if( rc!=0 ){ + storeLastErrno(pFile, errno); ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_IOERR, "findInodeInfo-msdos-osFstat, fd[%d], errno[%d], osFstat[%d]", fd, errno, rc); ++#endif /* LOG_DUMP */ + return SQLITE_IOERR; + } + } +@@ -39232,6 +39414,9 @@ static int flockUnlock(sqlite3_file *id, int eFileLock) { + #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS + return SQLITE_OK; + #endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_IOERR_UNLOCK, "IOERR_UNLOCK fd[%d], eFileLock[%d]", pFile->h, eFileLock); ++#endif /* LOG_DUMP */ + return SQLITE_IOERR_UNLOCK; + }else{ + pFile->eFileLock = NO_LOCK; +@@ -40059,8 +40244,14 @@ static int unixRead( + #ifdef EDEVERR + case EDEVERR: + #endif ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_IOERR_CORRUPTFS, "unixRead-EDEVERR, fd:[%d], amt[%d], got[%d], offset[%lld]", pFile->h, amt, got, offset); ++#endif /* LOG_DUMP */ + return SQLITE_IOERR_CORRUPTFS; + } ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_IOERR_READ, "unixRead-got<0, fd: [%d], amt[%d], got[%d], offset[%lld]", pFile->h, amt, got, offset); ++#endif /* LOG_DUMP */ + return SQLITE_IOERR_READ; + }else{ + storeLastErrno(pFile, 0); /* not a system error */ +@@ -40202,9 +40393,19 @@ static int unixWrite( + if( amt>wrote ){ + if( wrote<0 && pFile->lastErrno!=ENOSPC ){ + /* lastErrno set by seekAndWrite */ ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_IOERR_WRITE, ++ "unixWrite, lastErrno set by seekAndWrite, fd[%d], offset[%lld], wrote[%d], amt[%d], lastErrno[%d]", ++ pFile->h, offset, wrote, amt, pFile->lastErrno); ++#endif /* LOG_DUMP */ + return SQLITE_IOERR_WRITE; + }else{ + storeLastErrno(pFile, 0); /* not a system error */ ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_FULL, ++ "unixWrite, not a system error, fd[%d], offset[%lld], wrote[%d], amt[%d], lastErrno[%d]", ++ pFile->h, offset, wrote, amt, pFile->lastErrno); ++#endif /* LOG_DUMP */ + return SQLITE_FULL; + } + } +@@ -40558,7 +40759,14 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ + do{ + err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size); + }while( err==EINTR ); +- if( err && err!=EINVAL ) return SQLITE_IOERR_WRITE; ++ if( err && err!=EINVAL ) { ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_IOERR_WRITE, ++ "fcntlSizeHint-fallocate, fd[%d], bufSize[%lld], nSize[%lld] err[%d]", ++ pFile->h, buf.st_size, nSize, err); ++#endif /* LOG_DUMP */ ++ return SQLITE_IOERR_WRITE; ++ } + #else + /* If the OS does not have posix_fallocate(), fake it. Write a + ** single byte to the last byte in each block that falls entirely +@@ -40577,7 +40785,14 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ + for(/*no-op*/; iWrite=nSize ) iWrite = nSize - 1; + nWrite = seekAndWrite(pFile, iWrite, "", 1); +- if( nWrite!=1 ) return SQLITE_IOERR_WRITE; ++ if( nWrite!=1 ) { ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_IOERR_WRITE, ++ "fcntlSizeHint-seekAndWrite, fd[%d], nWrite[%d], nSize[%d], nBlk[%d], iWrite[%lld]", ++ pFile->h, nWrite, nSize, nBlk, iWrite); ++#endif /* LOG_DUMP */ ++ return SQLITE_IOERR_WRITE; ++ } + } + #endif + } +@@ -40632,14 +40847,29 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ + #if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) + case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: { + int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE); ++#ifdef LOG_DUMP ++ if( rc ){ ++ sqlite3_log(SQLITE_IOERR_BEGIN_ATOMIC, "unixFileControl-begin, fd[%d], op[%d]", pFile->h, op); ++ } ++#endif /* LOG_DUMP */ + return rc ? SQLITE_IOERR_BEGIN_ATOMIC : SQLITE_OK; + } + case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: { + int rc = osIoctl(pFile->h, F2FS_IOC_COMMIT_ATOMIC_WRITE); ++#ifdef LOG_DUMP ++ if( rc ){ ++ sqlite3_log(SQLITE_IOERR_COMMIT_ATOMIC, "unixFileControl-commit, fd[%d], op[%d]", pFile->h, op); ++ } ++#endif /* LOG_DUMP */ + return rc ? SQLITE_IOERR_COMMIT_ATOMIC : SQLITE_OK; + } + case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: { + int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE); ++#ifdef LOG_DUMP ++ if( rc ){ ++ sqlite3_log(SQLITE_IOERR_ROLLBACK_ATOMIC, "unixFileControl-rollback, fd[%d], op[%d]", pFile->h, op); ++ } ++#endif /* LOG_DUMP */ + return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK; + } + #endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ +@@ -41585,9 +41815,19 @@ static int unixShmLock( + int *aLock; + + p = pDbFd->pShm; +- if( p==0 ) return SQLITE_IOERR_SHMLOCK; ++ if( p==0 ) { ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_IOERR_SHMLOCK, "unixShmLock-pShm, fd[%d], ofst[%d], n[%d], flags[%d]", pDbFd->h, ofst, n, flags); ++#endif ++ return SQLITE_IOERR_SHMLOCK; ++ } + pShmNode = p->pShmNode; +- if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK; ++ if( NEVER(pShmNode==0) ) { ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_IOERR_SHMLOCK, "unixShmLock-pShmNode, fd[%d], ofst[%d], n[%d], flags[%d]", pDbFd->h, ofst, n, flags); ++#endif ++ return SQLITE_IOERR_SHMLOCK; ++ } + aLock = pShmNode->aLock; + + assert( pShmNode==pDbFd->pInode->pShmNode ); +@@ -42959,6 +43199,9 @@ static int unixOpen( + if( fstatfs(fd, &fsInfo) == -1 ){ + storeLastErrno(p, errno); + robust_close(p, fd, __LINE__); ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_IOERR_ACCESS, "unixOpen, fd[%d], flags[%d], errno[%d]", fd, errno, flags); ++#endif /* LOG_DUMP */ + return SQLITE_IOERR_ACCESS; + } + if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) { +@@ -43099,6 +43342,184 @@ static int unixAccess( + return SQLITE_OK; + } + ++#ifdef HARMONY_OS ++/* ++** If the last component of the pathname in z[0]..z[j-1] is something ++** other than ".." then back it out and return true. If the last ++** component is empty or if it is ".." then return false. ++*/ ++static int unixBackupDir(const char *z, int *pJ){ ++ int j = *pJ; ++ int i; ++ if( j<=0 ) return 0; ++ for(i=j-1; i>0 && z[i-1]!='/'; i--){} ++ if( i==0 ) return 0; ++ if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0; ++ *pJ = i-1; ++ return 1; ++} ++ ++/* ++** Convert a relative pathname into a full pathname. Also ++** simplify the pathname as follows: ++** ++** Remove all instances of /./ ++** Remove all isntances of /X/../ for any X ++*/ ++static int mkFullPathname( ++ const char *zPath, /* Input path */ ++ char *zOut, /* Output buffer */ ++ int nOut /* Allocated size of buffer zOut */ ++){ ++ int nPath = sqlite3Strlen30(zPath); ++ int iOff = 0; ++ int i, j; ++ if( zPath[0]!='/' ){ ++ if( osGetcwd(zOut, nOut-2)==0 ){ ++ return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); ++ } ++ iOff = sqlite3Strlen30(zOut); ++ zOut[iOff++] = '/'; ++ } ++ if( (iOff+nPath+1)>nOut ){ ++ /* SQLite assumes that xFullPathname() nul-terminates the output buffer ++ ** even if it returns an error. */ ++ zOut[iOff] = '\0'; ++ return SQLITE_CANTOPEN_BKPT; ++ } ++ sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath); ++ ++ /* Remove duplicate '/' characters. Except, two // at the beginning ++ ** of a pathname is allowed since this is important on windows. */ ++ for(i=j=1; zOut[i]; i++){ ++ zOut[j++] = zOut[i]; ++ while( zOut[i]=='/' && zOut[i+1]=='/' ) i++; ++ } ++ zOut[j] = 0; ++ ++ assert( zOut[0]=='/' ); ++ for(i=j=0; zOut[i]; i++){ ++ if( zOut[i]=='/' ){ ++ /* Skip over internal "/." directory components */ ++ if( zOut[i+1]=='.' && zOut[i+2]=='/' ){ ++ i += 1; ++ continue; ++ } ++ ++ /* If this is a "/.." directory component then back out the ++ ** previous term of the directory if it is something other than "..". ++ */ ++ if( zOut[i+1]=='.' ++ && zOut[i+2]=='.' ++ && zOut[i+3]=='/' ++ && unixBackupDir(zOut, &j) ++ ){ ++ i += 2; ++ continue; ++ } ++ } ++ if( ALWAYS(j>=0) ) zOut[j] = zOut[i]; ++ j++; ++ } ++ if( NEVER(j==0) ) zOut[j++] = '/'; ++ zOut[j] = 0; ++ return SQLITE_OK; ++} ++ ++/* ++** Turn a relative pathname into a full pathname. The relative path ++** is stored as a nul-terminated string in the buffer pointed to by ++** zPath. ++** ++** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes ++** (in this case, MAX_PATHNAME bytes). The full-path is written to ++** this buffer before returning. ++*/ ++static int unixFullPathname( ++ sqlite3_vfs *pVfs, /* Pointer to vfs object */ ++ const char *zPath, /* Possibly relative input path */ ++ int nOut, /* Size of output buffer in bytes */ ++ char *zOut /* Output buffer */ ++){ ++#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT) ++ return mkFullPathname(zPath, zOut, nOut); ++#else ++ int rc = SQLITE_OK; ++ int nByte; ++ int nLink = 0; /* Number of symbolic links followed so far */ ++ const char *zIn = zPath; /* Input path for each iteration of loop */ ++ char *zDel = 0; ++ ++ assert( pVfs->mxPathname==MAX_PATHNAME ); ++ UNUSED_PARAMETER(pVfs); ++ ++ /* It's odd to simulate an io-error here, but really this is just ++ ** using the io-error infrastructure to test that SQLite handles this ++ ** function failing. This function could fail if, for example, the ++ ** current working directory has been unlinked. ++ */ ++ SimulateIOError( return SQLITE_ERROR ); ++ ++ do { ++ ++ /* Call stat() on path zIn. Set bLink to true if the path is a symbolic ++ ** link, or false otherwise. */ ++ int bLink = 0; ++ struct stat buf; ++ if( osLstat(zIn, &buf)!=0 ){ ++ if( errno!=ENOENT ){ ++ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn); ++ } ++ }else{ ++ bLink = S_ISLNK(buf.st_mode); ++ } ++ ++ if( bLink ){ ++ nLink++; ++ if( zDel==0 ){ ++ zDel = sqlite3_malloc(nOut); ++ if( zDel==0 ) rc = SQLITE_NOMEM_BKPT; ++ }else if( nLink>=SQLITE_MAX_SYMLINKS ){ ++ rc = SQLITE_CANTOPEN_BKPT; ++ } ++ ++ if( rc==SQLITE_OK ){ ++ nByte = osReadlink(zIn, zDel, nOut-1); ++ if( nByte<0 ){ ++ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn); ++ }else{ ++ if( zDel[0]!='/' ){ ++ int n; ++ for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--); ++ if( nByte+n+1>nOut ){ ++ rc = SQLITE_CANTOPEN_BKPT; ++ }else{ ++ memmove(&zDel[n], zDel, nByte+1); ++ memcpy(zDel, zIn, n); ++ nByte += n; ++ } ++ } ++ zDel[nByte] = '\0'; ++ } ++ } ++ ++ zIn = zDel; ++ } ++ ++ assert( rc!=SQLITE_OK || zIn!=zOut || zIn[0]=='/' ); ++ if( rc==SQLITE_OK && zIn!=zOut ){ ++ rc = mkFullPathname(zIn, zOut, nOut); ++ } ++ if( bLink==0 ) break; ++ zIn = zOut; ++ }while( rc==SQLITE_OK ); ++ ++ sqlite3_free(zDel); ++ if( rc==SQLITE_OK && nLink ) rc = SQLITE_OK_SYMLINK; ++ return rc; ++#endif /* HAVE_READLINK && HAVE_LSTAT */ ++} ++#else + /* + ** A pathname under construction + */ +@@ -43156,7 +43577,7 @@ static void appendOnePathElement( + }else if( S_ISLNK(buf.st_mode) ){ + ssize_t got; + char zLnk[SQLITE_MAX_PATHLEN+2]; +- if( pPath->nSymlink++ > SQLITE_MAX_SYMLINK ){ ++ if( pPath->nSymlink++ > SQLITE_MAX_SYMLINKS ){ + pPath->rc = SQLITE_CANTOPEN_BKPT; + return; + } +@@ -43230,6 +43651,7 @@ static int unixFullPathname( + if( path.nSymlink ) return SQLITE_OK_SYMLINK; + return SQLITE_OK; + } ++#endif + + #ifndef SQLITE_OMIT_LOAD_EXTENSION + /* +@@ -43636,6 +44058,9 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){ + if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){ + OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n", + lPath, errno, osGetpid(0))); ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_IOERR_LOCK, "proxyGetLockPath len[%d], dbLen[%d], i[%d]", len, dbLen, i); ++#endif /* LOG_DUMP */ + return SQLITE_IOERR_LOCK; + } + len = strlcat(lPath, "sqliteplocks", maxLen); +@@ -43754,6 +44179,9 @@ static int proxyCreateUnixFile( + case EACCES: + return SQLITE_PERM; + case EIO: ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_IOERR_LOCK, "proxyCreateUnixFile-EIO, fd[%d]", fd); ++#endif /* LOG_DUMP */ + return SQLITE_IOERR_LOCK; /* even though it is the conch */ + default: + return SQLITE_CANTOPEN_BKPT; +@@ -43922,6 +44350,9 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ + struct stat buf; + if( osFstat(conchFile->h, &buf) ){ + storeLastErrno(pFile, errno); ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_IOERR_LOCK, "proxyConchLock pFile fd[%d], conchFile fd[%d], lastErrno[%d]", pFile->h, conchFile->h, errno); ++#endif /* LOG_DUMP */ + return SQLITE_IOERR_LOCK; + } + +@@ -43942,6 +44373,9 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ + int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0); + if( len<0 ){ + storeLastErrno(pFile, errno); ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_IOERR_LOCK, "proxyConchLock tries 2, pFile fd[%d], conchFile fd[%d], lastErrno[%d]", pFile->h, conchFile->h, errno); ++#endif /* LOG_DUMP */ + return SQLITE_IOERR_LOCK; + } + if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){ +@@ -44016,6 +44450,9 @@ static int proxyTakeConch(unixFile *pFile){ + if( readLen<0 ){ + /* I/O error: lastErrno set by seekAndRead */ + storeLastErrno(pFile, conchFile->lastErrno); ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_IOERR_READ, "proxyTakeConch pFile fd[%d], conchFile fd[%d], lastErrno[%d]", pFile->h, conchFile->h, conchFile->lastErrno); ++#endif /* LOG_DUMP */ + rc = SQLITE_IOERR_READ; + goto end_takeconch; + }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) || +@@ -51878,13 +52315,6 @@ end_deserialize: + return rc; + } + +-/* +-** Return true if the VFS is the memvfs. +-*/ +-SQLITE_PRIVATE int sqlite3IsMemdb(const sqlite3_vfs *pVfs){ +- return pVfs==&memdb_vfs; +-} +- + /* + ** This routine is called when the extension is loaded. + ** Register the new VFS. +@@ -55601,6 +56031,20 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ + */ + #define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1) + ++#ifdef SQLITE_HAS_CODEC ++/* ++** A macro used for invoking the codec if there is one ++*/ ++# define CODEC1(P,D,N,X,E) \ ++ if( P->xCodec && P->xCodec(P->pCodec,D,N,X)==0 ){ E; } ++# define CODEC2(P,D,N,X,E,O) \ ++ if( P->xCodec==0 ){ O=(char*)D; }else \ ++ if( (O=(char*)(P->xCodec(P->pCodec,D,N,X)))==0 ){ E; } ++#else ++# define CODEC1(P,D,N,X,E) /* NO-OP */ ++# define CODEC2(P,D,N,X,E,O) O=(char*)D ++#endif /* SQLITE_HAS_CODEC */ ++ + /* + ** The maximum allowed sector size. 64KiB. If the xSectorsize() method + ** returns a value larger than this, then MAX_SECTOR_SIZE is used instead. +@@ -55889,6 +56333,12 @@ struct Pager { + #endif + void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */ + int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */ ++#ifdef SQLITE_HAS_CODEC ++ void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ ++ void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */ ++ void (*xCodecFree)(void*); /* Destructor for the codec */ ++ void *pCodec; /* First argument to xCodec... methods */ ++#endif /* SQLITE_HAS_CODEC */ + char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ + PCache *pPCache; /* Pointer to page cache object */ + #ifndef SQLITE_OMIT_WAL +@@ -56010,6 +56460,9 @@ static const unsigned char aJournalMagic[] = { + SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){ + if( pPager->fd->pMethods==0 ) return 0; + if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; ++#ifdef SQLITE_HAS_CODEC ++ if( pPager->xCodec!=0 ) return 0; ++#endif /* SQLITE_HAS_CODEC */ + #ifndef SQLITE_OMIT_WAL + if( pPager->pWal ){ + u32 iRead = 0; +@@ -56243,7 +56696,11 @@ 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) ++#ifdef SQLITE_HAS_CODEC ++ && pPager->xCodec==0 ++#endif /* SQLITE_HAS_CODEC */ ++ ){ + pPager->xGet = getPageMMap; + #endif /* SQLITE_MAX_MMAP_SIZE>0 */ + }else{ +@@ -57394,6 +57851,32 @@ static u32 pager_cksum(Pager *pPager, const u8 *aData){ + return cksum; + } + ++#ifdef SQLITE_HAS_CODEC ++/* ++** Report the current page size and number of reserved bytes back ++** to the codec. ++*/ ++static void pagerReportSize(Pager *pPager){ ++ if( pPager->xCodecSizeChng ){ ++ pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize, ++ (int)pPager->nReserve); ++ } ++} ++/* ++** Make sure the number of reserved bits is the same in the destination ++** pager as it is in the source. This comes up when a VACUUM changes the ++** number of reserved bits to the "optimal" amount. ++*/ ++SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager *pDest, Pager *pSrc){ ++ if( pDest->nReserve!=pSrc->nReserve ){ ++ pDest->nReserve = pSrc->nReserve; ++ pagerReportSize(pDest); ++ } ++} ++#else ++# define pagerReportSize(X) /* No-op if we do not support a codec */ ++#endif ++ + /* + ** Read a single page from either the journal file (if isMainJrnl==1) or + ** from the sub-journal (if isMainJrnl==0) and playback that page. +@@ -57445,6 +57928,11 @@ static int pager_playback_one_page( + char *aData; /* Temporary storage for the page */ + sqlite3_file *jfd; /* The file descriptor for the journal file */ + int isSynced; /* True if journal page is synced */ ++#ifdef SQLITE_HAS_CODEC ++ /* The jrnlEnc flag is true if Journal pages should be passed through ++ ** the codec. It is false for pure in-memory journals. */ ++ const int jrnlEnc = (isMainJrnl || pPager->subjInMemory==0); ++#endif /* SQLITE_HAS_CODEC */ + + assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */ + assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */ +@@ -57574,12 +58062,26 @@ static int pager_playback_one_page( + ** is if the data was just read from an in-memory sub-journal. In that + ** case it must be encrypted here before it is copied into the database + ** file. */ ++#ifdef SQLITE_HAS_CODEC ++ if( !jrnlEnc ){ ++ CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData); ++ rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); ++ CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT); ++ }else ++#endif /* SQLITE_HAS_CODEC */ + rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); + + if( pgno>pPager->dbFileSize ){ + pPager->dbFileSize = pgno; + } + if( pPager->pBackup ){ ++#ifdef SQLITE_HAS_CODEC ++ if( jrnlEnc ){ ++ CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT); ++ sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); ++ CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT,aData); ++ }else ++#endif /* SQLITE_HAS_CODEC */ + sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); + } + }else if( !isMainJrnl && pPg==0 ){ +@@ -57630,6 +58132,10 @@ static int pager_playback_one_page( + if( pgno==1 ){ + memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers)); + } ++#if SQLITE_HAS_CODEC ++ /* Decode the page just read from disk */ ++ if( jrnlEnc ){ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT); } ++#endif /* SQLITE_HAS_CODEC */ + sqlite3PcacheRelease(pPg); + } + return rc; +@@ -58206,6 +58712,8 @@ static int readDbPage(PgHdr *pPg){ + memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers)); + } + } ++ CODEC1(pPager, pPg->pData, pPg->pgno, 3, rc = SQLITE_NOMEM_BKPT); ++ + PAGER_INCR(sqlite3_pager_readdb_count); + PAGER_INCR(pPager->nRead); + IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno)); +@@ -59353,6 +59861,10 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ + sqlite3OsClose(pPager->fd); + sqlite3PageFree(pTmp); + sqlite3PcacheClose(pPager->pPCache); ++#ifdef SQLITE_HAS_CODEC ++ if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec); ++#endif /* SQLITE_HAS_CODEC */ ++ + assert( !pPager->aSavepoint && !pPager->pInJournal ); + assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) ); + +@@ -59603,7 +60115,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ + assert( (pList->flags&PGHDR_NEED_SYNC)==0 ); + if( pList->pgno==1 ) pager_write_changecounter(pList); + +- pData = pList->pData; ++ CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM_BKPT, pData); + + /* Write out the page data. */ + rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset); +@@ -59692,6 +60204,11 @@ static int subjournalPage(PgHdr *pPg){ + void *pData = pPg->pData; + i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize); + char *pData2; ++#if SQLITE_HAS_CODEC ++ if( !pPager->subjInMemory ){ ++ CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2); ++ }else ++#endif /* SQLITE_HAS_CODEC */ + pData2 = pData; + PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno)); + rc = write32bits(pPager->sjfd, offset, pPg->pgno); +@@ -60795,6 +61312,9 @@ static int getPageMMap( + ); + + assert( USEFETCH(pPager) ); ++#ifdef SQLITE_HAS_CODEC ++ assert( pPager->xCodec==0 ); ++#endif /* SQLITE_HAS_CODEC */ + + /* Optimization note: Adding the "pgno<=1" term before "pgno==0" here + ** allows the compiler optimizer to reuse the results of the "pgno>1" +@@ -61125,7 +61645,7 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){ + assert( pPg->pgno!=PAGER_SJ_PGNO(pPager) ); + + assert( pPager->journalHdr<=pPager->journalOff ); +- pData2 = pPg->pData; ++ CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2); + cksum = pager_cksum(pPager, (u8*)pData2); + + /* Even if an IO or diskfull error occurs while journalling the +@@ -61490,7 +62010,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){ + if( DIRECT_MODE ){ + const void *zBuf; + assert( pPager->dbFileSize>0 ); +- zBuf = pPgHdr->pData; ++ CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM_BKPT, zBuf); + if( rc==SQLITE_OK ){ + rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0); + pPager->aStat[PAGER_STAT_WRITE]++; +@@ -62242,6 +62762,48 @@ SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){ + return pPager->zJournal; + } + ++#ifdef SQLITE_HAS_CODEC ++/* ++** Set or retrieve the codec for this pager ++*/ ++SQLITE_PRIVATE void sqlite3PagerSetCodec( ++ Pager *pPager, ++ void *(*xCodec)(void*,void*,Pgno,int), ++ void (*xCodecSizeChng)(void*,int,int), ++ void (*xCodecFree)(void*), ++ void *pCodec ++){ ++ if( pPager->xCodecFree ){ ++ pPager->xCodecFree(pPager->pCodec); ++ }else{ ++ pager_reset(pPager); ++ } ++ pPager->xCodec = pPager->memDb ? 0 : xCodec; ++ pPager->xCodecSizeChng = xCodecSizeChng; ++ pPager->xCodecFree = xCodecFree; ++ pPager->pCodec = pCodec; ++ setGetterMethod(pPager); ++ pagerReportSize(pPager); ++} ++SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){ ++ return pPager->pCodec; ++} ++ ++/* ++** This function is called by the wal module when writing page content ++** into the log file. ++** ++** This function returns a pointer to a buffer containing the encrypted ++** page content. If a malloc fails, this function may return NULL. ++*/ ++SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){ ++ void *aData = 0; ++ CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData); ++ return aData; ++} ++ ++#endif /* SQLITE_HAS_CODEC */ ++ + #ifndef SQLITE_OMIT_AUTOVACUUM + /* + ** Move the page pPg to location pgno in the file. +@@ -64937,6 +65499,11 @@ static void walRestartHdr(Wal *pWal, u32 salt1){ + assert( pInfo->aReadMark[0]==0 ); + } + ++#ifdef SQLITE_HDR_CHECK ++static int checkHeaderValid(Pager *pager, u8 *zBuf, const char *logStr); ++static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf); ++#endif /* SQLITE_HDR_CHECK */ ++ + /* + ** Copy as much content as we can from the WAL back into the database file + ** in response to an sqlite3_wal_checkpoint() request or the equivalent. +@@ -65077,6 +65644,10 @@ static int walCheckpoint( + if( rc!=SQLITE_OK ) break; + iOffset = (iDbpage-1)*(i64)szPage; + testcase( IS_BIG_INT(iOffset) ); ++#ifdef SQLITE_HDR_CHECK ++ rc = checkDbHeaderValid(db, iDbpage, zBuf); ++ if( rc!=SQLITE_OK ) break; ++#endif /* SQLITE_HDR_CHECK */ + rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); + if( rc!=SQLITE_OK ) break; + } +@@ -66471,7 +67042,18 @@ static int walWriteOneFrame( + int rc; /* Result code from subfunctions */ + void *pData; /* Data actually written */ + u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */ ++#ifdef SQLITE_HDR_CHECK ++ if( pPage->pgno==1 ){ ++ rc = checkHeaderValid(pPage->pPager, pPage->pData, "walWrite"); ++ if( rc!=SQLITE_OK ) return rc; ++ } ++#endif /* SQLITE_HDR_CHECK */ ++ ++#ifdef SQLITE_HAS_CODEC ++ if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT; ++#else + pData = pPage->pData; ++#endif /* SQLITE_HAS_CODEC */ + walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame); + rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset); + if( rc ) return rc; +@@ -66654,7 +67236,11 @@ SQLITE_PRIVATE int sqlite3WalFrames( + if( pWal->iReCksum==0 || iWriteiReCksum ){ + pWal->iReCksum = iWrite; + } ++#ifdef SQLITE_HAS_CODEC ++ if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM; ++#else + pData = p->pData; ++#endif /* SQLITE_HAS_CODEC */ + rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff); + if( rc ) return rc; + p->flags &= ~PGHDR_WAL_APPEND; +@@ -66765,6 +67351,10 @@ SQLITE_PRIVATE int sqlite3WalFrames( + return rc; + } + ++#ifdef LOG_DUMP ++static sqlite3_int64 g_lastCkptTime = 0; ++#endif /* LOG_DUMP */ ++ + /* + ** This routine is called to implement sqlite3_wal_checkpoint() and + ** related interfaces. +@@ -66888,6 +67478,12 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( + walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1); + pWal->ckptLock = 0; + } ++#ifdef LOG_DUMP ++ if( rc ){ ++ sqlite3_log(SQLITE_NOTICE, "ckpt rc[%d]", rc); ++ } ++ sqlite3OsCurrentTimeInt64(db->pVfs, &g_lastCkptTime); ++#endif /* LOG_DUMP */ + WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok")); + #ifdef SQLITE_ENABLE_SETLK_TIMEOUT + if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY; +@@ -68264,6 +68860,32 @@ SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){ + } + #endif + ++#ifdef SQLITE_HDR_CHECK ++static int checkHeaderValid(Pager *pager, u8 *zBuf, const char *logStr){ ++#ifdef SQLITE_HAS_CODEC ++ if( pager==NULL || pager->pCodec ){ ++ return SQLITE_OK; ++ } ++#endif /* SQLITE_HAS_CODEC */ ++ if( zBuf && strncmp((const char *)zBuf, zMagicHeader, 16)!=0 ){ ++ sqlite3_log(SQLITE_NOTADB, "[%s]wrong header format, memory might be overwritten!", logStr); ++ return SQLITE_NOTADB; ++ } ++ return SQLITE_OK; ++} ++ ++static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf){ ++ if( iDbpage==1 && db->aDb ){ ++ Btree *p = db->aDb[0].pBt; ++ if( p && p->pBt ){ ++ Pager *pager = sqlite3BtreePager(p); ++ return checkHeaderValid(pager, zBuf, "ckpt"); ++ } ++ } ++ return SQLITE_OK; ++} ++#endif /* SQLITE_HDR_CHECK */ ++ + /* + ** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single + ** (MemPage*) as an argument. The (MemPage*) must not be NULL. +@@ -70094,6 +70716,13 @@ static int decodeFlags(MemPage *pPage, int flagByte){ + pPage->intKeyLeaf = 0; + pPage->xCellSize = cellSizePtr; + pPage->xParseCell = btreeParseCellPtrIndex; ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_CORRUPT, ++ "database corruption at page[%u], flagByte[%x], isInit[%u], intKey[%u], intKeyLeaf[%u], leaf[%u], " ++ "childPtrSize[%u], cellOffset[%u], nCell[%u], hdrOffset[%u], minLocal[%u], maxLocal[%u], last ckpt time[%lld]", ++ pPage->pgno, flagByte, pPage->isInit, pPage->intKey, pPage->intKeyLeaf, pPage->leaf, ++ pPage->childPtrSize, pPage->cellOffset, pPage->nCell, pPage->hdrOffset, pPage->minLocal, pPage->maxLocal, g_lastCkptTime); ++#endif /* LOG_DUMP */ + return SQLITE_CORRUPT_PAGE(pPage); + } + pPage->max1bytePayload = pBt->max1bytePayload; +@@ -79481,6 +80110,13 @@ static int backupOnePage( + int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); + const int nCopy = MIN(nSrcPgsz, nDestPgsz); + const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; ++#ifdef SQLITE_HAS_CODEC ++ /* Use BtreeGetReserveNoMutex() for the source b-tree, as although it is ++ ** guaranteed that the shared-mutex is held by this thread, handle ++ ** p->pSrc may not actually be the owner. */ ++ int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc); ++ int nDestReserve = sqlite3BtreeGetRequestedReserve(p->pDest); ++#endif /* SQLITE_HAS_CODEC */ + int rc = SQLITE_OK; + i64 iOff; + +@@ -79497,6 +80133,26 @@ static int backupOnePage( + rc = SQLITE_READONLY; + } + ++#ifdef SQLITE_HAS_CODEC ++ /* Backup is not possible if the page size of the destination is changing ++ ** and a codec is in use. ++ */ ++ if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){ ++ rc = SQLITE_READONLY; ++ } ++ ++ /* Backup is not possible if the number of bytes of reserve space differ ++ ** between source and destination. If there is a difference, try to ++ ** fix the destination to agree with the source. If that is not possible, ++ ** then the backup cannot proceed. ++ */ ++ if( nSrcReserve!=nDestReserve ){ ++ u32 newPgsz = nSrcPgsz; ++ rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve); ++ if( rc==SQLITE_OK && newPgsz!=(u32)nSrcPgsz ) rc = SQLITE_READONLY; ++ } ++#endif /* SQLITE_HAS_CODEC */ ++ + /* This loop runs once for each destination page spanned by the source + ** page. For each iteration, variable iOff is set to the byte offset + ** of the destination page. +@@ -79992,6 +80648,10 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ + b.pDest = pTo; + b.iNext = 1; + ++#ifdef SQLITE_HAS_CODEC ++ sqlite3PagerAlignReserve(sqlite3BtreePager(pTo), sqlite3BtreePager(pFrom)); ++#endif /* SQLITE_HAS_CODEC */ ++ + /* 0x7FFFFFFF is the hard limit for the number of pages in a database + ** file. By passing this as the number of pages to copy to + ** sqlite3_backup_step(), we can guarantee that the copy finishes +@@ -88114,6 +88774,15 @@ end_of_step: + return (rc&db->errMask); + } + ++#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK ++SQLITE_API int sqlite3_set_droptable_handle(sqlite3 *db, void (*xFunc)(sqlite3*, const char*, const char*)){ ++ sqlite3_mutex_enter(db->mutex); ++ db->xDropTableHandle = xFunc; ++ sqlite3_mutex_leave(db->mutex); ++ return 0; ++} ++#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ ++ + /* + ** This is the top-level implementation of sqlite3_step(). Call + ** sqlite3Step() to do most of the work. If a schema error occurs, +@@ -88133,6 +88802,13 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ + while( (rc = sqlite3Step(v))==SQLITE_SCHEMA + && cnt++ < SQLITE_MAX_SCHEMA_RETRY ){ + int savedPc = v->pc; ++#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION ++ Sqlite3SharedBlockMethods *pSharedBlock = v->pSharedBlock; ++ int totalRows = v->totalRows; ++ int blockFull = v->blockFull; ++ int startPos = v->startPos; ++ int addedRows = v->addedRows; ++#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ + rc = sqlite3Reprepare(v); + if( rc!=SQLITE_OK ){ + /* This case occurs after failing to recompile an sql statement. +@@ -88154,6 +88830,15 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ + } + break; + } ++ ++#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION ++ v->pSharedBlock = pSharedBlock; ++ v->totalRows = totalRows; ++ v->blockFull = blockFull; ++ v->startPos = startPos; ++ v->addedRows = addedRows; ++#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ ++ + sqlite3_reset(pStmt); + if( savedPc>=0 ){ + /* Setting minWriteFileFormat to 254 is a signal to the OP_Init and +@@ -88164,6 +88849,20 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ + } + assert( v->expired==0 ); + } ++#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK ++ if( rc==SQLITE_DONE && db->xDropTableHandle!=NULL && db->isDropTable==1 ){ ++ db->isDropTable = 0; ++ db->xDropTableHandle(db, db->mDropTableName, db->mDropSchemaName); ++ } ++ if( db->mDropTableName!=NULL ){ ++ sqlite3_free(db->mDropTableName); ++ db->mDropTableName = NULL; ++ } ++ if( db->mDropSchemaName!=NULL ){ ++ sqlite3_free(db->mDropSchemaName); ++ db->mDropSchemaName = NULL; ++ } ++#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ + sqlite3_mutex_leave(db->mutex); + return rc; + } +@@ -90192,7 +90891,6 @@ static u16 numericType(Mem *pMem){ + testcase( pMem->flags & MEM_Str ); + testcase( pMem->flags & MEM_Blob ); + return computeNumericType(pMem); +- return 0; + } + + #ifdef SQLITE_DEBUG +@@ -90351,6 +91049,61 @@ static int checkSavepointCount(sqlite3 *db){ + } + #endif + ++#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION ++static int copySharedBlockRow( ++ Vdbe *p, /* The VDBE */ ++ Op *pOp, /* Current operation */ ++ Mem *pMem, ++ void *pCtx ++){ ++ int i = 0; ++ ++ int rc = p->pSharedBlock->xAddRow(pCtx, p->addedRows); ++ if( rc!=SQLITE_OK ){ ++ return rc; ++ } ++ ++ for(i=0; ip2; i++){ ++ switch (sqlite3_value_type(&pMem[i])) { ++ case SQLITE_INTEGER:{ ++ rc = p->pSharedBlock->xPutLong(pCtx, p->addedRows, i, (sqlite3_int64)pMem[i].u.i); ++ break; ++ } ++ case SQLITE_FLOAT: { ++ rc = p->pSharedBlock->xPutDouble(pCtx, p->addedRows, i, pMem[i].u.r); ++ break; ++ } ++ case SQLITE_TEXT: { ++ Deephemeralize(&pMem[i]); ++ sqlite3VdbeMemNulTerminate(&pMem[i]); ++ sqlite3VdbeChangeEncoding(&pMem[i],SQLITE_UTF8); ++ rc = p->pSharedBlock->xPutString(pCtx, p->addedRows, i, pMem[i].z, pMem[i].n+1); ++ break; ++ } ++ case SQLITE_BLOB: { ++ rc = p->pSharedBlock->xPutBlob(pCtx, p->addedRows, i, pMem[i].z, pMem[i].n); ++ break; ++ } ++ case SQLITE_NULL: { ++ rc = p->pSharedBlock->xPutNull(pCtx, p->addedRows, i); ++ break; ++ } ++ default: ++ rc = p->pSharedBlock->xPutOther(pCtx, p->addedRows, i); ++ break; ++ } ++ if( rc!=SQLITE_OK ){ ++ return rc; ++ } ++ } ++ ++ return rc; ++no_mem: ++ rc = SQLITE_NOMEM; ++ return rc; ++} ++#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ ++ + /* + ** Return the register of pOp->p2 after first preparing it to be + ** overwritten with an integer value. +@@ -90852,6 +91605,12 @@ case OP_Halt: { + VdbeFrame *pFrame; + int pcx; + ++#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION ++ if( p->pSharedBlock!=NULL ){ ++ p->pSharedBlock->xFinish(p->pSharedBlock->pContext, p->addedRows, p->totalRows); ++ } ++#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ ++ + #ifdef SQLITE_DEBUG + if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); } + #endif +@@ -91295,6 +92054,43 @@ case OP_ResultRow: { + assert( pOp->p1>0 || CORRUPT_DB ); + assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); + ++#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION ++ if( p->pSharedBlock!=NULL ){ ++ void *pCtx = p->pSharedBlock->pContext; ++ p->totalRows++; ++ if( p->totalRows<=p->startPos || p->blockFull ){ ++ break; ++ } ++ Mem *pMem = &aMem[pOp->p1]; ++ rc = copySharedBlockRow(p, pOp, pMem, pCtx); ++ if( rc==SQLITE_FULL && p->addedRows && (p->startPos + p->addedRows) <= p->pSharedBlock->requiredPos ){ ++ p->startPos += p->addedRows; ++ p->addedRows = 0; ++ p->pSharedBlock->xReset(pCtx,p->startPos); ++ p->blockFull = 0; ++ rc = copySharedBlockRow(p, pOp, pMem, pCtx); ++ } ++ ++ if( rc==SQLITE_OK ){ ++ p->addedRows++; ++ }else if( rc==SQLITE_FULL ){ ++ p->blockFull = 1; ++ }else{ ++ //SQLITE_NOMEM ++ goto no_mem; ++ } ++ ++ if( p->blockFull && p->pSharedBlock->countAllRows==0 ){ ++ p->pSharedBlock->xFinish(pCtx, p->addedRows, p->totalRows); ++ rc = SQLITE_DONE; ++ goto vdbe_return; ++ }else if( p->blockFull && p->pSharedBlock->countAllRows==1 ){ ++ rc = SQLITE_OK; ++ } ++ break; ++ } ++#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ ++ + p->cacheCtr = (p->cacheCtr + 2)|1; + p->pResultSet = &aMem[pOp->p1]; + #ifdef SQLITE_DEBUG +@@ -92091,6 +92887,17 @@ case OP_Compare: { + ** This opcode must immediately follow an OP_Compare opcode. + */ + case OP_Jump: { /* jump */ ++#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION ++ if( pOp->p5&0x80 ){ ++ if( p->pSharedBlock!=NULL ){ ++ if( p->totalRows < p->startPos || p->blockFull ){ ++ p->totalRows++; ++ pOp = &aOp[pOp->p2 - 1]; ++ } ++ } ++ break; ++ } ++#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ + assert( pOp>aOp && pOp[-1].opcode==OP_Compare ); + if( iCompare<0 ){ + VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1]; +@@ -97106,6 +97913,20 @@ case OP_IfNotZero: { /* jump, in1 */ + ** and jump to P2 if the new value is exactly zero. + */ + case OP_DecrJumpZero: { /* jump, in1 */ ++#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION ++ if( pOp->p5&0x80 ){ ++ if( p->pSharedBlock!=NULL ){ ++ if( p->totalRows < p->startPos || p->blockFull ){ ++ pIn1 = &aMem[pOp->p1]; ++ assert( pIn1->flags&MEM_Int ); ++ if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--; ++ VdbeBranchTaken(pIn1->u.i==-1, 2); ++ if( pIn1->u.i==-1 ) goto jump_to_p2; ++ } ++ } ++ break; ++ } ++#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ + pIn1 = &aMem[pOp->p1]; + assert( pIn1->flags&MEM_Int ); + if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--; +@@ -116053,6 +116874,40 @@ static void attachFunc( + if( rc==SQLITE_OK && pNew->zDbSName==0 ){ + rc = SQLITE_NOMEM_BKPT; + } ++#ifdef SQLITE_HAS_CODEC ++ if( rc==SQLITE_OK ){ ++ extern int sqlite3CodecAttach(sqlite3*, int, const void*, int); ++ extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); ++ int nKey; ++ char *zKey; ++ int t = sqlite3_value_type(argv[2]); ++ switch( t ){ ++ case SQLITE_INTEGER: ++ case SQLITE_FLOAT: ++ zErrDyn = sqlite3DbStrDup(db, "Invalid key value"); ++ rc = SQLITE_ERROR; ++ break; ++ ++ case SQLITE_TEXT: ++ case SQLITE_BLOB: ++ nKey = sqlite3_value_bytes(argv[2]); ++ zKey = (char *)sqlite3_value_blob(argv[2]); ++ rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); ++ break; ++ ++ case SQLITE_NULL: ++ /* No key specified. Use the key from URI filename, or if none, ++ ** use the key from the main database. */ ++ if( sqlite3CodecQueryParameters(db, zName, zPath)==0 ){ ++ sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); ++ if( nKey || sqlite3BtreeGetRequestedReserve(db->aDb[0].pBt)>0 ){ ++ rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); ++ } ++ } ++ break; ++ } ++ } ++#endif /* SQLITE_HAS_CODEC */ + sqlite3_free_filename( zPath ); + + /* If the file was opened successfully, read the schema for the new database. +@@ -117624,8 +118479,24 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char + testcase( zTabName[0]==0 ); /* Zero-length table names are allowed */ + pDb = &db->aDb[iDb]; + p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0); ++#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK ++ u8 tableType = p->eTabType; ++#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ + sqlite3DeleteTable(db, p); + db->mDbFlags |= DBFLAG_SchemaChange; ++#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK ++ if( tableType!=TABTYP_VIEW ){ ++ db->isDropTable = 1; ++ db->mDropTableName = sqlite3_malloc(strlen(zTabName) + 1); ++ if( db->mDropTableName!=NULL ){ ++ memcpy(db->mDropTableName, zTabName, strlen(zTabName) + 1); ++ } ++ db->mDropSchemaName = sqlite3_malloc(strlen(db->aDb[iDb].zDbSName) + 1); ++ if( db->mDropSchemaName!=NULL ){ ++ memcpy(db->mDropSchemaName, db->aDb[iDb].zDbSName, strlen(db->aDb[iDb].zDbSName) + 1); ++ } ++ } ++#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ + } + + /* +@@ -125898,10 +126769,16 @@ static void groupConcatValue(sqlite3_context *context){ + */ + SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){ + int rc = sqlite3_overload_function(db, "MATCH", 2); ++#ifdef SQLITE_HAS_CODEC ++ extern void sqlite3CodecExportData(sqlite3_context *, int, sqlite3_value **); ++#endif /* SQLITE_HAS_CODEC */ + assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); + if( rc==SQLITE_NOMEM ){ + sqlite3OomFault(db); + } ++#ifdef SQLITE_HAS_CODEC ++ sqlite3CreateFunc(db, "export_database", 1, SQLITE_TEXT, 0, sqlite3CodecExportData, 0, 0, 0, 0, 0); ++#endif /* SQLITE_HAS_CODEC */ + } + + /* +@@ -131535,6 +132412,10 @@ struct sqlite3_api_routines { + const char *(*db_name)(sqlite3*,int); + /* Version 3.40.0 and later */ + int (*value_encoding)(sqlite3_value*); ++#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK ++ /* handle after drop table done */ ++ int (*set_droptable_handle)(sqlite3*,void(*)(sqlite3*,const char*,const char*)); ++#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ + }; + + /* +@@ -131861,6 +132742,10 @@ typedef int (*sqlite3_loadext_entry)( + #define sqlite3_db_name sqlite3_api->db_name + /* Version 3.40.0 and later */ + #define sqlite3_value_encoding sqlite3_api->value_encoding ++#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK ++/* handle after drop table done */ ++#define sqlite3_set_droptable_handle sqlite3_api->set_droptable_handle ++#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ + #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ + + #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) +@@ -131884,7 +132769,7 @@ typedef int (*sqlite3_loadext_entry)( + /************** Continuing where we left off in loadext.c ********************/ + /* #include "sqliteInt.h" */ + +-#ifndef SQLITE_OMIT_LOAD_EXTENSION ++#if !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS) + /* + ** Some API routines are omitted when various features are + ** excluded from a build of SQLite. Substitute a NULL pointer +@@ -131898,7 +132783,9 @@ typedef int (*sqlite3_loadext_entry)( + # define sqlite3_column_origin_name 0 + # define sqlite3_column_origin_name16 0 + #endif ++#endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS) */ + ++#ifndef SQLITE_OMIT_LOAD_EXTENSION + #ifdef SQLITE_OMIT_AUTHORIZATION + # define sqlite3_set_authorizer 0 + #endif +@@ -131979,6 +132866,7 @@ typedef int (*sqlite3_loadext_entry)( + #if defined(SQLITE_OMIT_TRACE) + # define sqlite3_trace_v2 0 + #endif ++#endif /* !SQLITE_OMIT_LOAD_EXTENSION */ + + /* + ** The following structure contains pointers to all SQLite API routines. +@@ -131995,6 +132883,7 @@ typedef int (*sqlite3_loadext_entry)( + ** also check to make sure that the pointer to the function is + ** not NULL before calling it. + */ ++#if !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS) + static const sqlite3_api_routines sqlite3Apis = { + sqlite3_aggregate_context, + #ifndef SQLITE_OMIT_DEPRECATED +@@ -132264,7 +133153,11 @@ static const sqlite3_api_routines sqlite3Apis = { + sqlite3_bind_blob64, + sqlite3_bind_text64, + sqlite3_cancel_auto_extension, ++#ifndef SQLITE_OMIT_LOAD_EXTENSION + sqlite3_load_extension, ++#else ++ 0, ++#endif /* !SQLITE_OMIT_LOAD_EXTENSION */ + sqlite3_malloc64, + sqlite3_msize, + sqlite3_realloc64, +@@ -132375,7 +133268,10 @@ static const sqlite3_api_routines sqlite3Apis = { + #endif + sqlite3_db_name, + /* Version 3.40.0 and later */ +- sqlite3_value_encoding ++ sqlite3_value_encoding, ++#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK ++ sqlite3_set_droptable_handle ++#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ + }; + + /* True if x is the directory separator character +@@ -132386,6 +133282,9 @@ static const sqlite3_api_routines sqlite3Apis = { + # define DirSep(X) ((X)=='/') + #endif + ++#endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS) */ ++ ++#ifndef SQLITE_OMIT_LOAD_EXTENSION + /* + ** Attempt to load an SQLite extension library contained in the file + ** zFile. The entry point is zProc. zProc may be 0 in which case a +@@ -132846,6 +133745,9 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ + #define PragTyp_WAL_CHECKPOINT 43 + #define PragTyp_LOCK_STATUS 44 + #define PragTyp_STATS 45 ++#ifdef SQLITE_HAS_CODEC ++#define PragTyp_KEY 255 ++#endif /* SQLITE_HAS_CODEC */ + + /* Property flags associated with various pragma. */ + #define PragFlg_NeedSchema 0x01 /* Force schema load before running */ +@@ -133136,6 +134038,18 @@ static const PragmaName aPragmaName[] = { + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, ++#if defined(SQLITE_HAS_CODEC) ++ {/* zName: */ "hexkey", ++ /* ePragTyp: */ PragTyp_KEY, ++ /* ePragFlg: */ 0, ++ /* ColNames: */ 0, 0, ++ /* iArg: */ 2 }, ++ {/* zName: */ "hexrekey", ++ /* ePragTyp: */ PragTyp_KEY, ++ /* ePragFlg: */ 0, ++ /* ColNames: */ 0, 0, ++ /* iArg: */ 3 }, ++#endif + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + #if !defined(SQLITE_OMIT_CHECK) + {/* zName: */ "ignore_check_constraints", +@@ -133188,6 +134102,13 @@ static const PragmaName aPragmaName[] = { + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + #endif ++#if defined(SQLITE_HAS_CODEC) ++ {/* zName: */ "key", ++ /* ePragTyp: */ PragTyp_KEY, ++ /* ePragFlg: */ 0, ++ /* ColNames: */ 0, 0, ++ /* iArg: */ 0 }, ++#endif + #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + {/* zName: */ "legacy_alter_table", + /* ePragTyp: */ PragTyp_FLAG, +@@ -133295,6 +134216,15 @@ static const PragmaName aPragmaName[] = { + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_RecTriggers }, ++#endif ++#if defined(SQLITE_HAS_CODEC) ++ {/* zName: */ "rekey", ++ /* ePragTyp: */ PragTyp_KEY, ++ /* ePragFlg: */ 0, ++ /* ColNames: */ 0, 0, ++ /* iArg: */ 1 }, ++#endif ++#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + {/* zName: */ "reverse_unordered_selects", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, +@@ -133383,6 +134313,18 @@ static const PragmaName aPragmaName[] = { + /* ePragFlg: */ PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, ++#endif ++#if defined(SQLITE_HAS_CODEC) ++ {/* zName: */ "textkey", ++ /* ePragTyp: */ PragTyp_KEY, ++ /* ePragFlg: */ 0, ++ /* ColNames: */ 0, 0, ++ /* iArg: */ 4 }, ++ {/* zName: */ "textrekey", ++ /* ePragTyp: */ PragTyp_KEY, ++ /* ePragFlg: */ 0, ++ /* ColNames: */ 0, 0, ++ /* iArg: */ 5 }, + #endif + {/* zName: */ "threads", + /* ePragTyp: */ PragTyp_THREADS, +@@ -133824,6 +134766,10 @@ SQLITE_PRIVATE void sqlite3Pragma( + Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */ + const PragmaName *pPragma; /* The pragma */ + ++#ifdef SQLITE_HAS_CODEC ++ extern int sqlite3CodecPragma(sqlite3*, int, Parse *, const char *, const char *); ++#endif /* SQLITE_HAS_CODEC */ ++ + if( v==0 ) return; + sqlite3VdbeRunOnlyOnce(v); + pParse->nMem = 2; +@@ -133893,6 +134839,13 @@ SQLITE_PRIVATE void sqlite3Pragma( + goto pragma_out; + } + ++#ifdef SQLITE_HAS_CODEC ++ if(sqlite3CodecPragma(db, iDb, pParse, zLeft, zRight)) { ++ /* sqlite3CodecPragma executes internal */ ++ goto pragma_out; ++ } ++#endif /* SQLITE_HAS_CODEC */ ++ + /* Locate the pragma in the lookup table */ + pPragma = pragmaLocate(zLeft); + if( pPragma==0 ){ +@@ -135935,6 +136888,48 @@ SQLITE_PRIVATE void sqlite3Pragma( + } + #endif + ++#ifdef SQLITE_HAS_CODEC ++ /* Pragma iArg ++ ** ---------- ------ ++ ** key 0 ++ ** rekey 1 ++ ** hexkey 2 ++ ** hexrekey 3 ++ ** textkey 4 ++ ** textrekey 5 ++ */ ++ case PragTyp_KEY: { ++ if( zRight ){ ++ char zBuf[40]; ++ const char *zKey = zRight; ++ int n; ++ if( pPragma->iArg==2 || pPragma->iArg==3 ){ ++ u8 iByte; ++ int i; ++ for(i=0, iByte=0; i<(int)(sizeof(zBuf)*2) && sqlite3Isxdigit(zRight[i]); i++){ ++ iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]); ++ if( (i&1)!=0 ) zBuf[i/2] = iByte; ++ } ++ zKey = zBuf; ++ n = i/2; ++ }else{ ++ n = pPragma->iArg<4 ? sqlite3Strlen30(zRight) : -1; ++ } ++ if( (pPragma->iArg & 1)==0 ){ ++ rc = sqlite3_key_v2(db, zDb, zKey, n); ++ }else{ ++ rc = sqlite3_rekey_v2(db, zDb, zKey, n); ++ } ++ if( rc==SQLITE_OK && n!=0 ){ ++ sqlite3VdbeSetNumCols(v, 1); ++ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "ok", SQLITE_STATIC); ++ returnSingleText(v, "ok"); ++ } ++ } ++ break; ++ } ++#endif /* SQLITE_HAS_CODEC */ ++ + #if defined(SQLITE_ENABLE_CEROD) + case PragTyp_ACTIVATE_EXTENSIONS: if( zRight ){ + if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){ +@@ -138460,9 +139455,25 @@ static void selectInnerLoop( + assert( p->pEList!=0 ); + hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP; + if( pSort && pSort->pOrderBy==0 ) pSort = 0; ++#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION ++ if( hasDistinct && (pDistinct->eTnctType==WHERE_DISTINCT_UNIQUE) ){ ++ hasDistinct = WHERE_DISTINCT_NOOP; ++ sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct); ++ } ++#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ + if( pSort==0 && !hasDistinct ){ + assert( iContinue!=0 ); + codeOffset(v, p->iOffset, iContinue); ++#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION ++ if( eDest==SRT_Output ){ ++ if( p->iLimit ){ ++ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); ++ sqlite3VdbeChangeP5(v, 128); ++ } ++ sqlite3VdbeAddOp2(v, OP_Jump, 0, iContinue); ++ sqlite3VdbeChangeP5(v, 128); ++ } ++#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ + } + + /* Pull the requested columns. +@@ -138591,6 +139602,16 @@ static void selectInnerLoop( + fixDistinctOpenEph(pParse, eType, iTab, pDistinct->addrTnct); + if( pSort==0 ){ + codeOffset(v, p->iOffset, iContinue); ++#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION ++ if( eDest==SRT_Output ){ ++ if( p->iLimit ){ ++ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); ++ sqlite3VdbeChangeP5(v, 128); ++ } ++ sqlite3VdbeAddOp2(v, OP_Jump, 0, iContinue); ++ sqlite3VdbeChangeP5(v, 128); ++ } ++#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ + } + } + +@@ -139037,11 +140058,23 @@ static void generateSortTail( + addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); + VdbeCoverage(v); + assert( p->iLimit==0 && p->iOffset==0 ); ++#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION ++ if( eDest==SRT_Output ){ ++ sqlite3VdbeAddOp2(v, OP_Jump, 0, addrContinue); ++ sqlite3VdbeChangeP5(v, 128); ++ } ++#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ + sqlite3VdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab); + bSeq = 0; + }else{ + addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v); + codeOffset(v, p->iOffset, addrContinue); ++#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION ++ if( eDest==SRT_Output ){ ++ sqlite3VdbeAddOp2(v, OP_Jump, 0, addrContinue); ++ sqlite3VdbeChangeP5(v, 128); ++ } ++#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ + iSortTab = iTab; + bSeq = 1; + if( p->iOffset>0 ){ +@@ -148844,6 +149877,17 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( + } + nRes = sqlite3BtreeGetRequestedReserve(pMain); + ++#ifdef SQLITE_HAS_CODEC ++ /* A VACUUM cannot change the pagesize of an encrypted database. */ ++ if( db->nextPagesize ){ ++ extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); ++ int nKey; ++ char *zKey; ++ sqlite3CodecGetKey(db, iDb, (void**)&zKey, &nKey); ++ if( nKey ) db->nextPagesize = 0; ++ } ++#endif /* SQLITE_HAS_CODEC */ ++ + sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); + sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); + sqlite3BtreeSetPagerFlags(pTemp, pgflags|PAGER_CACHESPILL); +@@ -173422,6 +174466,29 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ + rc = setupLookaside(db, pBuf, sz, cnt); + break; + } ++#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION ++ case SQLITE_DBCONFIG_SET_SHAREDBLOCK: { ++ Vdbe *pVdbe = (Vdbe *)va_arg(ap, sqlite3_stmt*); ++ Sqlite3SharedBlockMethods *pSharedBlock = va_arg(ap, Sqlite3SharedBlockMethods*); ++ if( pVdbe==NULL ){ ++ rc = SQLITE_MISUSE; ++ break; ++ } ++ pVdbe->pSharedBlock = pSharedBlock; ++ if( pSharedBlock!=NULL ){ ++ pVdbe->startPos = pSharedBlock->startPos; ++ } ++ pVdbe->totalRows = 0; ++ pVdbe->blockFull = 0; ++ pVdbe->addedRows = 0; ++ rc = SQLITE_OK; ++ break; ++ } ++ case SQLITE_DBCONFIG_USE_SHAREDBLOCK: { ++ rc = SQLITE_OK; ++ break; ++ } ++#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ + default: { + static const struct { + int op; /* The opcode */ +@@ -175642,7 +176709,41 @@ static const char *uriParameter(const char *zFilename, const char *zParam){ + return 0; + } + +- ++#ifdef SQLITE_HAS_CODEC ++/* ++** Process URI filename query parameters relevant to the SQLite Encryption ++** Extension. Return true if any of the relevant query parameters are ++** seen and return false if not. ++*/ ++SQLITE_PRIVATE int sqlite3CodecQueryParameters( ++ sqlite3 *db, /* Database connection */ ++ const char *zDb, /* Which schema is being created/attached */ ++ const char *zUri /* URI filename */ ++){ ++ const char *zKey; ++ if( zUri==0 ){ ++ return 0; ++ }else if( (zKey = uriParameter(zUri, "hexkey"))!=0 && zKey[0] ){ ++ u8 iByte; ++ int i; ++ char zDecoded[40]; ++ for(i=0, iByte=0; i<(int)(sizeof(zDecoded)*2) && sqlite3Isxdigit(zKey[i]); i++){ ++ iByte = (iByte<<4) + sqlite3HexToInt(zKey[i]); ++ if( (i&1)!=0 ) zDecoded[i/2] = iByte; ++ } ++ sqlite3_key_v2(db, zDb, zDecoded, i/2); ++ return 1; ++ }else if( (zKey = uriParameter(zUri, "key"))!=0 ){ ++ sqlite3_key_v2(db, zDb, zKey, sqlite3Strlen30(zKey)); ++ return 1; ++ }else if( (zKey = uriParameter(zUri, "textkey"))!=0 ){ ++ sqlite3_key_v2(db, zDb, zKey, -1); ++ return 1; ++ }else{ ++ return 0; ++ } ++} ++#endif /* SQLITE_HAS_CODEC */ + + /* + ** This routine does the work of opening a database on behalf of +@@ -175987,6 +177088,12 @@ opendb_out: + }else if( rc!=SQLITE_OK ){ + db->eOpenState = SQLITE_STATE_SICK; + } ++#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK ++ db->isDropTable = 0; ++ db->mDropTableName = NULL; ++ db->mDropSchemaName = NULL; ++ db->xDropTableHandle = NULL; ++#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ + *ppDb = db; + #ifdef SQLITE_ENABLE_SQLLOG + if( sqlite3GlobalConfig.xSqllog ){ +@@ -175995,6 +177102,14 @@ opendb_out: + sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0); + } + #endif ++#ifdef SQLITE_HAS_CODEC ++ if( rc==SQLITE_OK ) { ++#ifdef SQLITE_CODEC_ATTACH_CHANGED ++ sqlite3CodecResetParameters(&db->codecParm); ++#endif /* SQLITE_CODEC_ATTACH_CHANGED */ ++ sqlite3CodecQueryParameters(db, 0, zOpen); ++ } ++#endif /* SQLITE_HAS_CODEC */ + sqlite3_free_filename(zOpen); + return rc; + } +@@ -217581,15 +218696,19 @@ static int sessionReadRecord( + } + } + if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ +- sqlite3_int64 v = sessionGetI64(aVal); +- if( eType==SQLITE_INTEGER ){ +- sqlite3VdbeMemSetInt64(apOut[i], v); ++ if( (pIn->nData-pIn->iNext)<8 ){ ++ rc = SQLITE_CORRUPT_BKPT; + }else{ +- double d; +- memcpy(&d, &v, 8); +- sqlite3VdbeMemSetDouble(apOut[i], d); ++ sqlite3_int64 v = sessionGetI64(aVal); ++ if( eType==SQLITE_INTEGER ){ ++ sqlite3VdbeMemSetInt64(apOut[i], v); ++ }else{ ++ double d; ++ memcpy(&d, &v, 8); ++ sqlite3VdbeMemSetDouble(apOut[i], d); ++ } ++ pIn->iNext += 8; + } +- pIn->iNext += 8; + } + } + } +@@ -243614,3 +244733,1667 @@ SQLITE_API int sqlite3_stmt_init( + /* Return the source-id for this library */ + SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } + /************************** End of sqlite3.c ******************************/ ++ ++#ifdef SQLITE_HAS_CODEC ++/************** Begin file hw_codec_openssl.h *******************************/ ++#ifndef EXPOSE_INTERNAL_FUNC ++#define CODEC_STATIC static ++#else ++#define CODEC_STATIC ++#endif ++ ++#define DEFAULT_CIPHER "aes-256-gcm" ++ ++typedef struct{ ++ unsigned char *buffer; ++ int bufferSize; ++}Buffer; ++/************** End file hw_codec_openssl.h *********************************/ ++/************** Begin file hw_codec.h ***************************************/ ++#define DEFAULT_PAGE_SIZE 1024 ++#define DEFAULT_ITER 10000 ++#define FILE_HEADER_SIZE 16 ++#define SALT_SIZE FILE_HEADER_SIZE ++#define HMAC_SALT_MASK 0x3a ++#define HMAC_ITER 2 ++#define MAX_HMAC_SIZE 64 ++#define MAX_INIT_VECTOR_SIZE 16 ++#define MIN_BLOCK_SIZE 16 ++ ++#define CODEC_OPERATION_ENCRYPT 1 ++#define CODEC_OPERATION_DECRYPT 0 ++ ++#define KEY_CONTEXT_HEAD_SIZE (sizeof(CodecConstant) + 3 * sizeof(int)) ++ ++typedef struct{ ++ void *cipher; ++ int keySize; ++ int keyInfoSize; ++ int cipherPageSize; ++ int initVectorSize; ++ int hmacSize; ++ int reserveSize; ++ int hmacAlgo; ++ int kdfAlgo; ++ int rekeyHmacAlgo; ++}CodecConstant; ++ ++typedef struct{ ++ CodecConstant codecConst; ++ int deriveFlag; ++ int iter; ++ int passwordSize; ++ unsigned char *password; ++ unsigned char *key; ++ unsigned char *hmacKey; ++ unsigned char *keyInfo; ++}KeyContext; ++ ++typedef struct{ ++ Btree *pBt; ++ int savePassword; ++ unsigned char salt[SALT_SIZE]; ++ unsigned char hmacSalt[SALT_SIZE]; ++ unsigned char *buffer; ++ KeyContext *readCtx; ++ KeyContext *writeCtx; ++}CodecContext; ++ ++/************** End file hw_codec.h *****************************************/ ++/************** Begin file hw_codec_openssl.c *******************************/ ++#include ++#include ++#include ++#include ++ ++unsigned int openssl_init_count = 0; ++unsigned int openssl_external_init_flag = 0; ++sqlite3_mutex *openssl_random_mutex = NULL; ++ ++CODEC_STATIC void opensslActive(){ ++ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ ++ if(openssl_init_count == 0){ ++ if(EVP_get_cipherbyname(DEFAULT_CIPHER) == NULL){ ++ OpenSSL_add_all_algorithms(); ++ }else{ ++ openssl_external_init_flag = 1; ++ } ++ } ++ ++ if(openssl_random_mutex == NULL){ ++ openssl_random_mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); ++ } ++ openssl_init_count++; ++ ++ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ return; ++} ++ ++CODEC_STATIC void opensslDeactive(){ ++ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ ++ openssl_init_count--; ++ if(openssl_init_count == 0){ ++ if(openssl_external_init_flag){ ++ openssl_external_init_flag = 0; ++ }else{ ++ EVP_cleanup(); ++ } ++ } ++ ++ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ return; ++} ++ ++CODEC_STATIC int opensslGetRandom(Buffer *buffer){ ++ sqlite3_mutex_enter(openssl_random_mutex); ++ int rc = RAND_bytes(buffer->buffer, buffer->bufferSize); ++ sqlite3_mutex_leave(openssl_random_mutex); ++ if(rc != 1){ ++ return SQLITE_ERROR; ++ } ++ return SQLITE_OK; ++} ++ ++CODEC_STATIC void *opensslGetCipher(const char *cipherName){ ++ return (void *)EVP_get_cipherbyname(cipherName); ++} ++ ++CODEC_STATIC int opensslFreeCipher(void *cipher){ ++ return SQLITE_OK; ++} ++ ++CODEC_STATIC const char *opensslGetCipherName(void *cipher){ ++ return EVP_CIPHER_name((EVP_CIPHER *)cipher); ++} ++ ++CODEC_STATIC int opensslGetKeySize(void *cipher){ ++ return EVP_CIPHER_key_length((EVP_CIPHER *)cipher); ++} ++ ++CODEC_STATIC int opensslGetInitVectorSize(void *cipher){ ++ return EVP_CIPHER_iv_length((EVP_CIPHER *)cipher); ++} ++ ++#define CIPHER_HMAC_ALGORITHM_SHA1 1 ++#define CIPHER_HMAC_ALGORITHM_SHA256 2 ++#define CIPHER_HMAC_ALGORITHM_SHA512 3 ++ ++#define DEFAULT_HMAC_ALGORITHM CIPHER_HMAC_ALGORITHM_SHA1 ++ ++#define CIPHER_HMAC_ALGORITHM_NAME_SHA1 "SHA1" ++#define CIPHER_HMAC_ALGORITHM_NAME_SHA256 "SHA256" ++#define CIPHER_HMAC_ALGORITHM_NAME_SHA512 "SHA512" ++ ++#define CIPHER_KDF_ALGORITHM_SHA1 1 ++#define CIPHER_KDF_ALGORITHM_SHA256 2 ++#define CIPHER_KDF_ALGORITHM_SHA512 3 ++ ++#define DEFAULT_KDF_ALGORITHM CIPHER_KDF_ALGORITHM_SHA1 ++ ++#define CIPHER_KDF_ALGORITHM_NAME_SHA1 "KDF_SHA1" ++#define CIPHER_KDF_ALGORITHM_NAME_SHA256 "KDF_SHA256" ++#define CIPHER_KDF_ALGORITHM_NAME_SHA512 "KDF_SHA512" ++ ++ ++CODEC_STATIC int opensslGetHmacSize(KeyContext *keyCtx){ ++ if( keyCtx==NULL ){ ++ return 0; ++ } ++ if( keyCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){ ++ return EVP_MD_size(EVP_sha1()); ++ }else if( keyCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){ ++ return EVP_MD_size(EVP_sha256()); ++ }else if( keyCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){ ++ return EVP_MD_size(EVP_sha512()); ++ } ++ return 0; ++} ++ ++CODEC_STATIC int opensslGetBlockSize(void *cipher){ ++ return EVP_CIPHER_block_size((EVP_CIPHER *)cipher); ++} ++ ++CODEC_STATIC void *opensslGetCtx(void *cipher, int mode, unsigned char *key, unsigned char *initVector){ ++ EVP_CIPHER_CTX *tmpCtx = EVP_CIPHER_CTX_new(); ++ if(tmpCtx == NULL){ ++ return (void *)tmpCtx; ++ } ++ EVP_CipherInit_ex(tmpCtx, (EVP_CIPHER *)cipher, NULL, NULL, NULL, mode); ++ EVP_CIPHER_CTX_set_padding(tmpCtx, 0); ++ EVP_CipherInit_ex(tmpCtx, NULL, NULL, key, initVector, mode); ++ return (void *)tmpCtx; ++} ++ ++CODEC_STATIC int opensslCipher(void *iCtx, Buffer *input, unsigned char *output){ ++ int outputLength = 0; ++ int cipherLength; ++ EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)iCtx; ++ EVP_CipherUpdate(ctx, output, &cipherLength, input->buffer, input->bufferSize); ++ outputLength += cipherLength; ++ output += cipherLength; ++ EVP_CipherFinal_ex(ctx, output, &cipherLength); ++ outputLength += cipherLength; ++ if(outputLength != input->bufferSize){ ++ return SQLITE_ERROR; ++ } ++ return SQLITE_OK; ++} ++ ++CODEC_STATIC void opensslFreeCtx(void *ctx){ ++ EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)ctx); ++} ++ ++CODEC_STATIC int opensslHmac(Buffer *key, Buffer *input1, Buffer *input2, Buffer *output, int hmacAlgo){ ++ HMAC_CTX *ctx = HMAC_CTX_new(); ++ if(ctx == NULL){ ++ return SQLITE_ERROR; ++ } ++ if( hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){ ++ HMAC_Init_ex(ctx, key->buffer, key->bufferSize, EVP_sha1(), NULL); ++ }else if( hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){ ++ HMAC_Init_ex(ctx, key->buffer, key->bufferSize, EVP_sha256(), NULL); ++ }else if( hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){ ++ HMAC_Init_ex(ctx, key->buffer, key->bufferSize, EVP_sha512(), NULL); ++ } ++ HMAC_Update(ctx, input1->buffer, input1->bufferSize); ++ HMAC_Update(ctx, input2->buffer, input2->bufferSize); ++ HMAC_Final(ctx, output->buffer, (unsigned int *)(&output->bufferSize)); ++ ++ HMAC_CTX_free(ctx); ++ return SQLITE_OK; ++} ++ ++CODEC_STATIC void opensslKdf(Buffer *password, Buffer *salt, int workfactor, Buffer *key, int kdfAlgo){ ++ if( kdfAlgo==CIPHER_KDF_ALGORITHM_SHA1 ){ ++ PKCS5_PBKDF2_HMAC((const char *)(password->buffer), password->bufferSize, salt->buffer, salt->bufferSize, ++ workfactor, EVP_sha1(), key->bufferSize, key->buffer); ++ }else if( kdfAlgo==CIPHER_KDF_ALGORITHM_SHA256 ){ ++ PKCS5_PBKDF2_HMAC((const char *)(password->buffer), password->bufferSize, salt->buffer, salt->bufferSize, ++ workfactor, EVP_sha256(), key->bufferSize, key->buffer); ++ }else if( kdfAlgo==CIPHER_KDF_ALGORITHM_SHA512 ){ ++ PKCS5_PBKDF2_HMAC((const char *)(password->buffer), password->bufferSize, salt->buffer, salt->bufferSize, ++ workfactor, EVP_sha512(), key->bufferSize, key->buffer); ++ } ++} ++ ++/************** End file hw_codec_openssl.c *********************************/ ++/************** Begin file hw_codec.c ***************************************/ ++ ++#include "securec.h" ++ ++typedef enum{ ++ OPERATE_CONTEXT_READ = 0, ++ OPERATE_CONTEXT_WRITE, ++ OPERATE_CONTEXT_BOTH ++}OperateContext; ++ ++CODEC_STATIC int sqlite3CodecIsHex(const unsigned char *buffer, int bufferSize){ ++ int i; ++ for(i = 0; i < bufferSize; i++){ ++ if((buffer[i] < '0' || buffer[i] > '9') && ++ (buffer[i] < 'a' || buffer[i] > 'f') && ++ (buffer[i] < 'A' || buffer[i] > 'F')){ ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++CODEC_STATIC int sqlite3CodecHex2int(char input){ ++ if(input >= '0' && input <= '9'){ ++ return (int)(input - '0'); ++ }else if(input >= 'a' && input <= 'f'){ ++ return (int)(input - 'a') + 10; ++ }else if(input >= 'A' && input <= 'F'){ ++ return (int)(input - 'A') + 10; ++ }else{ ++ return 0; ++ } ++} ++ ++CODEC_STATIC void sqlite3CodecHex2Bin(unsigned char *inputBuffer, int inputBuffersize, unsigned char *outputBuffer){ ++ int i; ++ for(i = 0; i < inputBuffersize - 1; i += 2){ ++ outputBuffer[i / 2] = sqlite3CodecHex2int(inputBuffer[i]) << 4 | sqlite3CodecHex2int(inputBuffer[i + 1]); ++ } ++ return; ++} ++ ++CODEC_STATIC void sqlite3CodecBin2Hex(unsigned char *inputBuffer, int inputBuffersize, unsigned char *outputBuffer){ ++ char *buffer = NULL; ++ int i; ++ for(i = 0; i < inputBuffersize; i++){ ++ buffer = (char *)(outputBuffer + i * 2); ++ sqlite3_snprintf(3, buffer, "%02x ", inputBuffer[i]); ++ } ++ return; ++} ++ ++CODEC_STATIC int sqlite3CodecIfMemset(unsigned char *input, unsigned char val, int len){ ++ int i; ++ for(i = 0; i < len; i++){ ++ if(input[i] != val){ ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++CODEC_STATIC int sqlite3CodecIsKeyInfoFormat(const unsigned char *input, int inputSize){ ++ return (input[0] == 'x') && (input[1] == '\'') && (input[inputSize - 1] == '\'') && (sqlite3CodecIsHex(input + 2, inputSize - 3)) ? 1 : 0; ++} ++ ++CODEC_STATIC void sqlite3CodecSetError(CodecContext *ctx, int error){ ++ if(ctx->pBt){ ++ ctx->pBt->pBt->pPager->errCode = error; ++ ctx->pBt->pBt->db->errCode = error; ++ } ++ return; ++} ++ ++CODEC_STATIC void sqlite3CodecClearDeriveKey(KeyContext *keyCtx){ ++ if(keyCtx->key != NULL){ ++ (void)memset_s(keyCtx->key, keyCtx->codecConst.keySize, 0, keyCtx->codecConst.keySize); ++ sqlite3_free(keyCtx->key); ++ keyCtx->key = NULL; ++ } ++ if(keyCtx->hmacKey != NULL){ ++ (void)memset_s(keyCtx->hmacKey, keyCtx->codecConst.keySize, 0, keyCtx->codecConst.keySize); ++ sqlite3_free(keyCtx->hmacKey); ++ keyCtx->hmacKey = NULL; ++ } ++ if(keyCtx->keyInfo != NULL){ ++ (void)memset_s(keyCtx->keyInfo, keyCtx->codecConst.keyInfoSize, 0, keyCtx->codecConst.keyInfoSize); ++ sqlite3_free(keyCtx->keyInfo); ++ keyCtx->keyInfo = NULL; ++ } ++ keyCtx->deriveFlag = 0; ++} ++ ++CODEC_STATIC void sqlite3CodecClearPassword(KeyContext *keyCtx){ ++ if(keyCtx->password != NULL){ ++ (void)memset_s(keyCtx->password, keyCtx->passwordSize, 0, keyCtx->passwordSize); ++ sqlite3_free(keyCtx->password); ++ keyCtx->password = NULL; ++ } ++ keyCtx->passwordSize = 0; ++} ++ ++CODEC_STATIC void sqlite3CodecInitDeriveKeyMemory(KeyContext *keyCtx){ ++ keyCtx->key = (unsigned char *)sqlite3Malloc(keyCtx->codecConst.keySize); ++ keyCtx->hmacKey = (unsigned char *)sqlite3Malloc(keyCtx->codecConst.keySize); ++ keyCtx->keyInfo = (unsigned char *)sqlite3Malloc(keyCtx->codecConst.keyInfoSize); ++ return; ++} ++ ++CODEC_STATIC int sqlite3CodecKeyCtxCmp(KeyContext *first, KeyContext *second){ ++ if(memcmp((unsigned char *)first, (unsigned char *)second, sizeof(CodecConstant))){ ++ return 0; ++ } ++ if(first->iter != second->iter){ ++ return 0; ++ } ++ if(first->passwordSize != second->passwordSize){ ++ return 0; ++ } ++ if((first->password != second->password) && memcmp(first->password, second->password, first->passwordSize)){ ++ return 0; ++ } ++ return 1; ++} ++ ++// This function will free all resources of key context, except it self. ++CODEC_STATIC void sqlite3CodecFreeKeyContext(KeyContext *keyCtx){ ++ sqlite3CodecClearDeriveKey(keyCtx); ++ sqlite3CodecClearPassword(keyCtx); ++ (void)opensslFreeCipher(keyCtx->codecConst.cipher); ++ (void)memset_s(keyCtx, sizeof(KeyContext), 0, KEY_CONTEXT_HEAD_SIZE); ++} ++ ++// You should clear key derive result of output before you call this function ++CODEC_STATIC int sqlite3CodecCopyDeriveKey(KeyContext *input, KeyContext *output){ ++ errno_t rc = EOK; ++ if(input->key != NULL && input->codecConst.keySize > 0){ ++ output->key = (unsigned char *)sqlite3Malloc(output->codecConst.keySize); ++ if(output->key == NULL){ ++ sqlite3CodecFreeKeyContext(output); ++ return SQLITE_NOMEM; ++ } ++ rc = memcpy_s(output->key, output->codecConst.keySize, input->key, input->codecConst.keySize); ++ if(rc != EOK){ ++ sqlite3CodecFreeKeyContext(output); ++ return SQLITE_ERROR; ++ } ++ } ++ if(input->hmacKey != NULL && input->codecConst.keySize > 0){ ++ output->hmacKey = (unsigned char *)sqlite3Malloc(output->codecConst.keySize); ++ if(output->hmacKey == NULL){ ++ sqlite3CodecFreeKeyContext(output); ++ return SQLITE_NOMEM; ++ } ++ rc = memcpy_s(output->hmacKey, output->codecConst.keySize, input->hmacKey, input->codecConst.keySize); ++ if(rc != EOK){ ++ sqlite3CodecFreeKeyContext(output); ++ return SQLITE_ERROR; ++ } ++ } ++ if(input->keyInfo != NULL && input->codecConst.keyInfoSize > 0){ ++ output->keyInfo = (unsigned char *)sqlite3Malloc(output->codecConst.keyInfoSize); ++ if(output->keyInfo == NULL){ ++ sqlite3CodecFreeKeyContext(output); ++ return SQLITE_NOMEM; ++ } ++ rc = memcpy_s(output->keyInfo, output->codecConst.keyInfoSize, input->keyInfo, input->codecConst.keyInfoSize); ++ if(rc != EOK){ ++ sqlite3CodecFreeKeyContext(output); ++ return SQLITE_ERROR; ++ } ++ } ++ return SQLITE_OK; ++} ++ ++// You should set all key infos including salt before you call this function ++CODEC_STATIC int sqlite3CodecDeriveKey(CodecContext *ctx, OperateContext whichKey){ ++ KeyContext *keyCtx = NULL; ++ KeyContext *secondKeyCtx = NULL; ++ switch(whichKey){ ++ case OPERATE_CONTEXT_READ: ++ keyCtx = ctx->readCtx; ++ secondKeyCtx = ctx->writeCtx; ++ break; ++ case OPERATE_CONTEXT_WRITE: ++ keyCtx = ctx->writeCtx; ++ secondKeyCtx = ctx->readCtx; ++ break; ++ default: ++ return SQLITE_ERROR; ++ } ++ if(keyCtx->password == NULL || keyCtx->passwordSize <= 0){ ++ return SQLITE_ERROR; ++ } ++ if(keyCtx->deriveFlag){ ++ return SQLITE_OK; ++ } ++ errno_t memcpyRc = EOK; ++ unsigned char salt[SALT_SIZE]; ++ if (ctx->pBt != NULL && sqlite3OsRead(ctx->pBt->pBt->pPager->fd, salt, SALT_SIZE, 0) == SQLITE_OK) { ++ assert(SALT_SIZE == FILE_HEADER_SIZE); ++ if (memcmp(SQLITE_FILE_HEADER, salt, SALT_SIZE) != 0 && memcmp(ctx->salt, salt, SALT_SIZE) != 0) { ++ memcpyRc = memcpy_s(ctx->salt, FILE_HEADER_SIZE, salt, SALT_SIZE); ++ if(memcpyRc != EOK){ ++ return SQLITE_ERROR; ++ } ++ } ++ } ++ sqlite3CodecInitDeriveKeyMemory(keyCtx); ++ if(keyCtx->key == NULL || keyCtx->hmacKey == NULL || keyCtx->keyInfo == NULL){ ++ sqlite3CodecClearDeriveKey(keyCtx); ++ return SQLITE_NOMEM; ++ } ++ if((keyCtx->passwordSize == keyCtx->codecConst.keyInfoSize) && ++ (sqlite3CodecIsKeyInfoFormat(keyCtx->password, keyCtx->passwordSize))){ ++ sqlite3CodecHex2Bin(keyCtx->password + 2, keyCtx->codecConst.keySize * 2, keyCtx->key); ++ sqlite3CodecHex2Bin(keyCtx->password + 2 + keyCtx->codecConst.keySize * 2, SALT_SIZE * 2, ctx->salt); ++ memcpyRc = memcpy_s(keyCtx->keyInfo, keyCtx->codecConst.keyInfoSize, keyCtx->password, keyCtx->passwordSize); ++ if(memcpyRc != EOK){ ++ return SQLITE_ERROR; ++ } ++ }else if((keyCtx->passwordSize == keyCtx->codecConst.keyInfoSize - SALT_SIZE * 2) && ++ (sqlite3CodecIsKeyInfoFormat(keyCtx->password, keyCtx->passwordSize))){ ++ sqlite3CodecHex2Bin(keyCtx->password + 2, keyCtx->codecConst.keySize * 2, keyCtx->key); ++ memcpyRc = memcpy_s(keyCtx->keyInfo, keyCtx->codecConst.keyInfoSize, keyCtx->password, keyCtx->passwordSize); ++ if(memcpyRc != EOK){ ++ return SQLITE_ERROR; ++ } ++ sqlite3CodecBin2Hex(ctx->salt, SALT_SIZE, keyCtx->keyInfo + 2 + keyCtx->codecConst.keySize * 2); ++ keyCtx->keyInfo[keyCtx->codecConst.keyInfoSize - 1] = '\''; ++ }else{ ++ Buffer password; ++ Buffer salt; ++ Buffer key; ++ password.buffer = keyCtx->password; ++ password.bufferSize = keyCtx->passwordSize; ++ salt.buffer = ctx->salt; ++ salt.bufferSize = SALT_SIZE; ++ key.buffer = keyCtx->key; ++ key.bufferSize = keyCtx->codecConst.keySize; ++ opensslKdf(&password, &salt, keyCtx->iter, &key, keyCtx->codecConst.kdfAlgo); ++ keyCtx->keyInfo[0] = 'x'; ++ keyCtx->keyInfo[1] = '\''; ++ sqlite3CodecBin2Hex(keyCtx->key, keyCtx->codecConst.keySize, keyCtx->keyInfo + 2); ++ sqlite3CodecBin2Hex(ctx->salt, SALT_SIZE, keyCtx->keyInfo + 2 + keyCtx->codecConst.keySize * 2); ++ keyCtx->keyInfo[keyCtx->codecConst.keyInfoSize - 1] = '\''; ++ } ++ int i; ++ for(i = 0; i < SALT_SIZE; i++){ ++ ctx->hmacSalt[i] = ctx->salt[i] ^ HMAC_SALT_MASK; ++ } ++ Buffer hmacPassword; ++ Buffer hmacSalt; ++ Buffer hmacKey; ++ hmacPassword.buffer = keyCtx->key; ++ hmacPassword.bufferSize = keyCtx->codecConst.keySize; ++ hmacSalt.buffer = ctx->hmacSalt; ++ hmacSalt.bufferSize = SALT_SIZE; ++ hmacKey.buffer = keyCtx->hmacKey; ++ hmacKey.bufferSize = keyCtx->codecConst.keySize; ++ opensslKdf(&hmacPassword, &hmacSalt, HMAC_ITER, &hmacKey, keyCtx->codecConst.kdfAlgo); ++ keyCtx->deriveFlag = 1; ++ if(sqlite3CodecKeyCtxCmp(keyCtx, secondKeyCtx)){ ++ sqlite3CodecClearDeriveKey(secondKeyCtx); ++ int rc = sqlite3CodecCopyDeriveKey(keyCtx, secondKeyCtx); ++ if(rc == SQLITE_OK){ ++ secondKeyCtx->deriveFlag = 1; ++ // clear password ++ if(!(ctx->savePassword)){ ++ sqlite3CodecClearPassword(secondKeyCtx); ++ } ++ } ++ } ++ // clear password ++ if(!(ctx->savePassword)){ ++ sqlite3CodecClearPassword(keyCtx); ++ } ++ return SQLITE_OK; ++} ++ ++// This function may clear key derive infos ++CODEC_STATIC int sqlite3CodecSetCodecConstant(KeyContext *keyCtx, const char *cipherName){ ++ if(keyCtx->codecConst.cipher){ ++ if(sqlite3StrICmp(cipherName, opensslGetCipherName(keyCtx->codecConst.cipher)) == 0){ ++ return SQLITE_OK; ++ } ++ } ++ sqlite3CodecClearDeriveKey(keyCtx); ++ void *cipher = opensslGetCipher(cipherName); ++ if(cipher != NULL){ ++ keyCtx->codecConst.cipher = cipher; ++ } else { ++ return SQLITE_ERROR; ++ } ++ keyCtx->codecConst.keySize = opensslGetKeySize(keyCtx->codecConst.cipher); ++ keyCtx->codecConst.keyInfoSize = (keyCtx->codecConst.keySize + SALT_SIZE) * 2 + 3; ++ keyCtx->codecConst.initVectorSize = opensslGetInitVectorSize(keyCtx->codecConst.cipher); ++ return SQLITE_OK; ++} ++ ++// You should clear key derive infos before you call this function ++CODEC_STATIC int sqlite3CodecSetIter(KeyContext *keyCtx, int iter){ ++ keyCtx->iter = iter; ++ return SQLITE_OK; ++} ++ ++#ifdef SQLITE_CODEC_ATTACH_CHANGED ++#define CIPHER_ID_AES_256_CBC 0 ++#define CIPHER_ID_AES_256_GCM 1 ++ ++#define CIPHER_TOTAL_NUM 2 ++ ++#define CIPHER_NAME_AES_256_CBC "aes-256-cbc" ++#define CIPHER_NAME_AES_256_GCM "aes-256-gcm" ++ ++struct CodecCipherNameId { ++ int cipherId; ++ const char *cipherName; ++}; ++ ++static const struct CodecCipherNameId g_cipherNameIdMap[CIPHER_TOTAL_NUM] = { ++ { CIPHER_ID_AES_256_CBC, CIPHER_NAME_AES_256_CBC }, ++ { CIPHER_ID_AES_256_GCM, CIPHER_NAME_AES_256_GCM } ++}; ++ ++SQLITE_PRIVATE void sqlite3CodecResetParameters(CodecParameter *p) ++{ ++ p->kdfIter = DEFAULT_ITER; ++ p->pageSize = DEFAULT_PAGE_SIZE; ++ p->cipher = CIPHER_ID_AES_256_GCM; ++ p->hmacAlgo = DEFAULT_HMAC_ALGORITHM; ++ p->kdfAlgo = DEFAULT_KDF_ALGORITHM; ++} ++ ++CODEC_STATIC void sqlite3CodecSetDefaultAttachCipher(CodecParameter *parm, const char *cipherName){ ++ int i; ++ for( i=0; icipher = g_cipherNameIdMap[i].cipherId; ++ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ return; ++ } ++ } ++ sqlite3_log(SQLITE_WARNING, "invalid attach cipher algorithm"); ++} ++ ++CODEC_STATIC const char *sqlite3CodecGetDefaultAttachCipher(CodecParameter *parm){ ++ const char *attachedCipher = CIPHER_NAME_AES_256_GCM; ++ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ if( (parm->cipher>=0) && (parm->ciphercipher].cipherName; ++ } ++ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ return attachedCipher; ++} ++ ++CODEC_STATIC void sqlite3CodecSetDefaultAttachKdfIter(CodecParameter *parm, int iter){ ++ if( iter<=0 ){ ++ return; ++ } ++ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ parm->kdfIter = iter; ++ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++} ++ ++CODEC_STATIC int sqlite3CodecGetDefaultAttachKdfIter(CodecParameter *parm){ ++ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ int iterNum = parm->kdfIter; ++ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ return iterNum; ++} ++ ++CODEC_STATIC void sqlite3CodecSetDefaultAttachHmacAlgo(CodecParameter *parm, int hmacAlgo){ ++ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ parm->hmacAlgo = hmacAlgo; ++ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++} ++ ++CODEC_STATIC int sqlite3CodecGetDefaultAttachHmacAlgo(CodecParameter *parm){ ++ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ int hmacAlgo = parm->hmacAlgo; ++ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ return hmacAlgo; ++} ++ ++CODEC_STATIC void sqlite3CodecSetDefaultAttachKdfAlgo(CodecParameter *parm, int kdfAlgo){ ++ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ parm->kdfAlgo = kdfAlgo; ++ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++} ++ ++CODEC_STATIC int sqlite3CodecGetDefaultAttachKdfAlgo(CodecParameter *parm){ ++ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ int kdfAlgo = parm->kdfAlgo; ++ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ return kdfAlgo; ++} ++ ++CODEC_STATIC void sqlite3CodecSetDefaultAttachPageSize(CodecParameter *parm, int pageSize){ ++ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ parm->pageSize = pageSize; ++ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++} ++ ++CODEC_STATIC int sqlite3CodecGetDefaultAttachPageSize(CodecParameter *parm){ ++ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ int pageSize = parm->pageSize; ++ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); ++ return pageSize; ++} ++ ++#endif /* SQLITE_CODEC_ATTACH_CHANGED */ ++ ++// You should clear key derive infos and password infos before you call this function ++CODEC_STATIC int sqlite3CodecSetPassword(KeyContext *keyCtx, const void *zKey, int nKey){ ++ keyCtx->passwordSize = nKey; ++ keyCtx->password = (unsigned char *)sqlite3Malloc(keyCtx->passwordSize); ++ if(keyCtx->password == NULL){ ++ return SQLITE_NOMEM; ++ } ++ errno_t rc = memcpy_s(keyCtx->password, keyCtx->passwordSize, zKey, nKey); ++ if(rc != EOK){ ++ sqlite3CodecClearPassword(keyCtx); ++ return SQLITE_ERROR; ++ } ++ return SQLITE_OK; ++} ++ ++// You should clear key derive infos and password infos before you call this function ++CODEC_STATIC int sqlite3CodecSetHmacAlgorithm(KeyContext *keyCtx, int hmacAlgo){ ++ keyCtx->codecConst.hmacAlgo = hmacAlgo; ++ keyCtx->codecConst.hmacSize = opensslGetHmacSize(keyCtx); ++ int cipherBlockSize = opensslGetBlockSize(keyCtx->codecConst.cipher); ++ int blockSize = cipherBlockSize; ++ while(blockSize < MIN_BLOCK_SIZE){ ++ blockSize += cipherBlockSize; ++ } ++ int reserveSize = MAX_INIT_VECTOR_SIZE + keyCtx->codecConst.hmacSize; ++ if(reserveSize % blockSize == 0){ ++ keyCtx->codecConst.reserveSize = reserveSize; ++ }else{ ++ keyCtx->codecConst.reserveSize = (reserveSize / blockSize + 1) * blockSize; ++ } ++ return SQLITE_OK; ++} ++ ++CODEC_STATIC int sqlite3CodecSetKdfAlgorithm(KeyContext *keyCtx, int kdfAlgo){ ++ keyCtx->codecConst.kdfAlgo = kdfAlgo; ++ return SQLITE_OK; ++} ++ ++CODEC_STATIC int sqlite3CodecSetCipherPageSize(CodecContext *ctx, int size){ ++ if(!((size != 0) && ((size & (size - 1)) == 0)) || size < 512 || size > 65536) { ++ sqlite3_log(SQLITE_ERROR, "codec: cipher_page_size not a power of 2 and between 512 and 65536 inclusive(%d).", size); ++ return SQLITE_ERROR; ++ } ++ int cipherPageSize = ctx->readCtx->codecConst.cipherPageSize; ++ (void)memset_s(ctx->buffer, cipherPageSize, 0, cipherPageSize); ++ sqlite3_free(ctx->buffer); ++ ctx->readCtx->codecConst.cipherPageSize = size; ++ ctx->writeCtx->codecConst.cipherPageSize = size; ++ ++ ctx->buffer = (unsigned char *)sqlite3Malloc(size); ++ if (ctx->buffer == NULL) { ++ sqlite3_log(SQLITE_NOMEM, "codec: alloc mem failed when set cipher page size(%d).", size); ++ return SQLITE_NOMEM; ++ } ++ return SQLITE_OK; ++} ++ ++// You should clear output before you call this function ++CODEC_STATIC int sqlite3CodecCopyKeyContext(KeyContext *input, KeyContext *output){ ++ errno_t rc = memcpy_s(output, sizeof(KeyContext), input, KEY_CONTEXT_HEAD_SIZE); ++ if(rc != EOK){ ++ return SQLITE_ERROR; ++ } ++ if(input->password != NULL && input->passwordSize > 0){ ++ output->password = (unsigned char *)sqlite3Malloc(output->passwordSize); ++ if(output->password == NULL){ ++ sqlite3CodecFreeKeyContext(output); ++ return SQLITE_NOMEM; ++ } ++ rc = memcpy_s(output->password, output->passwordSize, input->password, input->passwordSize); ++ if(rc != EOK){ ++ sqlite3CodecFreeKeyContext(output); ++ return SQLITE_ERROR; ++ } ++ } ++ return sqlite3CodecCopyDeriveKey(input, output); ++} ++ ++// You should clear key context before you call this function ++#ifdef SQLITE_CODEC_ATTACH_CHANGED ++CODEC_STATIC int sqlite3CodecInitKeyContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey, int attachFlag){ ++#else ++CODEC_STATIC int sqlite3CodecInitKeyContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey){ ++#endif /* SQLITE_CODEC_ATTACH_CHANGED */ ++ int rc = SQLITE_OK; ++ KeyContext *keyCtx = ctx->readCtx; ++#ifdef SQLITE_CODEC_ATTACH_CHANGED ++ if( attachFlag!=0 ){ ++ CodecParameter *parm = &p->db->codecParm; ++ int hmacAlgo = sqlite3CodecGetDefaultAttachHmacAlgo(parm); ++ rc = sqlite3CodecSetCodecConstant(keyCtx, sqlite3CodecGetDefaultAttachCipher(parm)); ++ rc += sqlite3CodecSetIter(keyCtx, sqlite3CodecGetDefaultAttachKdfIter(parm)); ++ if( hmacAlgo!=0 ){ ++ rc += sqlite3CodecSetHmacAlgorithm(keyCtx, hmacAlgo); ++ } ++ int attachKdfAlgo = sqlite3CodecGetDefaultAttachKdfAlgo(parm); ++ if( attachKdfAlgo!=0 ){ ++ rc += sqlite3CodecSetKdfAlgorithm(keyCtx, attachKdfAlgo); ++ } ++ int cipherPageSize = sqlite3CodecGetDefaultAttachPageSize(parm); ++ if( cipherPageSize!=0 ){ ++ rc += sqlite3CodecSetCipherPageSize(ctx, cipherPageSize); ++ if ( rc != SQLITE_OK ) { ++ sqlite3CodecFreeKeyContext(keyCtx); ++ return SQLITE_ERROR; ++ } ++ rc += sqlite3BtreeSetPageSize(p, cipherPageSize, keyCtx->codecConst.reserveSize, 0); ++ } ++ }else{ ++ rc = sqlite3CodecSetCodecConstant(keyCtx, DEFAULT_CIPHER); ++ rc += sqlite3CodecSetIter(keyCtx, DEFAULT_ITER); ++ rc += sqlite3CodecSetHmacAlgorithm(keyCtx, DEFAULT_HMAC_ALGORITHM); ++ rc += sqlite3CodecSetKdfAlgorithm(keyCtx, DEFAULT_KDF_ALGORITHM); ++ } ++#else ++ rc = sqlite3CodecSetCodecConstant(keyCtx, DEFAULT_CIPHER); ++ rc += sqlite3CodecSetIter(keyCtx, DEFAULT_ITER); ++ rc += sqlite3CodecSetHmacAlgorithm(keyCtx, DEFAULT_HMAC_ALGORITHM); ++ rc += sqlite3CodecSetKdfAlgorithm(keyCtx, DEFAULT_KDF_ALGORITHM); ++#endif /* SQLITE_CODEC_ATTACH_CHANGED */ ++ keyCtx->codecConst.rekeyHmacAlgo = DEFAULT_HMAC_ALGORITHM; ++ rc += sqlite3CodecSetPassword(keyCtx, zKey, nKey); ++ if(rc != SQLITE_OK){ ++ sqlite3CodecFreeKeyContext(keyCtx); ++ return SQLITE_ERROR; ++ } ++ return SQLITE_OK; ++} ++ ++// This function will free all resources of codec context, except it self. ++CODEC_STATIC void sqlite3CodecFreeContext(CodecContext *ctx){ ++ if(ctx->buffer){ ++ int cipherPageSize = ctx->readCtx->codecConst.cipherPageSize; ++ (void)memset_s(ctx->buffer, cipherPageSize, 0, cipherPageSize); ++ sqlite3_free(ctx->buffer); ++ ctx->buffer = NULL; ++ } ++ if(ctx->readCtx){ ++ sqlite3CodecFreeKeyContext(ctx->readCtx); ++ sqlite3_free(ctx->readCtx); ++ ctx->readCtx = NULL; ++ } ++ if(ctx->writeCtx){ ++ sqlite3CodecFreeKeyContext(ctx->writeCtx); ++ sqlite3_free(ctx->writeCtx); ++ ctx->writeCtx = NULL; ++ } ++ (void)memset_s(ctx, sizeof(CodecContext), 0, sizeof(CodecContext)); ++ return; ++} ++#ifdef SQLITE_CODEC_ATTACH_CHANGED ++CODEC_STATIC int sqlite3CodecInitContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey, int nDb){ ++ int attachFlag = (nDb > 1) ? 1 : 0; ++ int defaultPageSz = attachFlag ? p->db->codecParm.pageSize : DEFAULT_PAGE_SIZE; ++#else ++CODEC_STATIC int sqlite3CodecInitContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey){ ++ int defaultPageSz = DEFAULT_PAGE_SIZE; ++#endif /* SQLITE_CODEC_ATTACH_CHANGED */ ++ sqlite3_file *fd = p->pBt->pPager->fd; ++ ctx->pBt = p; ++ ctx->savePassword = 0; ++ ctx->buffer = (unsigned char *)sqlite3Malloc(defaultPageSz); ++ ctx->readCtx = (KeyContext *)sqlite3Malloc(sizeof(KeyContext)); ++ ctx->writeCtx = (KeyContext *)sqlite3Malloc(sizeof(KeyContext)); ++ if(ctx->buffer == NULL || ctx->readCtx == NULL || ctx->writeCtx == NULL){ ++ sqlite3CodecFreeContext(ctx); ++ return SQLITE_NOMEM; ++ } ++ errno_t memsetRc = memset_s(ctx->buffer, defaultPageSz, 0, defaultPageSz); ++ memsetRc += memset_s(ctx->readCtx, sizeof(KeyContext), 0, sizeof(KeyContext)); ++ memsetRc += memset_s(ctx->writeCtx, sizeof(KeyContext), 0, sizeof(KeyContext)); ++ if(memsetRc != EOK){ ++ sqlite3CodecFreeContext(ctx); ++ return SQLITE_ERROR; ++ } ++ ctx->readCtx->codecConst.cipherPageSize = defaultPageSz; ++ ctx->writeCtx->codecConst.cipherPageSize = defaultPageSz; ++#ifdef SQLITE_CODEC_ATTACH_CHANGED ++ int rc = sqlite3CodecInitKeyContext(ctx, p, zKey, nKey, attachFlag); ++#else ++ int rc = sqlite3CodecInitKeyContext(ctx, p, zKey, nKey); ++#endif /* SQLITE_CODEC_ATTACH_CHANGED */ ++ if(rc != SQLITE_OK){ ++ sqlite3CodecFreeContext(ctx); ++ return SQLITE_ERROR; ++ } ++ rc = sqlite3CodecCopyKeyContext(ctx->readCtx, ctx->writeCtx); ++ if(rc != SQLITE_OK){ ++ sqlite3CodecFreeContext(ctx); ++ return SQLITE_ERROR; ++ } ++ if(fd == NULL || !(isOpen(fd)) || sqlite3OsRead(fd, ctx->salt, SALT_SIZE, 0) != SQLITE_OK){ ++ Buffer salt; ++ salt.buffer = ctx->salt; ++ salt.bufferSize = SALT_SIZE; ++ rc = opensslGetRandom(&salt); ++ if(rc != SQLITE_OK){ ++ sqlite3CodecFreeContext(ctx); ++ return rc; ++ } ++ } ++ return SQLITE_OK; ++} ++ ++CODEC_STATIC int sqlite3CodecGetDbIndex(sqlite3 *db, const char *zDb){ ++ int nDbIndex; ++ if(zDb == NULL){ ++ return 0; ++ } ++ for(nDbIndex = 0; nDbIndex < db->nDb; nDbIndex++){ ++ const char *zDbSName = db->aDb[nDbIndex].zDbSName; ++ if(strcmp(zDbSName, zDb) == 0){ ++ return nDbIndex; ++ } ++ } ++ return 0; ++} ++ ++CODEC_STATIC void sqlite3CodecTransPgno(Pgno input, unsigned char *output){ ++#ifdef CIPHER_BIG_ENDAIN ++ sqlite3Put4byte(output, input); ++#else ++ output[0] = (u8)input; ++ output[1] = (u8)(input>>8); ++ output[2] = (u8)(input>>16); ++ output[3] = (u8)(input>>24); ++#endif ++} ++ ++CODEC_STATIC int sqlite3CodecHmac(KeyContext *ctx, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *output){ ++ Buffer key; ++ key.buffer = ctx->hmacKey; ++ key.bufferSize = ctx->codecConst.keySize; ++ Buffer input1; ++ input1.buffer = input; ++ input1.bufferSize = bufferSize; ++ Buffer input2; ++ unsigned char pgnoBuffer[sizeof(Pgno)]; ++ sqlite3CodecTransPgno(pgno, pgnoBuffer); ++ input2.buffer = pgnoBuffer; ++ input2.bufferSize = sizeof(Pgno); ++ Buffer outputBuffer; ++ outputBuffer.buffer = output; ++ outputBuffer.bufferSize = 0; ++ int rc = opensslHmac(&key, &input1, &input2, &outputBuffer, ctx->codecConst.hmacAlgo); ++ if(rc != SQLITE_OK || outputBuffer.bufferSize != ctx->codecConst.hmacSize){ ++ return SQLITE_ERROR; ++ } ++ return SQLITE_OK; ++} ++ ++CODEC_STATIC int sqlite3CodecCheckHmac(KeyContext *ctx, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *expectResult){ ++ if (ctx->codecConst.hmacSize <= 0) { ++ return 1; ++ } ++ int rc = SQLITE_OK; ++ if (ctx->codecConst.hmacSize <= MAX_HMAC_SIZE) { ++ unsigned char buffer[MAX_HMAC_SIZE]; ++ rc = sqlite3CodecHmac(ctx, pgno, bufferSize, input, buffer); ++ if(rc != SQLITE_OK){ ++ return 1; ++ } ++ return memcmp(buffer, expectResult, ctx->codecConst.hmacSize); ++ } else { ++ unsigned char *output = (unsigned char *)malloc(ctx->codecConst.hmacSize); ++ if (output == NULL) { ++ return 1; ++ } ++ rc = sqlite3CodecHmac(ctx, pgno, bufferSize, input, output); ++ if(rc != SQLITE_OK){ ++ free(output); ++ return 1; ++ } ++ rc = memcmp(output, expectResult, ctx->codecConst.hmacSize); ++ free(output); ++ return rc; ++ } ++} ++ ++CODEC_STATIC int sqlite3CodecEncryptData(CodecContext *ctx, OperateContext whichKey, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *output){ ++ KeyContext *keyCtx = NULL; ++ switch(whichKey){ ++ case OPERATE_CONTEXT_READ: ++ keyCtx = ctx->readCtx; ++ break; ++ case OPERATE_CONTEXT_WRITE: ++ keyCtx = ctx->writeCtx; ++ break; ++ default: ++ return SQLITE_ERROR; ++ } ++ int rc = SQLITE_OK; ++ if(!(keyCtx->deriveFlag)){ ++ rc = sqlite3CodecDeriveKey(ctx, whichKey); ++ if(rc != SQLITE_OK){ ++ return rc; ++ } ++ } ++ if(keyCtx->codecConst.keySize == 0){ ++ return SQLITE_ERROR; ++ } ++ Buffer inputBuffer; ++ inputBuffer.buffer = input; ++ inputBuffer.bufferSize = bufferSize - keyCtx->codecConst.reserveSize; ++ Buffer initVector; ++ initVector.buffer = output + inputBuffer.bufferSize; ++ initVector.bufferSize = keyCtx->codecConst.initVectorSize; ++ rc = opensslGetRandom(&initVector); ++ if(rc != SQLITE_OK){ ++ return rc; ++ } ++ void *cipherCtx = opensslGetCtx(keyCtx->codecConst.cipher, CODEC_OPERATION_ENCRYPT, keyCtx->key, initVector.buffer); ++ if(cipherCtx == NULL){ ++ return SQLITE_ERROR; ++ } ++ rc = opensslCipher(cipherCtx, &inputBuffer, output); ++ opensslFreeCtx(cipherCtx); ++ if(rc != SQLITE_OK){ ++ return rc; ++ } ++ rc = sqlite3CodecHmac(keyCtx, pgno, inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize, output, output + inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize); ++ if(rc != SQLITE_OK){ ++ return rc; ++ } ++ return SQLITE_OK; ++} ++ ++CODEC_STATIC int sqlite3CodecDecryptData(CodecContext *ctx, OperateContext whichKey, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *output){ ++ KeyContext *keyCtx = NULL; ++ switch(whichKey){ ++ case OPERATE_CONTEXT_READ: ++ keyCtx = ctx->readCtx; ++ break; ++ case OPERATE_CONTEXT_WRITE: ++ keyCtx = ctx->writeCtx; ++ break; ++ default: ++ return SQLITE_ERROR; ++ } ++ int rc = SQLITE_OK; ++ if(!(keyCtx->deriveFlag)){ ++ rc = sqlite3CodecDeriveKey(ctx, whichKey); ++ if(rc != SQLITE_OK){ ++ return rc; ++ } ++ } ++ if(keyCtx->codecConst.keySize == 0){ ++ return SQLITE_ERROR; ++ } ++ if(sqlite3CodecIfMemset(input, 0, bufferSize)){ ++ errno_t memsetRc = memset_s(output, bufferSize, 0, bufferSize); ++ if(memsetRc != EOK){ ++ return SQLITE_ERROR; ++ } ++ return SQLITE_OK; ++ }else{ ++ Buffer inputBuffer; ++ inputBuffer.buffer = input; ++ inputBuffer.bufferSize = bufferSize - keyCtx->codecConst.reserveSize; ++ if(sqlite3CodecCheckHmac(keyCtx, pgno, inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize, input, input + inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize)){ ++ sqlite3_log(SQLITE_ERROR, "codec: check hmac error at page %d, hmac %d, kdf %d, pageSize %d, iter %d.", ++ pgno, keyCtx->codecConst.hmacAlgo, keyCtx->codecConst.kdfAlgo, keyCtx->codecConst.cipherPageSize, keyCtx->iter); ++ return SQLITE_ERROR; ++ } ++ unsigned char *initVector = input + inputBuffer.bufferSize; ++ void *cipherCtx = opensslGetCtx(keyCtx->codecConst.cipher, CODEC_OPERATION_DECRYPT, keyCtx->key, initVector); ++ if(cipherCtx == NULL){ ++ return SQLITE_ERROR; ++ } ++ rc = opensslCipher(cipherCtx, &inputBuffer, output); ++ opensslFreeCtx(cipherCtx); ++ if(rc != SQLITE_OK){ ++ return rc; ++ } ++ } ++ return SQLITE_OK; ++} ++ ++void* sqlite3Codec(void *ctx, void *data, Pgno pgno, int mode){ ++ CodecContext *pCtx = (CodecContext *)ctx; ++ unsigned char *pData = (unsigned char *)data; ++ int offset = 0; ++ int rc = SQLITE_OK; ++ errno_t memcpyRc = EOK; ++ if(ctx == NULL || data == NULL){ ++ return pData; ++ } ++ if(pgno == 1){ ++ offset = FILE_HEADER_SIZE; ++ } ++ int cipherPageSize = pCtx->readCtx->codecConst.cipherPageSize; ++ switch(mode){ ++ case 0: ++ case 2: ++ case 3: ++ if(pgno == 1){ ++ memcpyRc = memcpy_s(pCtx->buffer, cipherPageSize, SQLITE_FILE_HEADER, FILE_HEADER_SIZE); ++ if(memcpyRc != EOK){ ++ sqlite3CodecSetError(pCtx, SQLITE_ERROR); ++ return pData; ++ } ++ } ++ rc = sqlite3CodecDecryptData(pCtx, OPERATE_CONTEXT_READ, pgno, cipherPageSize - offset, (unsigned char *)(pData + offset), pCtx->buffer + offset); ++ if(rc != SQLITE_OK){ ++ sqlite3CodecSetError(pCtx, rc); ++ } ++ (void)memcpy_s(pData, cipherPageSize, pCtx->buffer, cipherPageSize); ++ return pData; ++ break; ++ case 6: ++ if(pgno == 1){ ++ memcpyRc = memcpy_s(pCtx->buffer, cipherPageSize, pCtx->salt, FILE_HEADER_SIZE); ++ if(memcpyRc != EOK){ ++ sqlite3CodecSetError(pCtx, SQLITE_ERROR); ++ return pData; ++ } ++ } ++ rc = sqlite3CodecEncryptData(pCtx, OPERATE_CONTEXT_WRITE, pgno, cipherPageSize - offset, (unsigned char *)(pData + offset), pCtx->buffer + offset); ++ if(rc != SQLITE_OK){ ++ sqlite3CodecSetError(pCtx, rc); ++ return pData; ++ } ++ return pCtx->buffer; ++ break; ++ case 7: ++ if(pgno == 1){ ++ memcpyRc = memcpy_s(pCtx->buffer, cipherPageSize, pCtx->salt, FILE_HEADER_SIZE); ++ if(memcpyRc != EOK){ ++ sqlite3CodecSetError(pCtx, SQLITE_ERROR); ++ return pData; ++ } ++ } ++ rc = sqlite3CodecEncryptData(pCtx, OPERATE_CONTEXT_READ, pgno, cipherPageSize - offset, (unsigned char *)(pData + offset), pCtx->buffer + offset); ++ if(rc != SQLITE_OK){ ++ sqlite3CodecSetError(pCtx, rc); ++ return pData; ++ } ++ return pCtx->buffer; ++ break; ++ default: ++ return pData; ++ break; ++ } ++} ++ ++void sqlite3CodecDetach(void *ctx){ ++ if(ctx != NULL){ ++ sqlite3CodecFreeContext((CodecContext *)ctx); ++ sqlite3_free(ctx); ++ opensslDeactive(); ++ } ++ return; ++} ++ ++int sqlite3CodecAttach(sqlite3* db, int nDb, const void *pKey, int nKey){ ++ if(db == NULL){ ++ return SQLITE_ERROR; ++ } ++ Btree *p = db->aDb[nDb].pBt; ++ if(p == NULL || pKey == NULL || nKey <= 0){ ++ return SQLITE_OK; ++ } ++ opensslActive(); ++ CodecContext *ctx = (CodecContext *)sqlite3Malloc(sizeof(CodecContext)); ++ if(ctx == NULL){ ++ return SQLITE_NOMEM; ++ } ++ errno_t memsetRc = memset_s(ctx, sizeof(CodecContext), 0, sizeof(CodecContext)); ++ if(memsetRc != EOK){ ++ sqlite3_free(ctx); ++ return SQLITE_ERROR; ++ } ++ sqlite3_mutex_enter(db->mutex); ++#ifdef SQLITE_CODEC_ATTACH_CHANGED ++ int rc = sqlite3CodecInitContext(ctx, p, pKey, nKey, nDb); ++#else ++ int rc = sqlite3CodecInitContext(ctx, p, pKey, nKey); ++#endif /* SQLITE_CODEC_ATTACH_CHANGED */ ++ if(rc != SQLITE_OK){ ++ sqlite3_free(ctx); ++ return rc; ++ } ++ sqlite3PagerSetCodec(sqlite3BtreePager(p), sqlite3Codec, NULL, sqlite3CodecDetach, (void *)ctx); ++ ++ db->nextPagesize = ctx->readCtx->codecConst.cipherPageSize; ++ p->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED; ++ sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); ++ sqlite3BtreeSecureDelete(p, 1); ++ if(isOpen(p->pBt->pPager->fd)){ ++ sqlite3BtreeSetAutoVacuum(p, SQLITE_DEFAULT_AUTOVACUUM); ++ } ++ ++ sqlite3_mutex_leave(db->mutex); ++ ++ return SQLITE_OK; ++} ++ ++void sqlite3CodecGetKey(sqlite3* db, int nDb, void **pKey, int *nKey) ++{ ++ Btree *p = db->aDb[nDb].pBt; ++ if(p == NULL){ ++ return; ++ } ++ CodecContext *ctx = (CodecContext *)(p->pBt->pPager->pCodec); ++ if(ctx){ ++ if(ctx->savePassword){ ++ *pKey = ctx->readCtx->password; ++ *nKey = ctx->readCtx->passwordSize; ++ }else{ ++ *pKey = ctx->readCtx->keyInfo; ++ *nKey = ctx->readCtx->codecConst.keyInfoSize; ++ } ++ }else{ ++ *pKey = NULL; ++ *nKey = 0; ++ } ++ return; ++} ++ ++int sqlite3_key(sqlite3 *db, const void *pKey, int nKey){ ++ return sqlite3_key_v2(db, "main", pKey, nKey); ++} ++ ++int sqlite3_key_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey){ ++ if(db == NULL || pKey == NULL || nKey <= 0){ ++ return SQLITE_ERROR; ++ } ++ int iDb = sqlite3CodecGetDbIndex(db, zDb); ++ return sqlite3CodecAttach(db, iDb, pKey, nKey); ++} ++ ++int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey){ ++ return sqlite3_rekey_v2(db, "main", pKey, nKey); ++} ++ ++int sqlite3_rekey_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey){ ++ if(db == NULL || pKey == NULL || nKey == 0){ ++ return SQLITE_ERROR; ++ } ++ int iDb = sqlite3CodecGetDbIndex(db, zDb); ++ Btree *p = db->aDb[iDb].pBt; ++ if(p == NULL){ ++ return SQLITE_OK; ++ } ++ int pageCount; ++ Pgno pgno; ++ PgHdr *page = NULL; ++ Pager *pPager = p->pBt->pPager; ++ CodecContext *ctx = (CodecContext *)(p->pBt->pPager->pCodec); ++ if(ctx == NULL){ ++ return SQLITE_OK; ++ } ++ sqlite3CodecClearDeriveKey(ctx->writeCtx); ++ sqlite3CodecClearPassword(ctx->writeCtx); ++ int rc = sqlite3CodecSetPassword(ctx->writeCtx, pKey, nKey); ++ if(rc != SQLITE_OK){ ++ return rc; ++ } ++ sqlite3_mutex_enter(db->mutex); ++ (void)sqlite3BtreeBeginTrans(p, 1, 0); ++ sqlite3PagerPagecount(pPager, &pageCount); ++ // support hmac algo changed by using rekey operation ++ int oldHmacAlgo = ctx->writeCtx->codecConst.hmacAlgo; ++ if( ctx->writeCtx->codecConst.rekeyHmacAlgo!=ctx->writeCtx->codecConst.hmacAlgo ){ ++ sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, ctx->writeCtx->codecConst.rekeyHmacAlgo); ++ sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, ctx->writeCtx->codecConst.rekeyHmacAlgo); ++ } ++ ++ for(pgno = 1; pgno <= (unsigned int)pageCount; pgno++){ ++ if(PAGER_SJ_PGNO(pPager) != pgno){ ++ rc = sqlite3PagerGet(pPager, pgno, &page, 0); ++ if(rc == SQLITE_OK){ ++ rc = sqlite3PagerWrite(page); ++ if(rc == SQLITE_OK){ ++ sqlite3PagerUnref(page); ++ }else{ ++ sqlite3_log(SQLITE_WARNING, "sqlite3_rekey_v2: error when writing page %d: errno = %d.", pgno, rc); ++ } ++ }else{ ++ sqlite3_log(SQLITE_WARNING, "sqlite3_rekey_v2: error when reading page %d: errno = %d.", pgno, rc); ++ } ++ } ++ } ++ if(rc == SQLITE_OK){ ++ (void)sqlite3BtreeCommit(p); ++ sqlite3CodecFreeKeyContext(ctx->readCtx); ++ (void)sqlite3CodecCopyKeyContext(ctx->writeCtx, ctx->readCtx); ++ }else{ ++ if( ctx->writeCtx->codecConst.rekeyHmacAlgo!=oldHmacAlgo ){ ++ sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, oldHmacAlgo); ++ sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, oldHmacAlgo); ++ } ++ (void)sqlite3BtreeRollback(p, SQLITE_ABORT_ROLLBACK, 0); ++ } ++ sqlite3_mutex_leave(db->mutex); ++ ++ return rc; ++} ++ ++void sqlite3_activate_see(const char* zPassPhrase){ ++ return; ++} ++ ++CODEC_STATIC void sqlite3CodecReturnPragmaResult(Parse *parse, const char *label, const char *value){ ++ Vdbe *v = sqlite3GetVdbe(parse); ++ sqlite3VdbeSetNumCols(v, 1); ++ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, label, SQLITE_STATIC); ++ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, value, 0); ++ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); ++ return; ++} ++ ++// Each configuration setting operation should be done before read/write DB file or there might be some error. ++int sqlite3CodecPragma(sqlite3 *db, int iDb, Parse *parse, const char *zLeft, const char *zRight){ ++ Btree *p = db->aDb[iDb].pBt; ++ if(p == NULL){ ++ return 0; ++ } ++ CodecContext *ctx = (CodecContext *)(p->pBt->pPager->pCodec); ++#ifdef SQLITE_CODEC_ATTACH_CHANGED ++ CodecParameter *parm = &db->codecParm; ++ if(sqlite3StrICmp(zLeft, "cipher_default_attach_cipher") == 0 && zRight != NULL){ ++ (void)sqlite3CodecSetDefaultAttachCipher(parm, zRight); ++ return 1; ++ }else if(sqlite3StrICmp(zLeft, "cipher_default_attach_kdf_iter") == 0 && zRight != NULL){ ++ (void)sqlite3CodecSetDefaultAttachKdfIter(parm, atoi(zRight)); ++ return 1; ++ }else if( sqlite3StrICmp(zLeft, "cipher_default_attach_hmac_algo")==0 && zRight!=NULL ){ ++ /* ++ ** Make sure to set the Kdf algorithm after setting the Hmac algorithm, or it will not take effect. ++ ** This behavior is to ensure backward compatible. ++ */ ++ if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA1)==0 ){ ++ sqlite3CodecSetDefaultAttachHmacAlgo(parm, CIPHER_HMAC_ALGORITHM_SHA1); ++ sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA1); ++ }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA256)==0 ){ ++ sqlite3CodecSetDefaultAttachHmacAlgo(parm, CIPHER_HMAC_ALGORITHM_SHA256); ++ sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA256); ++ }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA512)==0 ){ ++ sqlite3CodecSetDefaultAttachHmacAlgo(parm, CIPHER_HMAC_ALGORITHM_SHA512); ++ sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA512); ++ }else{ ++ return 0; ++ } ++ return 1; ++ }else if( sqlite3StrICmp(zLeft, "cipher_default_attach_kdf_algo")==0 && zRight!=NULL ){ ++ if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA1)==0 ){ ++ sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA1); ++ }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA256)==0 ){ ++ sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA256); ++ }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA512)==0 ){ ++ sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA512); ++ }else{ ++ return 0; ++ } ++ return 1; ++ }else if( sqlite3StrICmp(zLeft, "cipher_default_attach_page_size")==0 && zRight!=NULL ){ ++ (void)sqlite3CodecSetDefaultAttachPageSize(parm, atoi(zRight)); ++ return 1; ++ } ++#endif /* SQLITE_CODEC_ATTACH_CHANGED */ ++ if(ctx == NULL){ ++ return 0; ++ } ++ if(sqlite3StrICmp(zLeft, "codec_cipher") == 0){ ++ if(zRight){ ++ sqlite3_mutex_enter(db->mutex); ++ (void)sqlite3CodecSetCodecConstant(ctx->readCtx, zRight); ++ (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, ctx->readCtx->codecConst.hmacAlgo); ++ (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, ctx->readCtx->codecConst.hmacAlgo); ++ sqlite3CodecFreeKeyContext(ctx->writeCtx); ++ (void)sqlite3CodecCopyKeyContext(ctx->readCtx, ctx->writeCtx); ++ sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); ++ sqlite3_mutex_leave(db->mutex); ++ }else{ ++ sqlite3CodecReturnPragmaResult(parse, "codec_cipher", opensslGetCipherName(ctx->writeCtx->codecConst.cipher)); ++ } ++ }else if(sqlite3StrICmp(zLeft, "codec_kdf_iter") == 0){ ++ if(zRight){ ++ (void)sqlite3CodecSetIter(ctx->readCtx, atoi(zRight)); ++ (void)sqlite3CodecSetIter(ctx->writeCtx, atoi(zRight)); ++ }else{ ++ char *iter = sqlite3_mprintf("%d", ctx->writeCtx->iter); ++ if(iter != NULL){ ++ sqlite3CodecReturnPragmaResult(parse, "codec_kdf_iter", iter); ++ sqlite3_free(iter); ++ } ++ } ++ }else if( sqlite3StrICmp(zLeft, "codec_hmac_algo")==0 ){ ++ /* ++ ** Make sure to set the Kdf algorithm after setting the Hmac algorithm, or it will not take effect. ++ ** This behavior is to ensure backward compatible. ++ */ ++ if(zRight){ ++ sqlite3_mutex_enter(db->mutex); ++ if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA1)==0 ){ ++ (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, CIPHER_HMAC_ALGORITHM_SHA1); ++ (void)sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, CIPHER_HMAC_ALGORITHM_SHA1); ++ (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA1); ++ (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA1); ++ }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA256)==0 ){ ++ (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, CIPHER_HMAC_ALGORITHM_SHA256); ++ (void)sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, CIPHER_HMAC_ALGORITHM_SHA256); ++ (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA256); ++ (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA256); ++ }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA512)==0 ){ ++ (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, CIPHER_HMAC_ALGORITHM_SHA512); ++ (void)sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, CIPHER_HMAC_ALGORITHM_SHA512); ++ (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA512); ++ (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA512); ++ }else{ ++ sqlite3_mutex_leave(db->mutex); ++ return 0; ++ } ++ sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); ++ sqlite3_mutex_leave(db->mutex); ++ }else{ ++ if( ctx->writeCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){ ++ sqlite3CodecReturnPragmaResult(parse, "codec_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA1); ++ }else if( ctx->writeCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){ ++ sqlite3CodecReturnPragmaResult(parse, "codec_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA256); ++ }else if( ctx->writeCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){ ++ sqlite3CodecReturnPragmaResult(parse, "codec_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA512); ++ } ++ } ++ }else if( sqlite3StrICmp(zLeft, "codec_kdf_algo")==0 ){ ++ if(zRight){ ++ sqlite3_mutex_enter(db->mutex); ++ if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA1)==0 ){ ++ (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA1); ++ (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA1); ++ }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA256)==0 ){ ++ (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA256); ++ (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA256); ++ }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA512)==0 ){ ++ (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA512); ++ (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA512); ++ }else{ ++ sqlite3_mutex_leave(db->mutex); ++ return 0; ++ } ++ sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); ++ sqlite3_mutex_leave(db->mutex); ++ }else{ ++ if( ctx->writeCtx->codecConst.kdfAlgo==CIPHER_KDF_ALGORITHM_SHA1 ){ ++ sqlite3CodecReturnPragmaResult(parse, "codec_kdf_algo", CIPHER_KDF_ALGORITHM_NAME_SHA1); ++ }else if( ctx->writeCtx->codecConst.kdfAlgo==CIPHER_KDF_ALGORITHM_SHA256 ){ ++ sqlite3CodecReturnPragmaResult(parse, "codec_kdf_algo", CIPHER_KDF_ALGORITHM_NAME_SHA256); ++ }else if( ctx->writeCtx->codecConst.kdfAlgo==CIPHER_KDF_ALGORITHM_SHA512 ){ ++ sqlite3CodecReturnPragmaResult(parse, "codec_kdf_algo", CIPHER_KDF_ALGORITHM_NAME_SHA512); ++ } ++ } ++ }else if( sqlite3StrICmp(zLeft, "codec_page_size")==0 ){ ++ if(zRight){ ++ sqlite3_mutex_enter(db->mutex); ++ int rc = sqlite3CodecSetCipherPageSize(ctx, atoi(zRight)); ++ if (rc != SQLITE_OK){ ++ sqlite3_mutex_leave(db->mutex); ++ return 0; ++ } ++ sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); ++ sqlite3_mutex_leave(db->mutex); ++ } else { ++ char *pageSize = sqlite3_mprintf("%d", ctx->readCtx->codecConst.cipherPageSize); ++ if (pageSize != NULL) { ++ sqlite3CodecReturnPragmaResult(parse, "codec_page_size", pageSize); ++ sqlite3_free(pageSize); ++ } ++ } ++ }else if(sqlite3StrICmp(zLeft, "codec_rekey_hmac_algo") == 0){ ++ if(zRight){ ++ sqlite3_mutex_enter(db->mutex); ++ if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA1)==0 ){ ++ ctx->writeCtx->codecConst.rekeyHmacAlgo = CIPHER_HMAC_ALGORITHM_SHA1; ++ }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA256)==0 ){ ++ ctx->writeCtx->codecConst.rekeyHmacAlgo = CIPHER_HMAC_ALGORITHM_SHA256; ++ }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA512)==0 ){ ++ ctx->writeCtx->codecConst.rekeyHmacAlgo = CIPHER_HMAC_ALGORITHM_SHA512; ++ }else{ ++ sqlite3_mutex_leave(db->mutex); ++ return 0; ++ } ++ sqlite3_mutex_leave(db->mutex); ++ }else{ ++ if( ctx->writeCtx->codecConst.rekeyHmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){ ++ sqlite3CodecReturnPragmaResult(parse, "codec_rekey_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA1); ++ }else if( ctx->writeCtx->codecConst.rekeyHmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){ ++ sqlite3CodecReturnPragmaResult(parse, "codec_rekey_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA256); ++ }else if( ctx->writeCtx->codecConst.rekeyHmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){ ++ sqlite3CodecReturnPragmaResult(parse, "codec_rekey_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA512); ++ } ++ } ++ }else{ ++ return 0; ++ } ++ return 1; ++} ++ ++CODEC_STATIC int sqlite3CodecExportMetadata(sqlite3 *db, const char *dbName, const char *metaName){ ++ char *sql = sqlite3_mprintf("PRAGMA %s;", metaName); ++ if(sql == NULL){ ++ return SQLITE_NOMEM; ++ } ++ sqlite3_stmt *statement = NULL; ++ int rc = sqlite3_prepare_v2(db, sql, -1, &statement, NULL); ++ sqlite3_free(sql); ++ if(rc != SQLITE_OK){ ++ return rc; ++ } ++ rc = sqlite3_step(statement); ++ if(rc != SQLITE_ROW){ ++ sqlite3_finalize(statement); ++ return rc; ++ } ++ int metadata = sqlite3_column_int(statement, 0); ++ sqlite3_finalize(statement); ++ ++ sql = sqlite3_mprintf("PRAGMA %s.%s=%d;", dbName, metaName, metadata); ++ if(sql == NULL){ ++ return SQLITE_NOMEM; ++ } ++ rc = sqlite3_exec(db, sql, NULL, NULL, NULL); ++ sqlite3_free(sql); ++ return rc; ++} ++ ++CODEC_STATIC int sqlite3CodecBatchExportSql(sqlite3 *db, const char *sql, char **errMsg){ ++ sqlite3_stmt *statement = NULL; ++ int rc = sqlite3_prepare_v2(db, sql, -1, &statement, NULL); ++ if(rc != SQLITE_OK){ ++ return rc; ++ } ++ while(sqlite3_step(statement) == SQLITE_ROW){ ++ rc = sqlite3_exec(db, (char*)sqlite3_column_text(statement, 0), NULL, NULL, errMsg); ++ if(rc != SQLITE_OK){ ++ sqlite3_finalize(statement); ++ return rc; ++ } ++ } ++ sqlite3_finalize(statement); ++ return rc; ++} ++ ++void sqlite3CodecExportData(sqlite3_context *context, int argc, sqlite3_value **argv){ ++ sqlite3 *db = sqlite3_context_db_handle(context); ++ const char *dbName = (const char*) sqlite3_value_text(argv[0]); ++ ++ int rc = SQLITE_OK; ++ char *sql = NULL; ++ char *errMsg = NULL; ++ ++ u64 flagsBackup = db->flags; ++ u32 mDbFlagsBackup = db->mDbFlags; ++ int nChangeBackup = db->nChange; ++ int nTotalChangeBackup = db->nTotalChange; ++ int (*xTraceBackup)(u32,void*,void*,void*) = db->trace.xV2; ++ ++ db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; ++ db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder); ++ db->mDbFlags |= DBFLAG_PreferBuiltin; ++ db->trace.xV2 = 0; ++ ++ rc = sqlite3CodecExportMetadata(db, dbName, "schema_version"); ++ if(rc != SQLITE_OK){ ++ goto export_finish; ++ } ++ rc = sqlite3CodecExportMetadata(db, dbName, "user_version"); ++ if(rc != SQLITE_OK){ ++ goto export_finish; ++ } ++ rc = sqlite3CodecExportMetadata(db, dbName, "application_id"); ++ if(rc != SQLITE_OK){ ++ goto export_finish; ++ } ++ sql = sqlite3_mprintf("SELECT 'CREATE TABLE %s.' || substr(sql,14) FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence' AND rootpage>0;", dbName); ++ if(sql == NULL){ ++ rc = SQLITE_NOMEM; ++ goto export_finish; ++ } ++ rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); ++ sqlite3_free(sql); ++ if(rc != SQLITE_OK){ ++ goto export_finish; ++ } ++ sql = sqlite3_mprintf("SELECT 'CREATE INDEX %s.' || substr(sql,14) FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %%';", dbName); ++ if(sql == NULL){ ++ rc = SQLITE_NOMEM; ++ goto export_finish; ++ } ++ rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); ++ sqlite3_free(sql); ++ if(rc != SQLITE_OK){ ++ goto export_finish; ++ } ++ sql = sqlite3_mprintf("SELECT 'CREATE UNIQUE INDEX %s.' || substr(sql,21) FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%';", dbName); ++ if(sql == NULL){ ++ rc = SQLITE_NOMEM; ++ goto export_finish; ++ } ++ rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); ++ sqlite3_free(sql); ++ if(rc != SQLITE_OK){ ++ goto export_finish; ++ } ++ sql = sqlite3_mprintf("SELECT 'INSERT INTO %s.' || quote(name) || ' SELECT * FROM main.' || quote(name) || ';' FROM main.sqlite_master WHERE type = 'table' AND name!='sqlite_sequence' AND rootpage>0;", dbName); ++ if(sql == NULL){ ++ rc = SQLITE_NOMEM; ++ goto export_finish; ++ } ++ rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); ++ sqlite3_free(sql); ++ if(rc != SQLITE_OK){ ++ goto export_finish; ++ } ++ sql = sqlite3_mprintf("SELECT 'DELETE FROM %s.' || quote(name) || ';' FROM %s.sqlite_master WHERE name='sqlite_sequence';", dbName, dbName); ++ if(sql == NULL){ ++ rc = SQLITE_NOMEM; ++ goto export_finish; ++ } ++ rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); ++ sqlite3_free(sql); ++ if(rc != SQLITE_OK){ ++ goto export_finish; ++ } ++ sql = sqlite3_mprintf("SELECT 'INSERT INTO %s.' || quote(name) || ' SELECT * FROM main.' || quote(name) || ';' FROM %s.sqlite_master WHERE name=='sqlite_sequence';", dbName, dbName); ++ if(sql == NULL){ ++ rc = SQLITE_NOMEM; ++ goto export_finish; ++ } ++ rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); ++ sqlite3_free(sql); ++ if(rc != SQLITE_OK){ ++ goto export_finish; ++ } ++ sql = sqlite3_mprintf("INSERT INTO %s.sqlite_master SELECT type, name, tbl_name, rootpage, sql FROM main.sqlite_master WHERE type='view' OR type='trigger' OR (type='table' AND rootpage=0);", dbName, dbName); ++ if(sql == NULL){ ++ rc = SQLITE_NOMEM; ++ goto export_finish; ++ } ++ rc = sqlite3_exec(db, sql, NULL, NULL, &errMsg); ++ sqlite3_free(sql); ++ if(rc != SQLITE_OK){ ++ goto export_finish; ++ } ++export_finish: ++ db->flags = flagsBackup; ++ db->mDbFlags = mDbFlagsBackup; ++ db->nChange = nChangeBackup; ++ db->nTotalChange = nTotalChangeBackup; ++ db->trace.xV2 = xTraceBackup; ++ if(rc != SQLITE_OK){ ++ if(errMsg != NULL) { ++ sqlite3_result_error(context, errMsg, -1); ++ sqlite3DbFree(db, errMsg); ++ } else { ++ sqlite3_result_error(context, sqlite3ErrStr(rc), -1); ++ } ++ } ++ return; ++} ++/************** End file hw_codec.c *****************************************/ ++#endif /* SQLITE_HAS_CODEC */ ++ ++ ++#ifdef SQLITE_EXPORT_SYMBOLS ++/************** Begin hw export the symbols *****************************************/ ++#if defined(__GNUC__) ++# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) ++#elif defined(_MSC_VER) ++# define EXPORT_SYMBOLS __declspec(dllexport) ++#else ++# define EXPORT_SYMBOLS ++#endif ++ ++struct sqlite3_api_routines_hw { ++ int (*initialize)(); ++ int (*config)(int,...); ++ int (*key)(sqlite3*,const void*,int); ++ int (*key_v2)(sqlite3*,const char*,const void*,int); ++ int (*rekey)(sqlite3*,const void*,int); ++ int (*rekey_v2)(sqlite3*,const char*,const void*,int); ++}; ++ ++typedef struct sqlite3_api_routines_hw sqlite3_api_routines_hw; ++static const sqlite3_api_routines_hw sqlite3HwApis = { ++ sqlite3_initialize, ++ sqlite3_config, ++#ifdef SQLITE_HAS_CODEC ++ sqlite3_key, ++ sqlite3_key_v2, ++ sqlite3_rekey, ++ sqlite3_rekey_v2 ++#else ++ 0, ++ 0, ++ 0, ++ 0 ++#endif /* SQLITE_HAS_CODEC */ ++}; ++ ++EXPORT_SYMBOLS const sqlite3_api_routines *sqlite3_export_symbols = &sqlite3Apis; ++EXPORT_SYMBOLS const sqlite3_api_routines_hw *sqlite3_export_hw_symbols = &sqlite3HwApis; ++/************** End hw export the symbols *****************************************/ ++#endif /* SQLITE_EXPORT_SYMBOLS */ +-- +2.47.0.windows.2 + diff --git a/patch/0002-add-busy-debug.patch b/patch/0002-add-busy-debug.patch new file mode 100644 index 0000000..a74a9e4 --- /dev/null +++ b/patch/0002-add-busy-debug.patch @@ -0,0 +1,818 @@ +From 65a555b62c822dc4825c76c9da28e89234d83765 Mon Sep 17 00:00:00 2001 +From: wanghaishuo +Date: Fri, 11 Apr 2025 19:47:08 +0800 +Subject: [PATCH 2/7] add busy debug + + Signed-off-by: ryne3366 +--- + src/sqlite3.c | 375 ++++++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 365 insertions(+), 10 deletions(-) + +diff --git a/src/sqlite3.c b/src/sqlite3.c +index a935685..f7bb7d5 100644 +--- a/src/sqlite3.c ++++ b/src/sqlite3.c +@@ -36790,6 +36790,45 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){ + #endif + + /************** End of os_kv.c ***********************************************/ ++/************** Define dump function *****************************************/ ++#if SQLITE_OS_UNIX ++#define DB_LOCK_NUM 3 ++#define WAL_LOCK_NUM 9 ++// 8 wal lock, 1 SHM_DMS lock, 1 TRX lock ++#define MAX_LOCK_NUM (WAL_LOCK_NUM + 1) ++#define SHM_DMS_IDX (WAL_LOCK_NUM - 1) ++#define TRX_LOCK_IDX WAL_LOCK_NUM ++#define LOCK_BY_PROCESS 1 ++#define LOCK_BY_THREAD 0 ++#define DUMP_BUF_MAX_LEN 180 ++#define DUMP_MAX_STR_LEN 21 ++ ++typedef struct LocalLockStatus { ++ u8 busyLockIdx; ++ u8 busyLockType; ++ u8 lockByProcess; ++ u8 reserved; ++ u32 lockLen; ++ u32 busyLine; ++ int curTid; ++ u8 lockStatus[MAX_LOCK_NUM]; // last index is trx lock ++} LocalLockStatus; ++__thread LocalLockStatus g_lockStatus = {0}; ++ ++#define MARK_LAST_BUSY_LINE(rc) {if ((rc)==SQLITE_BUSY || (rc) == SQLITE_LOCKED) g_lockStatus.busyLine = __LINE__;} ++static void ResetLockStatus(void); ++static void TryRecordTid(int *tidBuf, int ofs, int lockLen); ++static void TryClearTid(int *tidBuf, int ofs, int lockLen); ++static void MarkLockBusy(u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess); ++static void MarkLockStatus(u32 lockIdx, u32 lockLen, u8 lockType); ++static void MarkLockStatusByRc(int rc, u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess); ++#else ++#define MARK_LAST_BUSY_LINE(rc) ++#define ResetLockStatus(void) ++#define MarkLockBusy(A, B, C, D) ++#define MarkLockStatusByRc(A, B, C, D, E) ++#endif ++/************** End define dump function *************************************/ + /************** Begin file os_unix.c *****************************************/ + /* + ** 2004 May 22 +@@ -38564,6 +38603,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ + if( pFile->eFileLock>=eFileLock ){ + OSTRACE(("LOCK %d %s ok (already held) (unix)\n", pFile->h, + azFileLock(eFileLock))); ++ MarkLockStatus(TRX_LOCK_IDX, 1, eFileLock); + return SQLITE_OK; + } + +@@ -38588,6 +38628,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ + (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK)) + ){ + rc = SQLITE_BUSY; ++ MarkLockBusy(TRX_LOCK_IDX, 1, eFileLock, LOCK_BY_THREAD); + goto end_lock; + } + +@@ -38603,6 +38644,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ + pFile->eFileLock = SHARED_LOCK; + pInode->nShared++; + pInode->nLock++; ++ MarkLockStatus(TRX_LOCK_IDX, 1, eFileLock); + goto end_lock; + } + +@@ -38624,11 +38666,11 @@ static int unixLock(sqlite3_file *id, int eFileLock){ + if( rc!=SQLITE_BUSY ){ + storeLastErrno(pFile, tErrno); + } ++ MarkLockStatusByRc(rc, TRX_LOCK_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS); + goto end_lock; + } + } + +- + /* If control gets to this point, then actually go ahead and make + ** operating system calls for the specified lock. + */ +@@ -38644,7 +38686,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ + tErrno = errno; + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); + } +- ++ MarkLockStatusByRc(rc, TRX_LOCK_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS); + /* Drop the temporary PENDING lock */ + lock.l_start = PENDING_BYTE; + lock.l_len = 1L; +@@ -38669,6 +38711,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ + /* We are trying for an exclusive lock but another thread in this + ** same process is still holding a shared lock. */ + rc = SQLITE_BUSY; ++ MarkLockBusy(TRX_LOCK_IDX, 1, eFileLock, LOCK_BY_THREAD); + }else{ + /* The request was for a RESERVED or EXCLUSIVE lock. It is + ** assumed that there is a SHARED or greater lock on the file +@@ -38693,6 +38736,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ + storeLastErrno(pFile, tErrno); + } + } ++ MarkLockStatusByRc(rc, TRX_LOCK_IDX, 1, eFileLock, LOCK_BY_PROCESS); + } + + +@@ -38890,7 +38934,6 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ + pFile->eFileLock = NO_LOCK; + } + } +- + /* Decrement the count of locks against this same file. When the + ** count reaches zero, close any other file descriptors whose close + ** was deferred because of outstanding locks. +@@ -41187,6 +41230,7 @@ struct unixShmNode { + int nRef; /* Number of unixShm objects pointing to this */ + unixShm *pFirst; /* All unixShm objects pointing to this */ + int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */ ++ int aLockTid[SQLITE_SHM_NLOCK]; + #ifdef SQLITE_DEBUG + u8 exclMask; /* Mask of exclusive locks held */ + u8 sharedMask; /* Mask of shared locks held */ +@@ -41429,6 +41473,8 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ + rc = SQLITE_READONLY_CANTINIT; + }else{ + rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1); ++ MarkLockStatusByRc(rc, SHM_DMS_IDX, 1, EXCLUSIVE_LOCK, LOCK_BY_PROCESS); ++ MARK_LAST_BUSY_LINE(rc); + /* 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 +@@ -41440,11 +41486,15 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ + } + }else if( lock.l_type==F_WRLCK ){ + rc = SQLITE_BUSY; ++ MarkLockStatusByRc(rc, SHM_DMS_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS); ++ MARK_LAST_BUSY_LINE(rc); + } + + if( rc==SQLITE_OK ){ + assert( lock.l_type==F_UNLCK || lock.l_type==F_RDLCK ); + rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1); ++ MarkLockStatusByRc(rc, SHM_DMS_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS); ++ MARK_LAST_BUSY_LINE(rc); + } + return rc; + } +@@ -41829,7 +41879,8 @@ static int unixShmLock( + return SQLITE_IOERR_SHMLOCK; + } + aLock = pShmNode->aLock; +- ++ int *aLockTid = pShmNode->aLockTid; ++ u8 useProcessLock = LOCK_BY_THREAD; + assert( pShmNode==pDbFd->pInode->pShmNode ); + assert( pShmNode->pInode==pDbFd->pInode ); + assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK ); +@@ -41884,15 +41935,17 @@ static int unixShmLock( + if( rc==SQLITE_OK ){ + memset(&aLock[ofst], 0, sizeof(int)*n); + } ++ useProcessLock = LOCK_BY_PROCESS; + }else if( ALWAYS(p->sharedMask & (1<1 ); + aLock[ofst]--; + } +- ++ MarkLockStatusByRc(rc, ofst, n, NO_LOCK, useProcessLock); + /* Undo the local locks */ + if( rc==SQLITE_OK ){ + p->exclMask &= ~mask; + p->sharedMask &= ~mask; ++ TryClearTid(aLockTid, ofst, n); + } + } + }else if( flags & SQLITE_SHM_SHARED ){ +@@ -41903,12 +41956,14 @@ static int unixShmLock( + rc = SQLITE_BUSY; + }else if( aLock[ofst]==0 ){ + rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n); ++ useProcessLock = LOCK_BY_PROCESS; + } +- ++ MarkLockStatusByRc(rc, ofst, n, SHARED_LOCK, useProcessLock); + /* Get the local shared locks */ + if( rc==SQLITE_OK ){ + p->sharedMask |= mask; + aLock[ofst]++; ++ TryRecordTid(aLockTid, ofst, n); + } + } + }else{ +@@ -41927,14 +41982,17 @@ static int unixShmLock( + ** also update the in-memory values. */ + if( rc==SQLITE_OK ){ + rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n); ++ useProcessLock = LOCK_BY_PROCESS; + if( rc==SQLITE_OK ){ + assert( (p->sharedMask & mask)==0 ); + p->exclMask |= mask; + for(ii=ofst; iipShmMutex); +@@ -59933,6 +59991,7 @@ static int syncJournal(Pager *pPager, int newHdr){ + assert( !pagerUseWal(pPager) ); + + rc = sqlite3PagerExclusiveLock(pPager); ++ MARK_LAST_BUSY_LINE(rc); + if( rc!=SQLITE_OK ) return rc; + + if( !pPager->noSync ){ +@@ -60840,6 +60899,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){ + sqlite3OsDelete(pVfs, pPager->zJournal, 0); + if( !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK); + } ++ MARK_LAST_BUSY_LINE(rc); + sqlite3EndBenignMalloc(); + }else{ + /* The journal file exists and no other connection has a reserved +@@ -60929,6 +60989,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ + assert( pPager->tempFile==0 || pPager->eLock==EXCLUSIVE_LOCK ); + + rc = pager_wait_on_lock(pPager, SHARED_LOCK); ++ MARK_LAST_BUSY_LINE(rc); + if( rc!=SQLITE_OK ){ + assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK ); + goto failed; +@@ -60965,6 +61026,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ + ** downgraded to SHARED_LOCK before this function returns. + */ + rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); ++ MARK_LAST_BUSY_LINE(rc); + if( rc!=SQLITE_OK ){ + goto failed; + } +@@ -61579,6 +61641,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory + */ + if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){ + rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); ++ MARK_LAST_BUSY_LINE(rc); + if( rc!=SQLITE_OK ){ + return rc; + } +@@ -61591,6 +61654,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory + ** holds the write-lock. If possible, the upper layer will call it. + */ + rc = sqlite3WalBeginWriteTransaction(pPager->pWal); ++ MARK_LAST_BUSY_LINE(rc); + }else{ + /* Obtain a RESERVED lock on the database file. If the exFlag parameter + ** is true, then immediately upgrade this to an EXCLUSIVE lock. The +@@ -61598,8 +61662,10 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory + ** lock, but not when obtaining the RESERVED lock. + */ + rc = pagerLockDb(pPager, RESERVED_LOCK); ++ MARK_LAST_BUSY_LINE(rc); + if( rc==SQLITE_OK && exFlag ){ + rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); ++ MARK_LAST_BUSY_LINE(rc); + } + } + +@@ -63100,6 +63166,7 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ + if( pPager->eState==PAGER_READER ){ + assert( rc==SQLITE_OK ); + rc = pagerLockDb(pPager, RESERVED_LOCK); ++ MARK_LAST_BUSY_LINE(rc); + } + if( rc==SQLITE_OK ){ + sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); +@@ -63264,6 +63331,7 @@ static int pagerOpenWal(Pager *pPager){ + */ + if( pPager->exclusiveMode ){ + rc = pagerExclusiveLock(pPager); ++ MARK_LAST_BUSY_LINE(rc); + } + + /* Open the connection to the log file. If this operation fails, +@@ -63347,6 +63415,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){ + if( !pPager->pWal ){ + int logexists = 0; + rc = pagerLockDb(pPager, SHARED_LOCK); ++ MARK_LAST_BUSY_LINE(rc); + if( rc==SQLITE_OK ){ + rc = sqlite3OsAccess( + pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &logexists +@@ -63362,6 +63431,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){ + */ + if( rc==SQLITE_OK && pPager->pWal ){ + rc = pagerExclusiveLock(pPager); ++ MARK_LAST_BUSY_LINE(rc); + if( rc==SQLITE_OK ){ + rc = sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, + pPager->pageSize, (u8*)pPager->pTmpSpace); +@@ -64736,6 +64806,7 @@ static int walIndexRecover(Wal *pWal){ + iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock; + rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock); + if( rc ){ ++ MARK_LAST_BUSY_LINE(rc); + return rc; + } + +@@ -65576,6 +65647,7 @@ static int walCheckpoint( + if( mxSafeFrame>y ){ + assert( y<=pWal->hdr.mxFrame ); + rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1); ++ MARK_LAST_BUSY_LINE(rc); + if( rc==SQLITE_OK ){ + u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED); + AtomicStore(pInfo->aReadMark+i, iMark); +@@ -65670,8 +65742,9 @@ static int walCheckpoint( + + /* Release the reader lock held while backfilling */ + walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1); ++ } else { ++ MARK_LAST_BUSY_LINE(rc); + } +- + if( rc==SQLITE_BUSY ){ + /* Reset the return code so as not to report a checkpoint failure + ** just because there are active readers. */ +@@ -65688,11 +65761,13 @@ static int walCheckpoint( + assert( pWal->writeLock ); + if( pInfo->nBackfillhdr.mxFrame ){ + rc = SQLITE_BUSY; ++ MARK_LAST_BUSY_LINE(rc); + }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){ + u32 salt1; + sqlite3_randomness(4, &salt1); + assert( pInfo->nBackfill==pWal->hdr.mxFrame ); + rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1); ++ MARK_LAST_BUSY_LINE(rc); + if( rc==SQLITE_OK ){ + if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){ + /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as +@@ -65790,6 +65865,8 @@ SQLITE_PRIVATE int sqlite3WalClose( + walLimitSize(pWal, 0); + } + } ++ } else { ++ MARK_LAST_BUSY_LINE(rc); + } + + walIndexClose(pWal, isDelete); +@@ -65944,6 +66021,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ + walUnlockShared(pWal, WAL_WRITE_LOCK); + rc = SQLITE_READONLY_RECOVERY; + } ++ MARK_LAST_BUSY_LINE(rc); + }else{ + int bWriteLock = pWal->writeLock; + if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){ +@@ -65964,6 +66042,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ + walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); + } + } ++ MARK_LAST_BUSY_LINE(rc); + } + } + +@@ -65983,6 +66062,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ + ** writer truncated the WAL out from under it. If that happens, it + ** indicates that a writer has fixed the SHM file for us, so retry */ + if( rc==SQLITE_IOERR_SHORT_READ ) rc = WAL_RETRY; ++ MARK_LAST_BUSY_LINE(rc); + } + pWal->exclusiveMode = WAL_NORMAL_MODE; + } +@@ -66214,6 +66294,7 @@ 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 void DumpLocksByWal(Wal *pWal); + static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ + volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */ + u32 mxReadMark; /* Largest aReadMark[] value */ +@@ -66251,6 +66332,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ + return SQLITE_PROTOCOL; + } + if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39; ++#if SQLITE_OS_UNIX ++ if( cnt>=15 ) DumpLocksByWal(pWal); ++#endif /* SQLITE_OS_UNIX */ + sqlite3OsSleep(pWal->pVfs, nDelay); + } + +@@ -66277,11 +66361,14 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ + ** must be zeroed before the requested page is returned. + */ + rc = WAL_RETRY; ++ MARK_LAST_BUSY_LINE(SQLITE_BUSY); + }else if( SQLITE_OK==(rc = walLockShared(pWal, WAL_RECOVER_LOCK)) ){ + walUnlockShared(pWal, WAL_RECOVER_LOCK); + rc = WAL_RETRY; ++ MARK_LAST_BUSY_LINE(SQLITE_BUSY); + }else if( rc==SQLITE_BUSY ){ + rc = SQLITE_BUSY_RECOVERY; ++ MARK_LAST_BUSY_LINE(SQLITE_BUSY); + } + } + if( rc!=SQLITE_OK ){ +@@ -66304,6 +66391,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ + ** and can be safely ignored. + */ + rc = walLockShared(pWal, WAL_READ_LOCK(0)); ++ MARK_LAST_BUSY_LINE(SQLITE_BUSY); + walShmBarrier(pWal); + if( rc==SQLITE_OK ){ + if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){ +@@ -66321,6 +66409,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ + ** it finished. Leaving a corrupt image in the database file. + */ + walUnlockShared(pWal, WAL_READ_LOCK(0)); ++ MARK_LAST_BUSY_LINE(SQLITE_BUSY); + return WAL_RETRY; + } + pWal->readLock = 0; +@@ -66365,6 +66454,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ + }else if( rc!=SQLITE_BUSY ){ + return rc; + } ++ MARK_LAST_BUSY_LINE(rc); + } + } + if( mxI==0 ){ +@@ -66374,6 +66464,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ + + rc = walLockShared(pWal, WAL_READ_LOCK(mxI)); + if( rc ){ ++ MARK_LAST_BUSY_LINE(rc); + return rc==SQLITE_BUSY ? WAL_RETRY : rc; + } + /* Now that the read-lock has been obtained, check that neither the +@@ -66416,6 +66507,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ + || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) + ){ + walUnlockShared(pWal, WAL_READ_LOCK(mxI)); ++ MARK_LAST_BUSY_LINE(rc); + return WAL_RETRY; + }else{ + assert( mxReadMark<=pWal->hdr.mxFrame ); +@@ -66542,6 +66634,7 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ + (void)walEnableBlocking(pWal); + rc = walLockShared(pWal, WAL_CKPT_LOCK); + walDisableBlocking(pWal); ++ MARK_LAST_BUSY_LINE(rc); + + if( rc!=SQLITE_OK ){ + return rc; +@@ -67365,6 +67458,7 @@ static sqlite3_int64 g_lastCkptTime = 0; + ** If parameter xBusy is not NULL, it is a pointer to a busy-handler + ** callback. In this case this function runs a blocking checkpoint. + */ ++static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime); + SQLITE_PRIVATE int sqlite3WalCheckpoint( + Wal *pWal, /* Wal connection */ + sqlite3 *db, /* Check this handle's interrupt flag */ +@@ -67406,6 +67500,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( + ** it will not be invoked in this case. + */ + rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); ++ MARK_LAST_BUSY_LINE(rc); + testcase( rc==SQLITE_BUSY ); + testcase( rc!=SQLITE_OK && xBusy2!=0 ); + if( rc==SQLITE_OK ){ +@@ -67422,6 +67517,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( + */ + if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){ + rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1); ++ MARK_LAST_BUSY_LINE(rc); + if( rc==SQLITE_OK ){ + pWal->writeLock = 1; + }else if( rc==SQLITE_BUSY ){ +@@ -67449,7 +67545,12 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( + if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ + rc = SQLITE_CORRUPT_BKPT; + }else{ ++ sqlite3_int64 startTime; ++ sqlite3OsCurrentTimeInt64(db->pVfs, &startTime); + rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf); ++ if (rc == SQLITE_OK){ ++ walLogCheckpointInfo(pWal, db, startTime); ++ } + } + + /* If no error occurred, set the output variables. */ +@@ -71166,6 +71267,7 @@ static void pageReinit(DbPage *pData){ + } + } + ++static void DumpLocksByPager(Pager *pPager); + /* + ** Invoke the busy handler for a btree. + */ +@@ -71173,7 +71275,13 @@ static int btreeInvokeBusyHandler(void *pArg){ + BtShared *pBt = (BtShared*)pArg; + assert( pBt->db ); + assert( sqlite3_mutex_held(pBt->db->mutex) ); +- return sqlite3InvokeBusyHandler(&pBt->db->busyHandler); ++ int rc = sqlite3InvokeBusyHandler(&pBt->db->busyHandler); ++#if SQLITE_OS_UNIX ++ if (rc == 0) { ++ DumpLocksByPager(pBt->pPager); ++ } ++#endif /* SQLITE_OS_UNIX */ ++ return rc; + } + + /* +@@ -71601,7 +71709,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){ + } + } + #endif +- ++ ResetLockStatus(); + /* Rollback any active transaction and free the handle structure. + ** The call to sqlite3BtreeRollback() drops any table-locks held by + ** this handle. +@@ -79629,8 +79737,10 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int * + if( p ){ + BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); ++ ResetLockStatus(); + if( pBt->inTransaction!=TRANS_NONE ){ + rc = SQLITE_LOCKED; ++ MARK_LAST_BUSY_LINE(rc); + }else{ + rc = sqlite3PagerCheckpoint(pBt->pPager, p->db, eMode, pnLog, pnCkpt); + } +@@ -85479,6 +85589,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ + nTrans++; + } + rc = sqlite3PagerExclusiveLock(pPager); ++ MARK_LAST_BUSY_LINE(rc); + sqlite3BtreeLeave(pBt); + } + } +@@ -246354,9 +246465,253 @@ export_finish: + return; + } + /************** End file hw_codec.c *****************************************/ +-#endif /* SQLITE_HAS_CODEC */ ++#endif + ++#if SQLITE_OS_UNIX ++#include ++#include ++static inline int OsGetTid(void) ++{ ++#if defined(__linux__) ++ return (int)syscall(__NR_gettid); ++#elif defined(__APPLE__) ++ return (int)syscall(SYS_thread_selfid); ++#else ++ return 0; ++#endif ++} + ++static void ResetLockStatus(void) ++{ ++ (void)memset(&g_lockStatus, 0, sizeof(g_lockStatus)); ++ g_lockStatus.curTid = OsGetTid(); ++} ++/* ++** Record lock info, correspond wal aLock buf, 1 aLock: 1 ++*/ ++static inline void TryRecordTid(int *tidBuf, int ofs, int lockLen) ++{ ++ int lockOfs = ofs + lockLen; ++ for (int i = ofs; i < lockOfs; i++) { ++ if (tidBuf[i] == 0) { ++ tidBuf[i] = g_lockStatus.curTid; ++ } ++ } ++} ++/* ++** Clear locks info. ++*/ ++static inline void TryClearTid(int *tidBuf, int ofs, int lockLen) ++{ ++ int lockOfs = ofs + lockLen; ++ for (int i = ofs; i < lockOfs; i++) { ++ if (tidBuf[i] == g_lockStatus.curTid) { ++ tidBuf[i] = 0; ++ } ++ } ++} ++ ++static inline void MarkLockBusy(u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess) ++{ ++ g_lockStatus.busyLockIdx = lockIdx; ++ g_lockStatus.busyLockType = lockType; ++ g_lockStatus.lockByProcess = lockByProcess; ++ g_lockStatus.lockLen = lockLen; ++} ++ ++static void MarkLockStatus(u32 lockIdx, u32 lockLen, u8 lockType) ++{ ++ if (lockLen == 0 || (lockIdx + lockLen) > MAX_LOCK_NUM) { ++ sqlite3_log(SQLITE_ERROR, "Unexpect lock index %u lockLen %d!", lockIdx, lockLen); ++ return; ++ } ++ // only busy error code need record ++ if (g_lockStatus.lockLen != 0 && lockIdx == g_lockStatus.busyLockIdx) { ++ g_lockStatus.busyLockIdx = 0; ++ g_lockStatus.busyLockType = NO_LOCK; ++ g_lockStatus.lockLen = 0; ++ } ++ if (lockLen == 1) { ++ g_lockStatus.lockStatus[lockIdx] = lockType; ++ } else { ++ size_t len = sizeof(u8) * lockLen; ++ (void)memset(&g_lockStatus.lockStatus[lockIdx], lockType, len); ++ } ++} ++ ++static inline void MarkLockStatusByRc(int rc, u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess) ++{ ++ if (rc == SQLITE_OK) { ++ MarkLockStatus(lockIdx, lockLen, lockType); ++ } else if (rc == SQLITE_BUSY) { ++ MarkLockBusy(lockIdx, lockLen, lockType, lockByProcess); ++ } ++} ++ ++static inline const char *IdxToLockName(u32 idx) ++{ ++ const char *lockName[MAX_LOCK_NUM] = {"write", "ckpt", "recover", "read0", ++ "read1", "read2", "read3", "read4", "wal_dms", "trxLock"}; ++ return (idx < MAX_LOCK_NUM) ? lockName[idx] : "errLock"; ++} ++ ++static void DumpHandleLock(char *dumpBuf, int dumpBufLen) ++{ ++ char *tmp = dumpBuf; ++ u8 *lockStatus = g_lockStatus.lockStatus; ++ int availLen = dumpBufLen - 1; ++ dumpBuf[availLen] = '\0'; ++ for (int i = 0; i < MAX_LOCK_NUM && availLen > DUMP_MAX_STR_LEN; i++) { ++ if (lockStatus[i] != NO_LOCK) { ++ tmp[0] = '\0'; ++ sqlite3_snprintf(availLen, tmp, "<%s, %d>", IdxToLockName((u32)i), lockStatus[i]); ++ int len = strlen(tmp); ++ tmp += len; ++ availLen -= len; ++ } ++ } ++ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]BusyLine:%d, idx:%d, type:%d, fileLock:%d, len:%d, handleLocks:%s", ++ g_lockStatus.busyLine, g_lockStatus.busyLockIdx, g_lockStatus.busyLockType, g_lockStatus.lockByProcess, ++ g_lockStatus.lockLen, tmp != dumpBuf ? dumpBuf : "none"); ++} ++ ++static inline const char *FlockToName(int l_type) ++{ ++ return l_type == F_RDLCK ? "F_RDLCK" : ++ l_type == F_WRLCK ? "F_WRLCK" : ++ l_type == F_UNLCK ? "F_UNLCK" : "F_UNKNOWN"; ++} ++ ++static int DumpProcessLocks(int fd, struct flock *lock, const char *lockName, char *dumpBuf, int bufLen) ++{ ++ dumpBuf[0] = '\0'; ++ if (osFcntl(fd, F_GETLK, lock) != SQLITE_OK) { ++ sqlite3_log(SQLITE_ERROR, "[SQLite]Get wal file lock ofs %u failed, errno: %d", lock->l_start, errno); ++ return 0; ++ } ++ if (lock->l_type != F_UNLCK) { ++ sqlite3_snprintf(bufLen, dumpBuf, "<%s, pid:%u, %s>", lockName, lock->l_pid, FlockToName(lock->l_type)); ++ return strlen(dumpBuf); ++ } ++ return 0; ++} ++ ++static void DumpTrxProcessLocks(unixFile *file, char *dumpBuf, int dumpBufLen) ++{ ++ unixInodeInfo *inode = file->pInode; ++ if (inode == NULL) { ++ sqlite3_log(SQLITE_ERROR, "[SQLite]Inode is null!"); ++ return; ++ } ++ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]acqLock:%d, dbRef:%d, lockCnt:%d, curLock:%d, processLock:%d", ++ file->eFileLock, inode->nRef, inode->nLock, inode->eFileLock, inode->bProcessLock); ++ const char *lockName[DB_LOCK_NUM] = {"pending", "reserved", "shared_first"}; ++ char *tmp = dumpBuf; ++ int availLen = dumpBufLen - 1; ++ dumpBuf[availLen] = '\0'; ++ for (int i = 0; i < DB_LOCK_NUM && availLen > DUMP_MAX_STR_LEN; i++) { ++ off_t ofs = i + PENDING_BYTE; ++ off_t lockLen = (ofs == SHARED_FIRST) ? SHARED_SIZE : 1; ++ struct flock lock = {.l_type = F_WRLCK, .l_start = ofs, .l_len = lockLen, .l_whence = SEEK_SET}; ++ int lockBufLen = DumpProcessLocks(file->h, &lock, lockName[i], tmp, availLen); ++ tmp += lockBufLen; ++ availLen -= lockBufLen; ++ } ++ if (tmp != dumpBuf) { ++ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]Trx locks: %s", dumpBuf); ++ } ++} ++ ++static void DumpWalLocks(unixFile *file, u8 walEnabled, char *dumpBuf, int dumpBufLen) ++{ ++ if (file->pShm == NULL || file->pShm->pShmNode == NULL) { ++ sqlite3_log(SQLITE_ERROR, "[SQLite]Wal mode disabled! pShm or pShmNode is NULL"); ++ return; ++ } ++ if (!walEnabled) { ++ sqlite3_log(SQLITE_ERROR, "[SQLite] walEnabled false"); ++ } ++ unixShmNode *pShmNode = file->pShm->pShmNode; ++ char *tmp = dumpBuf; ++ int availLen = dumpBufLen - 1; ++ dumpBuf[availLen] = '\0'; ++ for (int i = 0; i < WAL_LOCK_NUM && availLen > DUMP_MAX_STR_LEN; i++) { ++ if (i < SQLITE_SHM_NLOCK && pShmNode->aLock[i]) { ++ tmp[0] = '\0'; ++ sqlite3_snprintf(availLen, tmp, "<%s, %d, tid:%d>", IdxToLockName((u32)i), pShmNode->aLock[i], ++ pShmNode->aLockTid[i]); ++ int strLen = strlen(tmp); ++ tmp += strLen; ++ availLen -= strLen; ++ } ++ off_t ofs = i + WALINDEX_LOCK_OFFSET; ++ struct flock lock = {.l_type = F_WRLCK, .l_start = ofs, .l_len = 1, .l_whence = SEEK_SET}; ++ int bufLen = DumpProcessLocks(pShmNode->hShm, &lock, IdxToLockName((u32)i), tmp, availLen); ++ tmp += bufLen; ++ availLen -= bufLen; ++ } ++ if (tmp != dumpBuf) { ++ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]Wal locks: %s", dumpBuf); ++ } ++} ++ ++static void DumpLocksInfo(unixFile *file, int walEnabled) ++{ ++ char *dumpBuf = sqlite3Malloc(DUMP_BUF_MAX_LEN); ++ if (dumpBuf == NULL) { ++ sqlite3_log(SQLITE_ERROR, "[SQLite]Can't alloc bufferSz %d for dump!", DUMP_BUF_MAX_LEN); ++ return; ++ } ++ DumpHandleLock(dumpBuf, DUMP_BUF_MAX_LEN); ++ DumpTrxProcessLocks(file, dumpBuf, DUMP_BUF_MAX_LEN); ++ DumpWalLocks(file, walEnabled, dumpBuf, DUMP_BUF_MAX_LEN); ++ sqlite3_free(dumpBuf); ++} ++ ++#ifndef SQLITE_OMIT_WAL ++static void DumpLocksByWal(Wal *pWal) ++{ ++ if (pWal == NULL) { ++ sqlite3_log(SQLITE_ERROR, "Wal ptr is NULL!"); ++ return; ++ } ++ if (pWal->pVfs == NULL || sqlite3_stricmp(pWal->pVfs->zName, "unix") != 0) { ++ return; ++ } ++ DumpLocksInfo((unixFile *)(pWal->pDbFd), 1); ++} ++#endif /* #ifndef SQLITE_OMIT_WAL */ ++ ++static void DumpLocksByPager(Pager *pPager) ++{ ++ if (pPager == NULL) { ++ sqlite3_log(SQLITE_ERROR, "Pager ptr is NULL!"); ++ return; ++ } ++ if (pPager->pVfs == NULL || sqlite3_stricmp(pPager->pVfs->zName, "unix") != 0) { ++ return; ++ } ++#ifndef SQLITE_OMIT_WAL ++ DumpLocksInfo((unixFile *)(pPager->fd), pPager->pWal != NULL); ++#else /* #ifndef SQLITE_OMIT_WAL */ ++ DumpLocksInfo((unixFile *)(pPager->fd), 0); ++#endif /* #ifndef SQLITE_OMIT_WAL */ ++} ++#endif /* SQLITE_OS_UNIX */ ++ ++#ifndef SQLITE_OMIT_WAL ++static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime) { ++ sqlite3_int64 endTime; ++ sqlite3OsCurrentTimeInt64(db->pVfs, &endTime); ++ sqlite3_int64 timeUse = endTime - startTime; ++ /* Only when timeUse > 1500ms or wal size > 50MB, default pageSize 4K, 50*1024/4 = 12800 */ ++ if (timeUse > 1500 || pWal->hdr.mxFrame > 12800) { ++ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]Wal ckpt use time: %lld(ms), wal frame: %u", ++ timeUse, pWal->hdr.mxFrame); ++ } ++} ++#endif ++// hw export the symbols + #ifdef SQLITE_EXPORT_SYMBOLS + /************** Begin hw export the symbols *****************************************/ + #if defined(__GNUC__) +-- +2.47.0.windows.2 + diff --git a/patch/0003-add-meta-dwr.patch b/patch/0003-add-meta-dwr.patch new file mode 100644 index 0000000..af83d13 --- /dev/null +++ b/patch/0003-add-meta-dwr.patch @@ -0,0 +1,1336 @@ +From 528a2badfd4a5e1a79e1359436f628b0821df231 Mon Sep 17 00:00:00 2001 +From: wanghaishuo +Date: Sat, 12 Apr 2025 09:26:04 +0800 +Subject: [PATCH 3/7] add meta dwr + +Signed-off-by: ryne3366 +--- + src/sqlite3.c | 1148 ++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 1136 insertions(+), 12 deletions(-) + +diff --git a/src/sqlite3.c b/src/sqlite3.c +index f7bb7d5..71f902b 100644 +--- a/src/sqlite3.c ++++ b/src/sqlite3.c +@@ -779,6 +779,7 @@ SQLITE_API int sqlite3_exec( + #define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ + #define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ + #define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ ++#define SQLITE_META_RECOVERED 66 /* meta page recovered*/ + /* end-of-error-codes */ + + /* +@@ -14964,7 +14965,6 @@ typedef int VList; + # define SQLITE_OS_UNIX 0 + #endif + +- + #endif /* SQLITE_OS_SETUP_H */ + + /************** End of os_setup.h ********************************************/ +@@ -56138,6 +56138,26 @@ struct PagerSavepoint { + #endif + }; + ++#if !defined(SQLITE_OS_UNIX) && defined(SQLITE_META_DWR) ++#undef SQLITE_META_DWR ++#endif ++ ++#ifdef SQLITE_META_DWR ++static int PragmaMetaDoubleWrie(sqlite3 *db, int iDb, Parse *parse, const char *zLeft, const char *zRight); ++typedef struct MetaDwrHdr MetaDwrHdr; ++static int MetaDwrWriteHeader(Pager *pPager, MetaDwrHdr *hdr); ++static int MetaDwrUpdateMetaPages(Btree *pBt); ++static void MetaDwrPagerRelease(Pager *pPager); ++static int MetaDwrOpenFile(Pager *pPager, u8 openCreate); ++static void MetaDwrCheckVacuum(BtShared *pBt); ++static int MetaDwrRecoverAndBeginTran(Btree *pBt, int wrflag, int *pSchemaVersion); ++static int MetaDwrOpenAndCheck(Btree *pBt); ++static void MetaDwrDisable(Btree *pBt); ++#define META_HEADER_CHANGED 1 ++#define META_SCHEMA_CHANGED 2 ++#define META_IN_RECOVERY 1 ++#define META_RECOVER_SUCCESS 2 ++#endif + /* + ** Bits of the Pager.doNotSpill flag. See further description below. + */ +@@ -56403,6 +56423,13 @@ struct Pager { + Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */ + char *zWal; /* File name for write-ahead log */ + #endif ++#ifdef SQLITE_META_DWR ++ u8 metaChanged; ++ sqlite3_file *metaFd; ++ MetaDwrHdr *metaHdr; ++ void *metaMapPage; ++ int (*xGetMethod)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */ ++#endif + }; + + /* +@@ -56762,7 +56789,11 @@ static void setGetterMethod(Pager *pPager){ + pPager->xGet = getPageMMap; + #endif /* SQLITE_MAX_MMAP_SIZE>0 */ + }else{ ++#ifdef SQLITE_META_DWR ++ pPager->xGet = pPager->xGetMethod ? pPager->xGetMethod : getPageNormal; ++#else + pPager->xGet = getPageNormal; ++#endif + } + } + +@@ -57813,7 +57844,14 @@ static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){ + } + sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize); + } +- ++#ifdef SQLITE_META_DWR ++ if (bCommit && pPager->metaChanged != 0) { ++ sqlite3BeginBenignMalloc(); ++ (void)MetaDwrWriteHeader(pPager, pPager->metaHdr); ++ sqlite3EndBenignMalloc(); ++ pPager->metaChanged = 0; ++ } ++#endif + if( pagerUseWal(pPager) ){ + /* Drop the WAL write-lock, if any. Also, if the connection was in + ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE +@@ -59890,6 +59928,9 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ + sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,a); + pPager->pWal = 0; + } ++#endif ++#ifdef SQLITE_META_DWR ++ MetaDwrPagerRelease(pPager); + #endif + pager_reset(pPager); + if( MEMDB ){ +@@ -60736,7 +60777,11 @@ act_like_temp_file: + rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb, + !memDb?pagerStress:0, (void *)pPager, pPager->pPCache); + } +- ++#ifdef SQLITE_META_DWR ++ if( rc==SQLITE_OK && !memDb && !readOnly){ ++ (void)MetaDwrOpenFile(pPager, 0); ++ } ++#endif + /* If an error occurred above, free the Pager structure and close the file. + */ + if( rc!=SQLITE_OK ){ +@@ -61168,7 +61213,6 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ + if( pPager->tempFile==0 && pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){ + rc = pagerPagecount(pPager, &pPager->dbSize); + } +- + failed: + if( rc!=SQLITE_OK ){ + assert( !MEMDB ); +@@ -62436,7 +62480,6 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){ + pPager->eState = PAGER_READER; + return SQLITE_OK; + } +- + PAGERTRACE(("COMMIT %d\n", PAGERID(pPager))); + rc = pager_end_transaction(pPager, pPager->setSuper, 1); + return pager_error(pPager, rc); +@@ -68267,6 +68310,10 @@ struct BtShared { + #endif + u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ + int nPreformatSize; /* Size of last cell written by TransferRow() */ ++#ifdef SQLITE_META_DWR ++ u32 maxMetaPage; ++ u32 metaRecoverStatus; ++#endif + }; + + /* +@@ -71563,8 +71610,8 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( + } + } + #endif +- *ppBtree = p; + ++ *ppBtree = p; + btree_open_out: + if( rc!=SQLITE_OK ){ + if( pBt && pBt->pPager ){ +@@ -72529,7 +72576,12 @@ trans_begun: + rc = sqlite3PagerOpenSavepoint(pPager, p->db->nSavepoint); + } + } +- ++#ifdef SQLITE_META_DWR ++ if (rc == SQLITE_NOTADB || rc == SQLITE_CORRUPT) { ++ int rc1 = MetaDwrRecoverAndBeginTran(p, wrflag, pSchemaVersion); ++ rc = (rc1 == SQLITE_OK) ? SQLITE_OK : rc; ++ } ++#endif + btreeIntegrity(p); + sqlite3BtreeLeave(p); + return rc; +@@ -72896,6 +72948,9 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){ + if( rc==SQLITE_OK ){ + rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); + put4byte(&pBt->pPage1->aData[28], pBt->nPage); ++#ifdef SQLITE_META_DWR ++ MetaDwrCheckVacuum(pBt); ++#endif + } + }else{ + rc = SQLITE_DONE; +@@ -72980,6 +73035,9 @@ static int autoVacuumCommit(Btree *p){ + put4byte(&pBt->pPage1->aData[28], nFin); + pBt->bDoTruncate = 1; + pBt->nPage = nFin; ++#ifdef SQLITE_META_DWR ++ MetaDwrCheckVacuum(pBt); ++#endif + } + if( rc!=SQLITE_OK ){ + sqlite3PagerRollback(pPager); +@@ -73036,6 +73094,9 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){ + if( pBt->bDoTruncate ){ + sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage); + } ++#endif ++#ifdef SQLITE_META_DWR ++ (void)MetaDwrUpdateMetaPages(p); + #endif + rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zSuperJrnl, 0); + sqlite3BtreeLeave(p); +@@ -78937,6 +78998,11 @@ SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ + assert( iMeta==0 || iMeta==1 ); + pBt->incrVacuum = (u8)iMeta; + } ++#endif ++#ifdef SQLITE_META_DWR ++ if (idx == 1 && pBt->pPager->metaFd) { ++ pBt->pPager->metaChanged = META_SCHEMA_CHANGED; ++ } + #endif + } + sqlite3BtreeLeave(p); +@@ -79307,7 +79373,6 @@ static int checkTreePage( + "unable to get the page. error code=%d", rc); + goto end_of_check; + } +- + /* Clear MemPage.isInit to make sure the corruption detection code in + ** btreeInitPage() is executed. */ + savedIsInit = pPage->isInit; +@@ -80514,6 +80579,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ + } + } + } ++ + if( rc==SQLITE_OK ){ + rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1); + } +@@ -80546,7 +80612,12 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ + sqlite3PagerTruncateImage(pDestPager, nDestTruncate); + rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0); + } +- ++ #ifdef SQLITE_META_DWR ++ if (rc == SQLITE_OK && p->pDest->pBt->pPager->metaFd) { ++ p->pDest->pBt->pPager->metaChanged = META_SCHEMA_CHANGED; ++ (void)MetaDwrUpdateMetaPages(p->pDest); ++ } ++ #endif + /* Finish committing the transaction to the destination database. */ + if( SQLITE_OK==rc + && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0)) +@@ -134955,8 +135026,14 @@ SQLITE_PRIVATE void sqlite3Pragma( + /* sqlite3CodecPragma executes internal */ + goto pragma_out; + } +-#endif /* SQLITE_HAS_CODEC */ +- ++#endif ++/* END CODEC */ ++#ifdef SQLITE_META_DWR ++ if(PragmaMetaDoubleWrie(db, iDb, pParse, zLeft, zRight)) { ++ /* PragmaMetaDoubleWrie executes internal */ ++ goto pragma_out; ++ } ++#endif + /* Locate the pragma in the lookup table */ + pPragma = pragmaLocate(zLeft); + if( pPragma==0 ){ +@@ -149391,7 +149468,6 @@ static void updateVirtualTable( + } + } + +- + if( eOnePass==ONEPASS_OFF ){ + /* End the virtual table scan */ + if( pSrc->nSrc==1 ){ +@@ -175302,6 +175378,10 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){ + zErr = "no more rows available"; + break; + } ++ case SQLITE_META_RECOVERED: { ++ zErr = "warning meta recover message"; ++ break; ++ } + default: { + rc &= 0xff; + if( ALWAYS(rc>=0) && rccheckFileId) { ++ unixFile *fd = (unixFile *)pPager->fd; ++ if (fd == NULL || fd->pInode == NULL || pPager->pVfs == NULL) { ++ return SQLITE_INTERNAL; ++ } ++ if (fd->pInode->fileId.ino != hdr->dbFileInode) { ++ sqlite3_log(SQLITE_IOERR_DATA, "Ino mismatch file %llu dwr file %llu", ++ fd->pInode->fileId.ino, hdr->dbFileInode); ++ return SQLITE_IOERR_DATA; ++ } ++ } ++#endif ++ if (hdr->pageCnt > META_DWR_MAX_PAGES || hdr->version != META_DWR_VERSION || ++ hdr->magic != META_DWR_MAGIC || hdr->checkSum != META_DWR_MAGIC) { ++ sqlite3_log(SQLITE_IOERR_DATA, "Meta dwr file check wrong pageCnt %u, version %u, magic %u, checkSum %u", ++ hdr->pageCnt, hdr->version, hdr->magic, hdr->checkSum); ++ return SQLITE_IOERR_DATA; ++ } ++ if (hdr->pageSz != pPager->pageSize) { ++ sqlite3_log(SQLITE_IOERR_DATA, "Meta dwr file check wrong pageSz %u-%u", hdr->pageSz, pPager->pageSize); ++ return SQLITE_IOERR_DATA; ++ } ++ return SQLITE_OK; ++} ++ ++static int PragmaMetaDoubleWrie(sqlite3 *db, int iDb, Parse *parse, const char *zLeft, const char *zRight) { ++ Btree *pBt = db->aDb[iDb].pBt; ++ if (pBt == NULL || zLeft == NULL || sqlite3StrICmp(zLeft, "meta_double_write") != 0) { ++ return 0; ++ } ++ Pager *pPager = pBt->pBt->pPager; ++ if (pPager == NULL) { ++ sqlite3_log(SQLITE_WARNING_DUMP, "Invalid pager handle"); ++ return 1; ++ } ++ if (zRight == NULL) { ++ Vdbe *v = sqlite3GetVdbe(parse); ++ sqlite3VdbeSetNumCols(v, 1); ++ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "meta_double_write", SQLITE_STATIC); ++ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, pPager->metaFd ? "enabled" : "disabled", 0); ++ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); ++ } else if (strncmp(zRight, "enabled", 7) == 0) { ++ sqlite3_mutex_enter(db->mutex); ++ // only support enabled meta double write ++ int rc = MetaDwrOpenAndCheck(pBt); ++ if (rc != SQLITE_OK) { ++ parse->nErr++; ++ parse->rc = rc; ++ } ++ sqlite3_mutex_leave(db->mutex); ++ } else if (strncmp(zRight, "disabled", 8) == 0) { ++ sqlite3_mutex_enter(db->mutex); ++ MetaDwrDisable(pBt); ++ sqlite3_mutex_leave(db->mutex); ++ } ++ return 1; ++} ++ ++static int GetBtreePageNo(MemPage *pPage, void *args) { ++ ScanPages *pInfo = (ScanPages *)args; ++ // realloc buffer to store pages ++ u32 pageCnt = pInfo->pageCnt; ++ if (pageCnt == pInfo->pageBufSize) { ++ u32 memSz = sizeof(Pgno) * ROUND8(pageCnt + 1); ++ Pgno *pages = sqlite3Malloc(memSz); ++ if (pages == NULL) { ++ sqlite3_log(SQLITE_NOMEM, "GetPages alloc buffer go wrong %u", memSz); ++ return SQLITE_NOMEM; ++ } ++ if (pageCnt != 0) { ++ memcpy(pages, pInfo->pages, pageCnt * sizeof(Pgno)); ++ } ++ sqlite3_free(pInfo->pages); ++ pInfo->pageBufSize = ROUND8(pageCnt + 1); ++ pInfo->pages = pages; ++ } ++ pInfo->pages[pageCnt] = pPage->pgno; ++ pInfo->pageCnt++; ++ if (pInfo->maxPageNo < pPage->pgno) { ++ pInfo->maxPageNo = pPage->pgno; ++ } ++ return 0; ++} ++ ++typedef int (*ScanFn)(MemPage *pPage, void *args); ++static SQLITE_NOINLINE int ScanOverflowPages( ++ MemPage *pPage, /* The page that contains the Cell */ ++ unsigned char *pCell, /* First byte of the Cell */ ++ CellInfo *pInfo, /* Size information about the cell */ ++ ScanFn fn, /* Scan pages function */ ++ void *args) { ++ BtShared *pBt; ++ Pgno ovflPgno; ++ int rc; ++ int nOvfl; ++ u32 ovflPageSize; ++ ++ if (pCell + pInfo->nSize > pPage->aDataEnd) { ++ /* Cell extends past end of page */ ++ return SQLITE_CORRUPT_BKPT; ++ } ++ ovflPgno = get4byte(pCell + pInfo->nSize - 4); ++ pBt = pPage->pBt; ++ assert(pBt->usableSize > 4); ++ ovflPageSize = pBt->usableSize - 4; ++ nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1) / ovflPageSize; ++ assert(nOvfl > 0 || ++ (CORRUPT_DB && (pInfo->nPayload + ovflPageSize) < ovflPageSize)); ++ while (nOvfl > 0) { ++ nOvfl--; ++ Pgno iNext = 0; ++ MemPage *pOvfl = 0; ++ if (ovflPgno < 2 || ovflPgno > btreePagecount(pBt)) { ++ sqlite3_log(SQLITE_WARNING_DUMP, "Ignore for ovfl page not as expect, pgno %u ovflPgno %u novfl %d payload %u local %u", ++ pPage->pgno, ovflPgno, nOvfl, pInfo->nPayload, pInfo->nLocal); ++ return SQLITE_MISUSE; ++ } ++ rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext); ++ if (rc) ++ return rc; ++ if (pOvfl) { ++ rc = fn(pOvfl, args); ++ if (rc) { ++ return rc; ++ } ++ sqlite3PagerUnref(pOvfl->pDbPage); ++ } ++ ovflPgno = iNext; ++ } ++ return SQLITE_OK; ++} ++ ++static int ScanBtreePage( ++ BtShared *pBt, /* The BTree that contains the table */ ++ Pgno pgno, /* Page number to clear */ ++ ScanFn fn, /* Scan pages function */ ++ void *args) { /* Scan pages args */ ++ MemPage *pPage; ++ int rc; ++ unsigned char *pCell; ++ int i; ++ int hdr; ++ CellInfo info; ++ ++ assert(sqlite3_mutex_held(pBt->mutex)); ++ if (pgno > btreePagecount(pBt)) { ++ return SQLITE_OK; ++ } ++ rc = getAndInitPage(pBt, pgno, &pPage, 0, 0); ++ if (rc) { ++ return rc; ++ } ++ rc = fn(pPage, args); ++ if (rc) { ++ goto SCAN_PAGE_OUT; ++ } ++ hdr = pPage->hdrOffset; ++ for (i = pPage->nCell - 1; i >= 0; i--) { ++ pCell = findCell(pPage, i); ++ if (!pPage->leaf) { ++ rc = ScanBtreePage(pBt, get4byte(pCell), fn, args); ++ if (rc) { ++ goto SCAN_PAGE_OUT; ++ } ++ } ++ pPage->xParseCell(pPage, pCell, &info); ++ if (info.nLocal < info.nPayload) { ++ rc = ScanOverflowPages(pPage, pCell, &info, fn, args); ++ if (rc) { ++ goto SCAN_PAGE_OUT; ++ } ++ } ++ } ++ if (!pPage->leaf) { ++ rc = ScanBtreePage(pBt, get4byte(&pPage->aData[hdr + 8]), fn, args); ++ if (rc) { ++ goto SCAN_PAGE_OUT; ++ } ++ } ++SCAN_PAGE_OUT: ++ releasePage(pPage); ++ return rc; ++} ++ ++static inline int ScanMetaPages(Btree *pBt, ScanPages *pages) { ++ return ScanBtreePage(pBt->pBt, 1, GetBtreePageNo, pages); ++} ++ ++static int ReleaseMetaPages(ScanPages *pages) { ++ sqlite3_free(pages->pages); ++ pages->pages = NULL; ++ return SQLITE_OK; ++} ++ ++static void InitMetaHeader(MetaDwrHdr *hdr) { ++ (void)memset(hdr, 0, META_VERIFIED_HDR_LEN); ++ hdr->magic = META_DWR_MAGIC; ++ hdr->version = META_DWR_VERSION; ++ hdr->checkSum = META_DWR_MAGIC; ++} ++ ++static void MetaDwrReleaseHdr(MetaDwrHdr *hdr) { ++ if (!hdr) { ++ return; ++ } ++ sqlite3_free(hdr->zones); ++ sqlite3_free(hdr); ++} ++ ++static int ExpandMetaPageBuf(MetaDwrHdr *hdr, u32 minimalPageCnt, u32 bufHasData) { ++ if (minimalPageCnt < hdr->pageBufSize && hdr->zones != NULL) { ++ return SQLITE_OK; ++ } ++ int pageBufSz = ROUND8(MAX(hdr->pageCnt, minimalPageCnt)); ++ u8 *zones = (u8 *)sqlite3Malloc(pageBufSz * (sizeof(u8) + sizeof(Pgno))); ++ if (zones == NULL) { ++ return SQLITE_NOMEM_BKPT; ++ } ++ Pgno *pgnos = (Pgno *)(zones + pageBufSz); ++ if (hdr->zones != NULL) { ++ if (bufHasData && hdr->pageCnt > 0) { ++ (void)memcpy(zones, hdr->zones, hdr->pageCnt * sizeof(u8)); ++ (void)memcpy(pgnos, hdr->pages, hdr->pageCnt * sizeof(Pgno)); ++ } ++ sqlite3_free(hdr->zones); ++ } ++ hdr->pageBufSize = pageBufSz; ++ hdr->zones = zones; ++ hdr->pages = pgnos; ++ return SQLITE_OK; ++} ++ ++static MetaDwrHdr *AllocInitMetaHeaderDwr(Pager *pPager) { ++ MetaDwrHdr *hdr = sqlite3MallocZero(sizeof(MetaDwrHdr)); ++ if (hdr == NULL) { ++ return NULL; ++ } ++ InitMetaHeader(hdr); ++ int rc = ExpandMetaPageBuf(hdr, META_DWR_HEADER_DEFAULT_PAGE_CNT, 0); ++ if (rc != SQLITE_OK) { ++ MetaDwrReleaseHdr(hdr); ++ return NULL; ++ } ++ hdr->checkFileId = (pPager->pVfs != NULL && sqlite3_stricmp(pPager->pVfs->zName, "unix") == 0); ++ return hdr; ++} ++ ++static void MetaDwrCloseFile(Pager *pPager) { ++ if (!pPager->metaFd) { ++ return; ++ } ++#if SQLITE_OS_UNIX ++ if (pPager->metaMapPage) { ++ osMunmap(pPager->metaMapPage, META_DWR_HEADER_PAGE_SIZE); ++ pPager->metaMapPage = NULL; ++ } ++#endif ++ if (pPager->metaHdr && pPager->metaHdr->needSync > 0) { ++ (void)sqlite3OsSync(pPager->metaFd, SQLITE_SYNC_NORMAL); ++ } ++ sqlite3OsClose(pPager->metaFd); ++} ++ ++static void MetaDwrPagerRelease(Pager *pPager) { ++ MetaDwrCloseFile(pPager); ++ MetaDwrReleaseHdr(pPager->metaHdr); ++ pPager->metaHdr = NULL; ++ if (pPager->metaFd) { ++ sqlite3_free(pPager->metaFd); ++ pPager->metaFd = NULL; ++ } ++} ++ ++static inline int ReadFromHdrPage(Pager *pPager, void *data, int amt, i64 offset) { ++ if (pPager->metaMapPage) { ++ (void)memcpy(data, (u8 *)pPager->metaMapPage + offset, amt); ++ return SQLITE_OK; ++ } ++ return sqlite3OsRead(pPager->metaFd, data, amt, offset); ++} ++ ++static int MetaDwrReadHeader(Pager *pPager, MetaDwrHdr *hdr) { ++ i64 sz = 0; ++ int rc = sqlite3OsFileSize(pPager->metaFd, &sz); ++ if (rc != SQLITE_OK) { ++ sqlite3_log(rc, "Meta dwr file size go wrong"); ++ return rc; ++ } ++ if (sz <= META_DWR_HEADER_PAGE_SIZE) { ++ rc = SQLITE_IOERR_DATA; ++ goto READ_META_OUT; ++ } ++ rc = ReadFromHdrPage(pPager, hdr, META_VERIFIED_HDR_LEN, 0); ++ if (rc != SQLITE_OK) { ++ sqlite3_log(rc, "Meta dwr file header read wrong"); ++ goto READ_META_OUT; ++ } ++ rc = MetaDwrHeaderSimpleCheck(pPager, hdr); ++ if (rc != SQLITE_OK) { ++ goto READ_META_OUT; ++ } ++ // avoid realloc buffer if buf can't hold all pages ++ rc = ExpandMetaPageBuf(hdr, hdr->pageCnt, 0); ++ if (rc != SQLITE_OK) { ++ goto READ_META_OUT; ++ } ++ int zoneSize = hdr->pageCnt * sizeof(u8); ++ rc = ReadFromHdrPage(pPager, hdr->zones, zoneSize, META_VERIFIED_HDR_LEN); ++ if (rc != SQLITE_OK) { ++ goto READ_META_OUT; ++ } ++ rc = ReadFromHdrPage(pPager, hdr->pages, hdr->pageCnt * sizeof(Pgno), META_PAGE_NO_OFFSET); ++ if (rc != SQLITE_OK) { ++ goto READ_META_OUT; ++ } ++ for (u32 i = 0; i < hdr->pageCnt; i++) { ++ u8 zoneIdx = hdr->zones[i]; ++ if (zoneIdx != 0 && zoneIdx != 1 && zoneIdx != META_DWR_INVALID_ZONE) { ++ sqlite3_log(SQLITE_IOERR_DATA, "Invalid zoneIdx %d", zoneIdx); ++ rc = SQLITE_IOERR_DATA; ++ break; ++ } ++ } ++READ_META_OUT: ++ if (rc == SQLITE_IOERR_DATA) { ++ InitMetaHeader(hdr); ++ rc = SQLITE_OK; ++ } ++ return rc; ++} ++ ++static inline u64 CaculateMetaDwrWriteOffset(int pageSz, u32 idx, u8 zone) { ++ // 1 header page, idx correspond 2 zone pages ++ return META_DWR_HEADER_PAGE_SIZE + pageSz * (idx * 2 + zone); ++} ++ ++static void MetaDwrUpdateHeaderDbInfo(BtShared *pBt) { ++ MetaDwrHdr *hdr = pBt->pPager->metaHdr; ++ // 28 offset: dbSize, freelist pageNo, freelist pages count, schema cookie ++ const u8 *dbHdrInfo = &pBt->pPage1->aData[28]; ++ hdr->dbSize = sqlite3Get4byte(dbHdrInfo); ++#ifndef SQLITE_OMIT_WAL ++ if (pagerUseWal(pBt->pPager)) { ++ WalIndexHdr *pWalHdr = &pBt->pPager->pWal->hdr; ++ if (pWalHdr->isInit) { ++ hdr->mxFrameInWal = pWalHdr->mxFrame; ++ hdr->dbSize = pWalHdr->nPage; ++ } ++ } else { ++ hdr->mxFrameInWal = 0; ++ } ++#endif ++#if SQLITE_OS_UNIX ++ if (hdr->checkFileId) { ++ unixFile *fd = (unixFile *)pBt->pPager->fd; ++ if (fd == NULL || fd->pInode == NULL) { ++ sqlite3_log(SQLITE_WARNING_DUMP, "update meta header invalid fd"); ++ hdr->hdrValid = 0; ++ return; ++ } ++ hdr->dbFileInode = fd->pInode->fileId.ino; ++ } ++#endif ++ hdr->freeListPageNo = sqlite3Get4byte(dbHdrInfo + 4); ++ hdr->freeListPageCnt = sqlite3Get4byte(dbHdrInfo + 8); ++ hdr->schemaCookie = sqlite3Get4byte(dbHdrInfo + 12); ++ hdr->hdrValid = 1; ++} ++ ++static inline int WriteToHdrPage(Pager *pPager, const void *data, int amt, i64 offset) { ++ if (pPager->metaMapPage) { ++ (void)memcpy((u8 *)pPager->metaMapPage + offset, data, amt); ++ return SQLITE_OK; ++ } ++ return sqlite3OsWrite(pPager->metaFd, data, amt, offset); ++} ++ ++static int MetaDwrWriteHeader(Pager *pPager, MetaDwrHdr *hdr) { ++ if (pPager->metaChanged == 0 || hdr == NULL || hdr->pageCnt == 0 || hdr->hdrValid == 0) { ++ return SQLITE_OK; ++ } ++ hdr->hdrValid = 0; ++ hdr->pageSz = pPager->pageSize; ++ hdr->dbSize = pPager->dbSize; ++ int rc = WriteToHdrPage(pPager, hdr, META_VERIFIED_HDR_LEN, 0); ++ if (rc != SQLITE_OK) { ++ sqlite3_log(rc, "update meta header write hdr %u wrong", META_VERIFIED_HDR_LEN); ++ return rc; ++ } ++ if (hdr->zones) { ++ int zoneSize = hdr->pageCnt * sizeof(u8); ++ rc = WriteToHdrPage(pPager, hdr->zones, zoneSize, META_VERIFIED_HDR_LEN); ++ if (rc != SQLITE_OK) { ++ sqlite3_log(rc, "update meta header write zonebuf %u wrong", zoneSize); ++ return rc; ++ } ++ } ++ if (hdr->pages) { ++ int pageBufSz = hdr->pageCnt * sizeof(Pgno); ++ rc = WriteToHdrPage(pPager, hdr->pages, pageBufSz, META_PAGE_NO_OFFSET); ++ if (rc != SQLITE_OK) { ++ sqlite3_log(rc, "update meta header write pagebuf %u wrong", pageBufSz); ++ } ++ } ++ if (rc == SQLITE_OK) { ++ u64 size = CaculateMetaDwrWriteOffset((int)pPager->pageSize, hdr->pageCnt, 0); ++ rc = sqlite3OsTruncate(pPager->metaFd, size); ++ if (rc != SQLITE_OK) { ++ sqlite3_log(rc, "update meta header truncate filesz %lu wrong", size); ++ } ++ i64 timeMs = 0; ++ sqlite3OsCurrentTimeInt64(pPager->pVfs, &timeMs); ++ if ((timeMs - hdr->lastSyncTime) > META_FILE_SYNC_TIMEOUT_MS || ++ hdr->needSync >= META_FILE_UPDATE_TIMES_PER_SYNC) { ++ rc = sqlite3OsSync(pPager->metaFd, SQLITE_SYNC_NORMAL); ++ if (rc != SQLITE_OK) { ++ sqlite3_log(rc, "update meta header sync filesz %lu wrong", size); ++ } ++ hdr->lastSyncTime = timeMs; ++ hdr->needSync = 0; ++ } else { ++ hdr->needSync++; ++ } ++ } ++ return rc; ++} ++ ++static int MetaDwrFindPageIdx(MetaDwrHdr *hdr, u32 pgno, u32 *idx) { ++ for (u32 i = 0; i < hdr->pageCnt && i < META_DWR_MAX_PAGES; i++) { ++ if (pgno == hdr->pages[i]) { ++ *idx = i; ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++static int MetaDwrWriteOnePage(Btree *pBt, PgHdr *pPage, MetaDwrHdr *hdr, u8 curZones, u32 idx) { ++ int rc = SQLITE_OK; ++ u8 pageExpand = 0; ++ if (hdr->pageCnt <= idx) { ++ rc = ExpandMetaPageBuf(hdr, idx + 1, 1); ++ if (rc != SQLITE_OK) { ++ return rc; ++ } ++ pageExpand = 1; ++ } ++ Pager *pPager = pBt->pBt->pPager; ++ // asume zone 0 or 1 ++ u8 zone = 1 - curZones; ++ int pageSz = sqlite3BtreeGetPageSize(pBt); ++ u64 ofs = CaculateMetaDwrWriteOffset(pageSz, idx, zone); ++ void *pData; ++#if defined(SQLITE_HAS_CODEC) ++ if ((pData = sqlite3PagerCodec(pPage)) == 0) ++ return SQLITE_NOMEM; ++#else ++ pData = pPage->pData; ++#endif ++ rc = sqlite3OsWrite(pPager->metaFd, pData, pageSz, ofs); ++ if (rc != SQLITE_OK) { ++ return rc; ++ } ++ hdr->zones[idx] = zone; ++ hdr->pages[idx] = pPage->pgno; ++ if (pageExpand) { ++ hdr->pageCnt++; ++ } ++ return SQLITE_OK; ++} ++ ++static int MetaDwrRestoreAllPages(Btree *pBt, const ScanPages *metaPages, MetaDwrHdr *hdr) { ++ u32 i = 0; ++ PgHdr *p = NULL; ++ int rc = SQLITE_OK; ++ for (i = 0; i < metaPages->pageCnt && i < META_DWR_MAX_PAGES; i++) { ++ Pgno pgno = metaPages->pages[i]; ++ if (pgno > btreePagecount(pBt->pBt)) { ++ sqlite3_log(SQLITE_WARNING_DUMP, "pageno %d overlimit", pgno); ++ return SQLITE_CORRUPT_BKPT; ++ } ++ rc = sqlite3PagerGet(pBt->pBt->pPager, pgno, &p, 0); ++ if (rc) { ++ return rc; ++ } ++ rc = MetaDwrWriteOnePage(pBt, p, hdr, 1, i); ++ sqlite3PagerUnref(p); ++ if (rc) { ++ return rc; ++ } ++ } ++ hdr->pageCnt = metaPages->pageCnt; ++ MetaDwrUpdateHeaderDbInfo(pBt->pBt); ++ return rc; ++} ++ ++static inline const char *GetMetaFilePath(Pager *pPager) ++{ ++ return pPager->metaFd == NULL ? NULL : ((const char *)pPager->metaFd + ROUND8(pPager->pVfs->szOsFile)); ++} ++ ++static int MetaDwrOpenFile(Pager *pPager, u8 openCreate) { ++ if (pPager->metaFd || pPager->zFilename == NULL) { ++ return SQLITE_OK; ++ } ++ sqlite3BeginBenignMalloc(); ++ sqlite3_vfs *pVfs = pPager->pVfs; ++ int size = strlen(pPager->zFilename) + sizeof("-dwr"); ++ int szOsFile = ROUND8(pVfs->szOsFile); ++ sqlite3_file *metaFd = (sqlite3_file *)sqlite3MallocZero(szOsFile + size); ++ char *metaPath = (char *)metaFd + szOsFile; ++ if (metaFd == NULL) { ++ sqlite3EndBenignMalloc(); ++ sqlite3_log(SQLITE_NOMEM_BKPT, "sqlite alloc memsize %d go wrong", szOsFile + size); ++ return SQLITE_NOMEM_BKPT; ++ } ++ sqlite3_snprintf(size, metaPath, "%s-dwr", pPager->zFilename); ++ int exists = 0; ++ int rc = sqlite3OsAccess(pVfs, metaPath, SQLITE_ACCESS_EXISTS, &exists); ++ if (rc != SQLITE_OK) { ++ goto INIT_META_OUT; ++ } ++ if (!exists && !openCreate) { ++ sqlite3_free(metaFd); ++ goto INIT_META_OUT; ++ } ++ u32 flags = (SQLITE_OPEN_READWRITE | SQLITE_OPEN_SUPER_JOURNAL); ++ if (openCreate) { ++ flags |= SQLITE_OPEN_CREATE; ++ } ++ rc = sqlite3OsOpen(pVfs, metaPath, metaFd, (int)flags, 0); ++ if (rc != SQLITE_OK) { ++ goto INIT_META_OUT; ++ } ++#if SQLITE_OS_UNIX ++ if (pPager->metaMapPage == NULL) { ++ sqlite3_int64 sz = META_DWR_HEADER_PAGE_SIZE; ++ sqlite3OsFileControlHint(metaFd, SQLITE_FCNTL_CHUNK_SIZE, &sz); ++ sqlite3OsFileControlHint(metaFd, SQLITE_FCNTL_SIZE_HINT, &sz); ++ void *page = osMmap(0, META_DWR_HEADER_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, ++ ((unixFile *)metaFd)->h, 0); ++ if (page != MAP_FAILED) { ++ pPager->metaMapPage = page; ++ } ++ } ++#endif ++ pPager->metaFd = metaFd; ++INIT_META_OUT: ++ sqlite3EndBenignMalloc(); ++ if (rc != SQLITE_OK && metaFd != NULL) { ++ sqlite3_free(metaFd); ++ } ++ return rc; ++} ++ ++void MetaDwrCheckVacuum(BtShared *pBt) { ++ if (!pBt || !pBt->pPager->metaFd) { ++ return; ++ } ++ if (pBt->nPage < pBt->maxMetaPage) { ++ pBt->pPager->metaChanged = META_SCHEMA_CHANGED; ++ } ++} ++ ++static inline u8 LocalMetaHdrValid(Pager *pPager) { ++ return pPager->metaMapPage != NULL && memcmp(pPager->metaMapPage, pPager->metaHdr, ++ META_VERIFIED_HDR_LEN) == 0; ++} ++ ++static int MetaDwrLoadHdr(Pager *pPager) { ++ if (!pPager->metaHdr) { ++ pPager->metaHdr = AllocInitMetaHeaderDwr(pPager); ++ if (pPager->metaHdr == NULL) { ++ return SQLITE_NOMEM_BKPT; ++ } ++ } ++ if (LocalMetaHdrValid(pPager)) { ++ return SQLITE_OK; ++ } ++ return MetaDwrReadHeader(pPager, pPager->metaHdr); ++} ++ ++static int MetaDwrLoadAndCheckMetaFile(BtShared *pBt, u8 reportErr) { ++ int rc = MetaDwrLoadHdr(pBt->pPager); ++ if (rc != SQLITE_OK) { ++ return rc; ++ } ++ MetaDwrHdr *hdr = pBt->pPager->metaHdr; ++ if (hdr->pageCnt == 0) { ++ return reportErr ? SQLITE_IOERR_DATA : SQLITE_OK; ++ } ++ // 28 offset: dbSize, freelist pageNo, freelist pages count, schema cookie ++ u8 *dbHdrInfo = &pBt->pPage1->aData[28]; ++ if (hdr->dbSize != pBt->pPager->dbSize || hdr->dbSize != sqlite3Get4byte(dbHdrInfo) || ++ hdr->freeListPageNo != sqlite3Get4byte(dbHdrInfo + 4) || ++ hdr->freeListPageCnt != sqlite3Get4byte(dbHdrInfo + 8) || ++ hdr->schemaCookie != sqlite3Get4byte(dbHdrInfo + 12)) { ++ sqlite3_log(SQLITE_IOERR_DATA, "Meta dwr file expect %u-%u-%u-%u-%u but gotton %u-%u-%u-%u-%u", ++ pBt->pPager->dbSize, hdr->dbSize, sqlite3Get4byte(dbHdrInfo), sqlite3Get4byte(dbHdrInfo + 4), ++ sqlite3Get4byte(dbHdrInfo + 8), sqlite3Get4byte(dbHdrInfo + 12), hdr->dbSize, hdr->freeListPageNo, ++ hdr->freeListPageCnt, hdr->schemaCookie); ++ // reinit ++ InitMetaHeader(hdr); ++ if (reportErr) { ++ return SQLITE_IOERR_DATA; ++ } ++ } ++ return SQLITE_OK; ++} ++ ++static int MetaDwrReadOnePage(Pager *pPager, MetaDwrHdr *hdr, int idx, u8 *pData) { ++ u64 ofs = CaculateMetaDwrWriteOffset(pPager->pageSize, idx, hdr->zones[idx]); ++ int rc = sqlite3OsRead(pPager->metaFd, pData, pPager->pageSize, ofs); ++ CODEC1(pPager, pData, hdr->pages[idx], 3, rc = SQLITE_NOMEM_BKPT); ++ return rc; ++} ++ ++static int MetaDwrRecoverHeadPage( ++ Pager *pPager, /* The pager open on the database file */ ++ Pgno pgno, /* Page number to fetch */ ++ DbPage **pDbPage, ++ int flag) { ++ if (pPager->metaFd == NULL) { ++ return pgno == 1 ? SQLITE_NOTADB : SQLITE_CORRUPT; ++ } ++ sqlite3_pcache_page *pCachePage = sqlite3PcacheFetch(pPager->pPCache, pgno, 3); ++ if (pCachePage == NULL) { ++ sqlite3_log(SQLITE_NOMEM_BKPT, "Get meta page wrong %d", pgno); ++ return SQLITE_NOMEM_BKPT; ++ } ++ DbPage *pPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pCachePage); ++ pPage->pPager = pPager; ++ assert(pCachePage != 0); ++ int rc = MetaDwrLoadHdr(pPager); ++ if (rc != SQLITE_OK) { ++ goto RELEASE_OUT; ++ } ++ MetaDwrHdr *hdr = pPager->metaHdr; ++ u8 walChecked = 0; ++#ifndef SQLITE_OMIT_WAL ++ if (pagerUseWal(pPager)) { ++ WalIndexHdr *pWalHdr = &pPager->pWal->hdr; ++ if (pWalHdr->isInit && pWalHdr->mxFrame != 0) { ++ if (hdr->mxFrameInWal != pWalHdr->mxFrame || hdr->dbSize != pWalHdr->nPage) { ++ rc = SQLITE_NOTADB; ++ sqlite3_log(SQLITE_WARNING_DUMP, "Meta dwr wal hdr expect %u-%u but gotten %u-%u", ++ hdr->mxFrameInWal, hdr->dbSize, pWalHdr->mxFrame, pWalHdr->nPage); ++ goto RELEASE_OUT; ++ } else { ++ walChecked = 1; ++ } ++ } ++ } ++ if (walChecked == 0) { ++ i64 size = 0; ++ rc = sqlite3OsFileSize(pPager->fd, &size); ++ if (rc != SQLITE_OK) { ++ rc = SQLITE_NOTADB; ++ sqlite3_log(SQLITE_WARNING_DUMP, "Meta dwr get db file size go wrong"); ++ goto RELEASE_OUT; ++ } ++ i64 expectSz = (i64)hdr->dbSize * (i64)hdr->pageSz; ++ if (size != expectSz) { ++ rc = SQLITE_NOTADB; ++ sqlite3_log(SQLITE_WARNING_DUMP, "Meta dwr expect file size %lu but gotten size %llu", ++ expectSz, size); ++ goto RELEASE_OUT; ++ } ++ } ++#endif ++ rc = SQLITE_NOTADB; ++ for (u32 i = 0; i < hdr->pageCnt; i++) { ++ if (hdr->pages[i] != pgno) { ++ continue; ++ } ++ rc = MetaDwrReadOnePage(pPager, hdr, i, sqlite3PagerGetData(pPage)); ++ if (rc == SQLITE_OK) { ++ *pDbPage = pPage; ++ if (pPage->pgno == 1) { ++ memcpy(&pPager->dbFileVers, &((u8 *)pPage->pData)[24], sizeof(pPager->dbFileVers)); ++ } ++ pager_set_pagehash(pPage); ++ } ++ break; ++ } ++RELEASE_OUT: ++ if (rc != SQLITE_OK && pPage != NULL) { ++ sqlite3PcacheDrop(pPage); ++ } ++ return rc; ++} ++ ++static int MetaDwrRestoreChangedPages(Btree *pBt) { ++ Pager *pPager = pBt->pBt->pPager; ++ MetaDwrHdr *hdr = pPager->metaHdr; ++ u8 *zones = sqlite3MallocZero(hdr->pageBufSize * sizeof(u8)); ++ if (zones == NULL) { ++ sqlite3_log(SQLITE_NOMEM_BKPT, "Alloc zones buffer size %u go wrong", hdr->pageBufSize * sizeof(u8)); ++ return SQLITE_NOMEM_BKPT; ++ } ++ if (hdr->pageCnt > 0) { ++ memcpy(zones, hdr->zones, hdr->pageCnt * sizeof(u8)); ++ } ++ u32 idx = 0; ++ PgHdr *p = 0; ++ PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache); ++ int rc = SQLITE_OK; ++ for (p = pList; p; p = p->pDirty) { ++ if (MetaDwrFindPageIdx(hdr, p->pgno, &idx) == 0) { ++ continue; ++ } ++ rc = MetaDwrWriteOnePage(pBt, p, hdr, zones[idx], idx); ++ if (rc != SQLITE_OK) { ++ break; ++ } ++ } ++ if (rc == SQLITE_OK) { ++ MetaDwrUpdateHeaderDbInfo(pBt->pBt); ++ } ++ sqlite3_free(zones); ++ return rc; ++} ++ ++static int MetaDwrUpdateMetaPages(Btree *pBt) { ++ Pager *pPager = pBt->pBt->pPager; ++ if (!pPager || !pPager->metaFd || pPager->memDb || pPager->readOnly || pBt->pBt->pPage1 == NULL) { ++ return SQLITE_OK; ++ } ++ if (pPager->metaChanged == 0) { ++ if ((pBt->pBt->pPage1->pDbPage->flags & PGHDR_DIRTY) == 0) { ++ return SQLITE_OK; ++ } ++ pPager->metaChanged = META_HEADER_CHANGED; ++ } ++ sqlite3BeginBenignMalloc(); ++ int rc = MetaDwrLoadHdr(pPager); ++ if (rc != SQLITE_OK) { ++ goto UPDATE_OUT; ++ } ++ // only update header page ++ if (pPager->metaChanged == META_HEADER_CHANGED) { ++ rc = MetaDwrRestoreChangedPages(pBt); ++ goto UPDATE_OUT; ++ } ++ // update schema pages ++ ScanPages metaPages = {0}; ++ rc = ScanMetaPages(pBt, &metaPages); ++ if (rc != SQLITE_OK) { ++ goto UPDATE_OUT; ++ } ++ MetaDwrHdr *hdr = pPager->metaHdr; ++ // rewrite ++ if (hdr->pageCnt == 0 || hdr->pageCnt != metaPages.pageCnt || pBt->pBt->nPage > pBt->pBt->maxMetaPage || ++ memcmp(hdr->pages, metaPages.pages, hdr->pageCnt * sizeof(Pgno))) { ++ // if page numbers unorderred, restore all pages ++ rc = MetaDwrRestoreAllPages(pBt, &metaPages, hdr); ++ } else { ++ rc = MetaDwrRestoreChangedPages(pBt); ++ } ++ if (rc == SQLITE_OK) { ++ pBt->pBt->maxMetaPage = metaPages.maxPageNo; ++ } ++ ReleaseMetaPages(&metaPages); ++UPDATE_OUT: ++ sqlite3EndBenignMalloc(); ++ return rc; ++} ++ ++static int MetaDwrRecoverSinglePage(Btree *pBt, int pgno, u8 *pData) { ++ if (pgno < 1 || pBt == NULL) { ++ return SQLITE_CORRUPT_BKPT; ++ } ++ Pager *pPager = sqlite3BtreePager(pBt); ++ DbPage *pDbPage = NULL; ++ int rc = sqlite3PagerGet(pPager, pgno, &pDbPage, 0); ++ if (rc) { ++ return rc; ++ } ++ if ((rc = sqlite3PagerWrite(pDbPage)) == SQLITE_OK) { ++ memcpy(sqlite3PagerGetData(pDbPage), pData, pPager->pageSize); ++ } else { ++ sqlite3_log(rc, "Dwr recoverwrite meta page %d failed", pgno); ++ } ++ sqlite3PagerUnref(pDbPage); ++ return rc; ++} ++ ++static int MetaDwrCheckMeta(Btree *pBt) { ++ int nErr = 0; ++ Pgno aRoot[2] = {0, 1}; // quick check and only check root btree ++ char *errStr = sqlite3BtreeIntegrityCheck(pBt->db, pBt, &aRoot[0], 2, SQLITE_INTEGRITY_CHECK_ERROR_MAX, ++ &nErr); ++ if (nErr == 0) { ++ assert(errStr == 0); ++ return SQLITE_OK; ++ } ++ if (errStr == 0) { ++ sqlite3_log(SQLITE_NOMEM, "Meta integrity check no mem"); ++ return SQLITE_NOMEM; ++ } ++ sqlite3_log(SQLITE_WARNING_DUMP, "Meta integrity check %s", errStr); ++ sqlite3DbFree(pBt->db, errStr); ++ return SQLITE_CORRUPT; ++} ++ ++static int MetaDwrBeginTrans(Btree *pBt, int wrflag) { ++ pBt->pBt->btsFlags &= ~BTS_READ_ONLY; ++ Pager *pPager = pBt->pBt->pPager; ++ void *xGetMethod = pPager->xGet; ++ pPager->xGetMethod = MetaDwrRecoverHeadPage; ++ pPager->xGet = MetaDwrRecoverHeadPage; ++ int rc = sqlite3BtreeBeginTrans(pBt, wrflag, 0); ++ pPager->xGet = xGetMethod; ++ pPager->xGetMethod = 0; ++ if (rc == SQLITE_OK) { ++ sqlite3PagerWrite(pBt->pBt->pPage1->pDbPage); ++ sqlite3_log(rc, "sqlite fix meta header"); ++ } ++ return rc; ++} ++ ++static int MetaDwrRecoverAndBeginTran(Btree *pBt, int wrflag, int *pSchemaVersion) ++{ ++ Pager *pPager = pBt->pBt->pPager; ++ assert(sqlite3_mutex_held(pBt->pBt->mutex)); ++ if (!pPager->metaFd || pBt->pBt->metaRecoverStatus || pPager->readOnly || pPager->memDb) { ++ return SQLITE_NOTADB; ++ } ++ int rc = MetaDwrLoadHdr(pPager); ++ if (rc != SQLITE_OK) { ++ sqlite3_log(rc, "MetaDwr load header failed"); ++ return rc; ++ } ++ pBt->pBt->metaRecoverStatus = META_IN_RECOVERY; ++ rc = MetaDwrBeginTrans(pBt, 2); ++ if (rc != SQLITE_OK) { ++ return rc; ++ } ++ void *pData = NULL; ++ pPager->metaChanged = META_HEADER_CHANGED; ++ MetaDwrHdr *hdr = pPager->metaHdr; ++ sqlite3_log(SQLITE_WARNING_DUMP, "sqlite meta recover %u frames", hdr->pageCnt); ++ int szPage = sqlite3BtreeGetPageSize(pBt); ++ pData = sqlite3Malloc(szPage); ++ if (pData == NULL) { ++ rc = SQLITE_NOMEM; ++ sqlite3_log(rc, "Dwr malloc mem size %d failed", szPage); ++ goto DWR_RECOVER_OUT; ++ } ++ for (u32 i = 0; i < hdr->pageCnt; i++) { ++ rc = MetaDwrReadOnePage(pPager, hdr, i, pData); ++ if (rc != SQLITE_OK) { ++ sqlite3_log(rc, "Dwr read %d meta page failed ", i); ++ break; ++ } ++ rc = MetaDwrRecoverSinglePage(pBt, hdr->pages[i], pData); ++ if (rc != SQLITE_OK) { ++ sqlite3_log(rc, "Dwr recover %d meta page failed ", i); ++ break; ++ } ++ } ++DWR_RECOVER_OUT: ++ /* Close the transaction, if one was opened. */ ++ if (rc == SQLITE_OK) { ++ sqlite3BtreeCommit(pBt); ++ } else { ++ (void)sqlite3BtreeRollback(pBt, SQLITE_ABORT_ROLLBACK, 0); ++ } ++ if (rc == SQLITE_OK) { ++ rc = sqlite3BtreeBeginTrans(pBt, wrflag, pSchemaVersion); ++ } ++ if (rc == SQLITE_OK) { ++ pBt->pBt->metaRecoverStatus = META_RECOVER_SUCCESS; ++ } ++ if (pData) { ++ sqlite3_free(pData); ++ } ++ return rc; ++} ++ ++static int Sqlite3MetaDwrCheckRestore(Btree *pBt) { ++ Pager *pPager = pBt->pBt->pPager; ++ int rc = MetaDwrOpenFile(pPager, 1); ++ if (rc != SQLITE_OK) { ++ return rc; ++ } ++ ScanPages metaPages = {0}; ++ rc = ScanMetaPages(pBt, &metaPages); ++ if (rc != SQLITE_OK || metaPages.pageCnt == 0) { ++ goto CHK_RESTORE_OUT; ++ } ++ rc = MetaDwrLoadAndCheckMetaFile(pBt->pBt, 0); ++ if (rc != SQLITE_OK) { ++ goto CHK_RESTORE_OUT; ++ } ++ MetaDwrHdr *hdr = pPager->metaHdr; ++ if (hdr->pageCnt == 0 || hdr->pageCnt != metaPages.pageCnt || ++ memcmp(hdr->pages, metaPages.pages, hdr->pageCnt * sizeof(Pgno))) { ++ sqlite3_log(SQLITE_WARNING_DUMP, "sqlite meta restore all"); ++ rc = MetaDwrRestoreAllPages(pBt, &metaPages, hdr); ++ if (rc == SQLITE_OK) { ++ pPager->metaChanged = META_SCHEMA_CHANGED; ++ rc = MetaDwrWriteHeader(pPager, hdr); ++ pPager->metaChanged = 0; ++ } ++ } ++ if (rc == SQLITE_OK) { ++ pBt->pBt->maxMetaPage = metaPages.maxPageNo; ++ } ++CHK_RESTORE_OUT: ++ ReleaseMetaPages(&metaPages); ++ return rc; ++} ++ ++static inline u8 IsConnectionValidForCheck(Pager *pPager) ++{ ++#if SQLITE_OS_UNIX ++ unixFile *fd = (unixFile *)pPager->fd; ++ // unix and only one connection exist ++ if (fd == NULL || fd->pInode == NULL || pPager->pVfs == NULL || ++ sqlite3_stricmp(pPager->pVfs->zName, "unix") != 0 || fd->pInode->nRef != 1) { ++ return 0; ++ } ++ return 1; ++#else ++ return 0; ++#endif ++} ++ ++static int MetaDwrOpenAndCheck(Btree *pBt) ++{ ++ Pager *pPager = pBt->pBt->pPager; ++ if (pPager->memDb || pPager->readOnly || !IsConnectionValidForCheck(pPager)) { ++ return SQLITE_OK; ++ } ++#ifdef SQLITE_HAS_CODEC ++ // not support codec right now ++ if (pPager->xCodec) { ++ return SQLITE_OK; ++ } ++#endif ++ sqlite3BtreeEnter(pBt); ++ int rc = SQLITE_OK; ++ int openedTransaction = 0; ++ int tnxState = sqlite3BtreeTxnState(pBt); ++ if (tnxState == SQLITE_TXN_NONE) { ++ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); ++ if (rc != SQLITE_OK) { ++ goto DWR_OPEN_OUT; ++ } ++ openedTransaction = 1; ++ } ++ rc = MetaDwrCheckMeta(pBt); ++ if (rc == SQLITE_CORRUPT || rc == SQLITE_NOTADB) { ++ // keep txn status after recover ++ rc = MetaDwrRecoverAndBeginTran(pBt, tnxState == SQLITE_TXN_WRITE ? 1 : 0, 0); ++ goto DWR_OPEN_OUT; ++ } ++ rc = Sqlite3MetaDwrCheckRestore(pBt); ++DWR_OPEN_OUT: ++ if (rc == SQLITE_OK && pBt->pBt->metaRecoverStatus == META_RECOVER_SUCCESS) { ++ rc = MetaDwrCheckMeta(pBt); ++ if (rc == SQLITE_OK) { ++ rc = SQLITE_META_RECOVERED; ++ } ++ } ++ /* Close the transaction, if one was opened. */ ++ if (openedTransaction) { ++ sqlite3BtreeCommit(pBt); ++ } ++ sqlite3BtreeLeave(pBt); ++ return rc; ++} + ++static void MetaDwrDisable(Btree *pBt) ++{ ++ Pager *pPager = pBt->pBt->pPager; ++ if (pPager->metaFd == NULL || pPager->memDb || pPager->readOnly || !IsConnectionValidForCheck(pPager)) { ++ return; ++ } ++#ifdef SQLITE_HAS_CODEC ++ // not support codec right now ++ if (pPager->xCodec) { ++ return; ++ } ++#endif ++ sqlite3BtreeEnter(pBt); ++ MetaDwrCloseFile(pPager); ++ MetaDwrReleaseHdr(pPager->metaHdr); ++ pPager->metaHdr = NULL; ++ const char *metaPath = GetMetaFilePath(pPager); ++ if (metaPath != NULL) { ++ (void)osUnlink(metaPath); ++ } ++ if (pPager->metaFd) { ++ sqlite3_free(pPager->metaFd); ++ pPager->metaFd = NULL; ++ } ++ sqlite3BtreeLeave(pBt); ++} ++#endif + #if SQLITE_OS_UNIX + #include + #include +-- +2.47.0.windows.2 + diff --git a/patch/0004-add-icu.patch b/patch/0004-add-icu.patch new file mode 100644 index 0000000..869b40b --- /dev/null +++ b/patch/0004-add-icu.patch @@ -0,0 +1,2052 @@ +From f79d3bcfd2d24256413ed95f65a0be7d2c77a6e1 Mon Sep 17 00:00:00 2001 +From: wanghaishuo +Date: Sat, 12 Apr 2025 10:09:45 +0800 +Subject: [PATCH 4/7] add icu + +Signed-off-by: ryne3366 +--- + src/sqlite3.c | 1033 ++++------------------------------------------ + src/sqlite3icu.c | 892 +++++++++++++++++++++++++++++++++++++++ + 2 files changed, 976 insertions(+), 949 deletions(-) + create mode 100644 src/sqlite3icu.c + +diff --git a/src/sqlite3.c b/src/sqlite3.c +index 71f902b..dd89c5a 100644 +--- a/src/sqlite3.c ++++ b/src/sqlite3.c +@@ -2459,7 +2459,7 @@ struct sqlite3_mem_methods { + #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ + #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ + #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ +- ++#define SQLITE_CONFIG_ENABLE_ICU 31 /* boolean */ + /* + ** CAPI3REF: Database Connection Configuration Options + ** +@@ -3193,6 +3193,17 @@ SQLITE_API int sqlite3_get_table( + ); + SQLITE_API void sqlite3_free_table(char **result); + ++// hw export the symbols ++#ifdef SQLITE_EXPORT_SYMBOLS ++#if defined(__GNUC__) ++# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) ++#elif defined(_MSC_VER) ++# define EXPORT_SYMBOLS __declspec(dllexport) ++#else ++# define EXPORT_SYMBOLS ++#endif ++#endif // SQLITE_EXPORT_SYMBOLS ++ + /* + ** CAPI3REF: Formatted String Printing Functions + ** +@@ -173713,6 +173724,7 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db); + /************** End of rtree.h ***********************************************/ + /************** Continuing where we left off in main.c ***********************/ + #endif ++#include "sqlite3tokenizer.h" + #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) + /************** Include sqliteicu.h in the middle of main.c ******************/ + /************** Begin file sqliteicu.h ***************************************/ +@@ -173737,13 +173749,54 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db); + extern "C" { + #endif /* __cplusplus */ + +-SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db); ++SQLITE_PRIVATE int sqlite3IcuInitInner(sqlite3 *db); + + #if 0 + } /* extern "C" */ + #endif /* __cplusplus */ + + /************** End of sqliteicu.h *******************************************/ ++#ifndef _WIN32 ++#include ++#endif ++ ++typedef void (*sqlite3Fts3IcuTokenizerModule_ptr)(sqlite3_tokenizer_module const** ppModule); ++typedef int (*sqlite3IcuInit_ptr)(sqlite3 *db); ++static sqlite3Fts3IcuTokenizerModule_ptr tokenModulePtr = NULL; ++static sqlite3IcuInit_ptr icuInitPtr = NULL; ++static u32 icuEnable = 0u; ++static u32 icuInit = 0u; ++static void *g_library = NULL; ++ ++int sqlite3IcuModuleInit(){ ++ int rc = SQLITE_OK; ++ if( icuInit ){ ++ return rc; ++ } ++#ifndef _WIN32 ++ g_library = dlopen("libsqliteicu.z.so", RTLD_LAZY); ++ if( g_library==NULL ){ ++ sqlite3_log(SQLITE_ERROR, "load icu so failed"); ++ return SQLITE_ERROR; ++ } ++ tokenModulePtr = (sqlite3Fts3IcuTokenizerModule_ptr)dlsym(g_library, "sqlite3Fts3IcuTokenizerModule"); ++ icuInitPtr = (sqlite3IcuInit_ptr)dlsym(g_library, "sqlite3IcuInit"); ++ if( tokenModulePtr==NULL || icuInitPtr==NULL ){ ++ sqlite3_log(SQLITE_ERROR, "load icu init function failed"); ++ return SQLITE_ERROR; ++ } ++ icuInit = 1u; ++#endif ++ return rc; ++} ++ ++SQLITE_PRIVATE int sqlite3IcuInitInner(sqlite3 *db) ++{ ++ if( !icuEnable ){ ++ return SQLITE_OK; ++ } ++ return icuInitPtr(db); ++} + /************** Continuing where we left off in main.c ***********************/ + #endif + +@@ -173793,7 +173846,7 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = { + sqlite3Fts5Init, + #endif + #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) +- sqlite3IcuInit, ++ sqlite3IcuInitInner, + #endif + #ifdef SQLITE_ENABLE_RTREE + sqlite3RtreeInit, +@@ -174150,12 +174203,24 @@ SQLITE_API int sqlite3_shutdown(void){ + SQLITE_API int sqlite3_config(int op, ...){ + va_list ap; + int rc = SQLITE_OK; ++ va_start(ap, op); ++ ++#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) ++ if( op==SQLITE_CONFIG_ENABLE_ICU ){ ++ int iVal = va_arg(ap, int); ++ if( iVal==0 ){ ++ icuEnable = 0u; ++ }else{ ++ icuEnable = 1u; ++ } ++ return rc; ++ } ++#endif /* SQLITE_ENABLE_ICU */ + + /* sqlite3_config() shall return SQLITE_MISUSE if it is invoked while + ** the SQLite library is in use. */ + if( sqlite3GlobalConfig.isInit ) return SQLITE_MISUSE_BKPT; + +- va_start(ap, op); + switch( op ){ + + /* Mutex configuration options are only available in a threadsafe +@@ -177223,6 +177288,12 @@ static int openDatabase( + sqlite3RegisterPerConnectionBuiltinFunctions(db); + rc = sqlite3_errcode(db); + ++#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) ++ if( icuEnable ){ ++ rc = sqlite3IcuModuleInit(); ++ if( rc!=SQLITE_OK ) return rc; ++ } ++#endif + + /* Load compiled-in extensions */ + for(i=0; rc==SQLITE_OK && i arg1 arg2) +- ** +- ** then argc is set to 2, and the argv[] array contains pointers +- ** to the strings "arg1" and "arg2". +- ** +- ** This method should return either SQLITE_OK (0), or an SQLite error +- ** code. If SQLITE_OK is returned, then *ppTokenizer should be set +- ** to point at the newly created tokenizer structure. The generic +- ** sqlite3_tokenizer.pModule variable should not be initialized by +- ** this callback. The caller will do so. +- */ +- int (*xCreate)( +- int argc, /* Size of argv array */ +- const char *const*argv, /* Tokenizer argument strings */ +- sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ +- ); +- +- /* +- ** Destroy an existing tokenizer. The fts3 module calls this method +- ** exactly once for each successful call to xCreate(). +- */ +- int (*xDestroy)(sqlite3_tokenizer *pTokenizer); +- +- /* +- ** Create a tokenizer cursor to tokenize an input buffer. The caller +- ** is responsible for ensuring that the input buffer remains valid +- ** until the cursor is closed (using the xClose() method). +- */ +- int (*xOpen)( +- sqlite3_tokenizer *pTokenizer, /* Tokenizer object */ +- const char *pInput, int nBytes, /* Input buffer */ +- sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */ +- ); +- +- /* +- ** Destroy an existing tokenizer cursor. The fts3 module calls this +- ** method exactly once for each successful call to xOpen(). +- */ +- int (*xClose)(sqlite3_tokenizer_cursor *pCursor); +- +- /* +- ** Retrieve the next token from the tokenizer cursor pCursor. This +- ** method should either return SQLITE_OK and set the values of the +- ** "OUT" variables identified below, or SQLITE_DONE to indicate that +- ** the end of the buffer has been reached, or an SQLite error code. +- ** +- ** *ppToken should be set to point at a buffer containing the +- ** normalized version of the token (i.e. after any case-folding and/or +- ** stemming has been performed). *pnBytes should be set to the length +- ** of this buffer in bytes. The input text that generated the token is +- ** identified by the byte offsets returned in *piStartOffset and +- ** *piEndOffset. *piStartOffset should be set to the index of the first +- ** byte of the token in the input buffer. *piEndOffset should be set +- ** to the index of the first byte just past the end of the token in +- ** the input buffer. +- ** +- ** The buffer *ppToken is set to point at is managed by the tokenizer +- ** implementation. It is only required to be valid until the next call +- ** to xNext() or xClose(). +- */ +- /* TODO(shess) current implementation requires pInput to be +- ** nul-terminated. This should either be fixed, or pInput/nBytes +- ** should be converted to zInput. +- */ +- int (*xNext)( +- sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */ +- const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */ +- int *piStartOffset, /* OUT: Byte offset of token in input buffer */ +- int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */ +- int *piPosition /* OUT: Number of tokens returned before this one */ +- ); +- +- /*********************************************************************** +- ** Methods below this point are only available if iVersion>=1. +- */ +- +- /* +- ** Configure the language id of a tokenizer cursor. +- */ +- int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid); +-}; +- +-struct sqlite3_tokenizer { +- const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */ +- /* Tokenizer implementations will typically add additional fields */ +-}; +- +-struct sqlite3_tokenizer_cursor { +- sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */ +- /* Tokenizer implementations will typically add additional fields */ +-}; + + int fts3_global_term_cnt(int iTerm, int iCol); + int fts3_term_cnt(int iTerm, int iCol); +@@ -183999,9 +183962,6 @@ SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(sqlite3_tokenizer_module co + #ifndef SQLITE_DISABLE_FTS3_UNICODE + SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const**ppModule); + #endif +-#ifdef SQLITE_ENABLE_ICU +-SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); +-#endif + + /* + ** Initialize the fts3 extension. If this extension is built as part +@@ -184020,7 +183980,14 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){ + + #ifdef SQLITE_ENABLE_ICU + const sqlite3_tokenizer_module *pIcu = 0; +- sqlite3Fts3IcuTokenizerModule(&pIcu); ++ if( icuEnable ){ ++ if( tokenModulePtr!=NULL ){ ++ tokenModulePtr(&pIcu); ++ }else{ ++ sqlite3_log(SQLITE_ERROR, "icu module ptr is null"); ++ return SQLITE_ERROR; ++ } ++ } + #endif + + #ifndef SQLITE_DISABLE_FTS3_UNICODE +@@ -184056,7 +184023,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){ + || sqlite3Fts3HashInsert(&pHash->hash, "unicode61", 10, (void *)pUnicode) + #endif + #ifdef SQLITE_ENABLE_ICU +- || (pIcu && sqlite3Fts3HashInsert(&pHash->hash, "icu", 4, (void *)pIcu)) ++ || (icuEnable && pIcu && sqlite3Fts3HashInsert(&pHash->hash, "icu", 4, (void *)pIcu)) + #endif + ){ + rc = SQLITE_NOMEM; +@@ -207668,829 +207635,6 @@ SQLITE_API int sqlite3_rtree_init( + #endif + + /************** End of rtree.c ***********************************************/ +-/************** Begin file icu.c *********************************************/ +-/* +-** 2007 May 6 +-** +-** The author disclaims copyright to this source code. In place of +-** a legal notice, here is a blessing: +-** +-** May you do good and not evil. +-** May you find forgiveness for yourself and forgive others. +-** May you share freely, never taking more than you give. +-** +-************************************************************************* +-** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $ +-** +-** This file implements an integration between the ICU library +-** ("International Components for Unicode", an open-source library +-** for handling unicode data) and SQLite. The integration uses +-** ICU to provide the following to SQLite: +-** +-** * An implementation of the SQL regexp() function (and hence REGEXP +-** operator) using the ICU uregex_XX() APIs. +-** +-** * Implementations of the SQL scalar upper() and lower() functions +-** for case mapping. +-** +-** * Integration of ICU and SQLite collation sequences. +-** +-** * An implementation of the LIKE operator that uses ICU to +-** provide case-independent matching. +-*/ +- +-#if !defined(SQLITE_CORE) \ +- || defined(SQLITE_ENABLE_ICU) \ +- || defined(SQLITE_ENABLE_ICU_COLLATIONS) +- +-/* Include ICU headers */ +-#include +-#include +-#include +-#include +- +-/* #include */ +- +-#ifndef SQLITE_CORE +-/* #include "sqlite3ext.h" */ +- SQLITE_EXTENSION_INIT1 +-#else +-/* #include "sqlite3.h" */ +-#endif +- +-/* +-** This function is called when an ICU function called from within +-** the implementation of an SQL scalar function returns an error. +-** +-** The scalar function context passed as the first argument is +-** loaded with an error message based on the following two args. +-*/ +-static void icuFunctionError( +- sqlite3_context *pCtx, /* SQLite scalar function context */ +- const char *zName, /* Name of ICU function that failed */ +- UErrorCode e /* Error code returned by ICU function */ +-){ +- char zBuf[128]; +- sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e)); +- zBuf[127] = '\0'; +- sqlite3_result_error(pCtx, zBuf, -1); +-} +- +-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) +- +-/* +-** Maximum length (in bytes) of the pattern in a LIKE or GLOB +-** operator. +-*/ +-#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH +-# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000 +-#endif +- +-/* +-** Version of sqlite3_free() that is always a function, never a macro. +-*/ +-static void xFree(void *p){ +- sqlite3_free(p); +-} +- +-/* +-** This lookup table is used to help decode the first byte of +-** a multi-byte UTF8 character. It is copied here from SQLite source +-** code file utf8.c. +-*/ +-static const unsigned char icuUtf8Trans1[] = { +- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, +- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, +- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, +- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, +- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +- 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, +-}; +- +-#define SQLITE_ICU_READ_UTF8(zIn, c) \ +- c = *(zIn++); \ +- if( c>=0xc0 ){ \ +- c = icuUtf8Trans1[c-0xc0]; \ +- while( (*zIn & 0xc0)==0x80 ){ \ +- c = (c<<6) + (0x3f & *(zIn++)); \ +- } \ +- } +- +-#define SQLITE_ICU_SKIP_UTF8(zIn) \ +- assert( *zIn ); \ +- if( *(zIn++)>=0xc0 ){ \ +- while( (*zIn & 0xc0)==0x80 ){zIn++;} \ +- } +- +- +-/* +-** Compare two UTF-8 strings for equality where the first string is +-** a "LIKE" expression. Return true (1) if they are the same and +-** false (0) if they are different. +-*/ +-static int icuLikeCompare( +- const uint8_t *zPattern, /* LIKE pattern */ +- const uint8_t *zString, /* The UTF-8 string to compare against */ +- const UChar32 uEsc /* The escape character */ +-){ +- static const uint32_t MATCH_ONE = (uint32_t)'_'; +- static const uint32_t MATCH_ALL = (uint32_t)'%'; +- +- int prevEscape = 0; /* True if the previous character was uEsc */ +- +- while( 1 ){ +- +- /* Read (and consume) the next character from the input pattern. */ +- uint32_t uPattern; +- SQLITE_ICU_READ_UTF8(zPattern, uPattern); +- if( uPattern==0 ) break; +- +- /* There are now 4 possibilities: +- ** +- ** 1. uPattern is an unescaped match-all character "%", +- ** 2. uPattern is an unescaped match-one character "_", +- ** 3. uPattern is an unescaped escape character, or +- ** 4. uPattern is to be handled as an ordinary character +- */ +- if( uPattern==MATCH_ALL && !prevEscape && uPattern!=(uint32_t)uEsc ){ +- /* Case 1. */ +- uint8_t c; +- +- /* Skip any MATCH_ALL or MATCH_ONE characters that follow a +- ** MATCH_ALL. For each MATCH_ONE, skip one character in the +- ** test string. +- */ +- while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){ +- if( c==MATCH_ONE ){ +- if( *zString==0 ) return 0; +- SQLITE_ICU_SKIP_UTF8(zString); +- } +- zPattern++; +- } +- +- if( *zPattern==0 ) return 1; +- +- while( *zString ){ +- if( icuLikeCompare(zPattern, zString, uEsc) ){ +- return 1; +- } +- SQLITE_ICU_SKIP_UTF8(zString); +- } +- return 0; +- +- }else if( uPattern==MATCH_ONE && !prevEscape && uPattern!=(uint32_t)uEsc ){ +- /* Case 2. */ +- if( *zString==0 ) return 0; +- SQLITE_ICU_SKIP_UTF8(zString); +- +- }else if( uPattern==(uint32_t)uEsc && !prevEscape ){ +- /* Case 3. */ +- prevEscape = 1; +- +- }else{ +- /* Case 4. */ +- uint32_t uString; +- SQLITE_ICU_READ_UTF8(zString, uString); +- uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT); +- uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT); +- if( uString!=uPattern ){ +- return 0; +- } +- prevEscape = 0; +- } +- } +- +- return *zString==0; +-} +- +-/* +-** Implementation of the like() SQL function. This function implements +-** the build-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 +-** +-** is implemented as like(B, A). If there is an escape character E, +-** +-** A LIKE B ESCAPE E +-** +-** is mapped to like(B, A, E). +-*/ +-static void icuLikeFunc( +- sqlite3_context *context, +- int argc, +- sqlite3_value **argv +-){ +- const unsigned char *zA = sqlite3_value_text(argv[0]); +- const unsigned char *zB = sqlite3_value_text(argv[1]); +- UChar32 uEsc = 0; +- +- /* Limit the length of the LIKE or GLOB pattern to avoid problems +- ** of deep recursion and N*N behavior in patternCompare(). +- */ +- if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){ +- sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); +- return; +- } +- +- +- if( argc==3 ){ +- /* The escape character string must consist of a single UTF-8 character. +- ** Otherwise, return an error. +- */ +- int nE= sqlite3_value_bytes(argv[2]); +- const unsigned char *zE = sqlite3_value_text(argv[2]); +- int i = 0; +- if( zE==0 ) return; +- U8_NEXT(zE, i, nE, uEsc); +- if( i!=nE){ +- sqlite3_result_error(context, +- "ESCAPE expression must be a single character", -1); +- return; +- } +- } +- +- if( zA && zB ){ +- sqlite3_result_int(context, icuLikeCompare(zA, zB, uEsc)); +- } +-} +- +-/* +-** Function to delete compiled regexp objects. Registered as +-** a destructor function with sqlite3_set_auxdata(). +-*/ +-static void icuRegexpDelete(void *p){ +- URegularExpression *pExpr = (URegularExpression *)p; +- uregex_close(pExpr); +-} +- +-/* +-** Implementation of SQLite REGEXP operator. This scalar function takes +-** two arguments. The first is a regular expression pattern to compile +-** the second is a string to match against that pattern. If either +-** argument is an SQL NULL, then NULL Is returned. Otherwise, the result +-** is 1 if the string matches the pattern, or 0 otherwise. +-** +-** SQLite maps the regexp() function to the regexp() operator such +-** that the following two are equivalent: +-** +-** zString REGEXP zPattern +-** regexp(zPattern, zString) +-** +-** Uses the following ICU regexp APIs: +-** +-** uregex_open() +-** uregex_matches() +-** uregex_close() +-*/ +-static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ +- UErrorCode status = U_ZERO_ERROR; +- URegularExpression *pExpr; +- UBool res; +- const UChar *zString = sqlite3_value_text16(apArg[1]); +- +- (void)nArg; /* Unused parameter */ +- +- /* If the left hand side of the regexp operator is NULL, +- ** then the result is also NULL. +- */ +- if( !zString ){ +- return; +- } +- +- pExpr = sqlite3_get_auxdata(p, 0); +- if( !pExpr ){ +- const UChar *zPattern = sqlite3_value_text16(apArg[0]); +- if( !zPattern ){ +- return; +- } +- pExpr = uregex_open(zPattern, -1, 0, 0, &status); +- +- if( U_SUCCESS(status) ){ +- sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete); +- pExpr = sqlite3_get_auxdata(p, 0); +- } +- if( !pExpr ){ +- icuFunctionError(p, "uregex_open", status); +- return; +- } +- } +- +- /* Configure the text that the regular expression operates on. */ +- uregex_setText(pExpr, zString, -1, &status); +- if( !U_SUCCESS(status) ){ +- icuFunctionError(p, "uregex_setText", status); +- return; +- } +- +- /* Attempt the match */ +- res = uregex_matches(pExpr, 0, &status); +- if( !U_SUCCESS(status) ){ +- icuFunctionError(p, "uregex_matches", status); +- return; +- } +- +- /* Set the text that the regular expression operates on to a NULL +- ** pointer. This is not really necessary, but it is tidier than +- ** leaving the regular expression object configured with an invalid +- ** pointer after this function returns. +- */ +- uregex_setText(pExpr, 0, 0, &status); +- +- /* Return 1 or 0. */ +- sqlite3_result_int(p, res ? 1 : 0); +-} +- +-/* +-** Implementations of scalar functions for case mapping - upper() and +-** lower(). Function upper() converts its input to upper-case (ABC). +-** Function lower() converts to lower-case (abc). +-** +-** ICU provides two types of case mapping, "general" case mapping and +-** "language specific". Refer to ICU documentation for the differences +-** between the two. +-** +-** To utilise "general" case mapping, the upper() or lower() scalar +-** functions are invoked with one argument: +-** +-** upper('ABC') -> 'abc' +-** lower('abc') -> 'ABC' +-** +-** To access ICU "language specific" case mapping, upper() or lower() +-** should be invoked with two arguments. The second argument is the name +-** of the locale to use. Passing an empty string ("") or SQL NULL value +-** as the second argument is the same as invoking the 1 argument version +-** of upper() or lower(). +-** +-** lower('I', 'en_us') -> 'i' +-** lower('I', 'tr_tr') -> '\u131' (small dotless i) +-** +-** http://www.icu-project.org/userguide/posix.html#case_mappings +-*/ +-static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ +- const UChar *zInput; /* Pointer to input string */ +- UChar *zOutput = 0; /* Pointer to output buffer */ +- int nInput; /* Size of utf-16 input string in bytes */ +- int nOut; /* Size of output buffer in bytes */ +- int cnt; +- int bToUpper; /* True for toupper(), false for tolower() */ +- UErrorCode status; +- const char *zLocale = 0; +- +- assert(nArg==1 || nArg==2); +- bToUpper = (sqlite3_user_data(p)!=0); +- if( nArg==2 ){ +- zLocale = (const char *)sqlite3_value_text(apArg[1]); +- } +- +- zInput = sqlite3_value_text16(apArg[0]); +- if( !zInput ){ +- return; +- } +- nOut = nInput = sqlite3_value_bytes16(apArg[0]); +- if( nOut==0 ){ +- sqlite3_result_text16(p, "", 0, SQLITE_STATIC); +- return; +- } +- +- for(cnt=0; cnt<2; cnt++){ +- UChar *zNew = sqlite3_realloc(zOutput, nOut); +- if( zNew==0 ){ +- sqlite3_free(zOutput); +- sqlite3_result_error_nomem(p); +- return; +- } +- zOutput = zNew; +- status = U_ZERO_ERROR; +- if( bToUpper ){ +- nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); +- }else{ +- nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); +- } +- +- if( U_SUCCESS(status) ){ +- sqlite3_result_text16(p, zOutput, nOut, xFree); +- }else if( status==U_BUFFER_OVERFLOW_ERROR ){ +- assert( cnt==0 ); +- continue; +- }else{ +- icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status); +- } +- return; +- } +- assert( 0 ); /* Unreachable */ +-} +- +-#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ +- +-/* +-** Collation sequence destructor function. The pCtx argument points to +-** a UCollator structure previously allocated using ucol_open(). +-*/ +-static void icuCollationDel(void *pCtx){ +- UCollator *p = (UCollator *)pCtx; +- ucol_close(p); +-} +- +-/* +-** Collation sequence comparison function. The pCtx argument points to +-** a UCollator structure previously allocated using ucol_open(). +-*/ +-static int icuCollationColl( +- void *pCtx, +- int nLeft, +- const void *zLeft, +- int nRight, +- const void *zRight +-){ +- UCollationResult res; +- UCollator *p = (UCollator *)pCtx; +- res = ucol_strcoll(p, (UChar *)zLeft, nLeft/2, (UChar *)zRight, nRight/2); +- switch( res ){ +- case UCOL_LESS: return -1; +- case UCOL_GREATER: return +1; +- case UCOL_EQUAL: return 0; +- } +- assert(!"Unexpected return value from ucol_strcoll()"); +- return 0; +-} +- +-/* +-** Implementation of the scalar function icu_load_collation(). +-** +-** This scalar function is used to add ICU collation based collation +-** types to an SQLite database connection. It is intended to be called +-** as follows: +-** +-** SELECT icu_load_collation(, ); +-** +-** Where is a string containing an ICU locale identifier (i.e. +-** "en_AU", "tr_TR" etc.) and is the name of the +-** collation sequence to create. +-*/ +-static void icuLoadCollation( +- sqlite3_context *p, +- int nArg, +- sqlite3_value **apArg +-){ +- sqlite3 *db = (sqlite3 *)sqlite3_user_data(p); +- UErrorCode status = U_ZERO_ERROR; +- const char *zLocale; /* Locale identifier - (eg. "jp_JP") */ +- const char *zName; /* SQL Collation sequence name (eg. "japanese") */ +- UCollator *pUCollator; /* ICU library collation object */ +- int rc; /* Return code from sqlite3_create_collation_x() */ +- +- assert(nArg==2); +- (void)nArg; /* Unused parameter */ +- zLocale = (const char *)sqlite3_value_text(apArg[0]); +- zName = (const char *)sqlite3_value_text(apArg[1]); +- +- if( !zLocale || !zName ){ +- return; +- } +- +- pUCollator = ucol_open(zLocale, &status); +- if( !U_SUCCESS(status) ){ +- icuFunctionError(p, "ucol_open", status); +- return; +- } +- assert(p); +- +- rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator, +- icuCollationColl, icuCollationDel +- ); +- if( rc!=SQLITE_OK ){ +- ucol_close(pUCollator); +- sqlite3_result_error(p, "Error registering collation function", -1); +- } +-} +- +-/* +-** Register the ICU extension functions with database db. +-*/ +-SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){ +-# define SQLITEICU_EXTRAFLAGS (SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS) +- static const struct IcuScalar { +- const char *zName; /* Function name */ +- unsigned char nArg; /* Number of arguments */ +- unsigned int enc; /* Optimal text encoding */ +- unsigned char iContext; /* sqlite3_user_data() context */ +- void (*xFunc)(sqlite3_context*,int,sqlite3_value**); +- } scalars[] = { +- {"icu_load_collation",2,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}, +- {"lower", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, +- {"upper", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, +- {"upper", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, +- {"lower", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, +- {"lower", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, +- {"upper", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, +- {"upper", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, +- {"like", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc}, +- {"like", 3, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc}, +-#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ +- }; +- int rc = SQLITE_OK; +- int i; +- +- for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){ +- const struct IcuScalar *p = &scalars[i]; +- rc = sqlite3_create_function( +- db, p->zName, p->nArg, p->enc, +- p->iContext ? (void*)db : (void*)0, +- p->xFunc, 0, 0 +- ); +- } +- +- return rc; +-} +- +-#if !SQLITE_CORE +-#ifdef _WIN32 +-__declspec(dllexport) +-#endif +-SQLITE_API int sqlite3_icu_init( +- sqlite3 *db, +- char **pzErrMsg, +- const sqlite3_api_routines *pApi +-){ +- SQLITE_EXTENSION_INIT2(pApi) +- return sqlite3IcuInit(db); +-} +-#endif +- +-#endif +- +-/************** End of icu.c *************************************************/ +-/************** Begin file fts3_icu.c ****************************************/ +-/* +-** 2007 June 22 +-** +-** The author disclaims copyright to this source code. In place of +-** a legal notice, here is a blessing: +-** +-** May you do good and not evil. +-** May you find forgiveness for yourself and forgive others. +-** May you share freely, never taking more than you give. +-** +-************************************************************************* +-** This file implements a tokenizer for fts3 based on the ICU library. +-*/ +-/* #include "fts3Int.h" */ +-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) +-#ifdef SQLITE_ENABLE_ICU +- +-/* #include */ +-/* #include */ +-/* #include "fts3_tokenizer.h" */ +- +-#include +-/* #include */ +-/* #include */ +-#include +- +-typedef struct IcuTokenizer IcuTokenizer; +-typedef struct IcuCursor IcuCursor; +- +-struct IcuTokenizer { +- sqlite3_tokenizer base; +- char *zLocale; +-}; +- +-struct IcuCursor { +- sqlite3_tokenizer_cursor base; +- +- UBreakIterator *pIter; /* ICU break-iterator object */ +- int nChar; /* Number of UChar elements in pInput */ +- UChar *aChar; /* Copy of input using utf-16 encoding */ +- int *aOffset; /* Offsets of each character in utf-8 input */ +- +- int nBuffer; +- char *zBuffer; +- +- int iToken; +-}; +- +-/* +-** Create a new tokenizer instance. +-*/ +-static int icuCreate( +- int argc, /* Number of entries in argv[] */ +- const char * const *argv, /* Tokenizer creation arguments */ +- sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ +-){ +- IcuTokenizer *p; +- int n = 0; +- +- if( argc>0 ){ +- n = strlen(argv[0])+1; +- } +- p = (IcuTokenizer *)sqlite3_malloc64(sizeof(IcuTokenizer)+n); +- if( !p ){ +- return SQLITE_NOMEM; +- } +- memset(p, 0, sizeof(IcuTokenizer)); +- +- if( n ){ +- p->zLocale = (char *)&p[1]; +- memcpy(p->zLocale, argv[0], n); +- } +- +- *ppTokenizer = (sqlite3_tokenizer *)p; +- +- return SQLITE_OK; +-} +- +-/* +-** Destroy a tokenizer +-*/ +-static int icuDestroy(sqlite3_tokenizer *pTokenizer){ +- IcuTokenizer *p = (IcuTokenizer *)pTokenizer; +- sqlite3_free(p); +- return SQLITE_OK; +-} +- +-/* +-** Prepare to begin tokenizing a particular string. The input +-** string to be tokenized is pInput[0..nBytes-1]. A cursor +-** used to incrementally tokenize this string is returned in +-** *ppCursor. +-*/ +-static int icuOpen( +- sqlite3_tokenizer *pTokenizer, /* The tokenizer */ +- const char *zInput, /* Input string */ +- int nInput, /* Length of zInput in bytes */ +- sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ +-){ +- IcuTokenizer *p = (IcuTokenizer *)pTokenizer; +- IcuCursor *pCsr; +- +- const int32_t opt = U_FOLD_CASE_DEFAULT; +- UErrorCode status = U_ZERO_ERROR; +- int nChar; +- +- UChar32 c; +- int iInput = 0; +- int iOut = 0; +- +- *ppCursor = 0; +- +- if( zInput==0 ){ +- nInput = 0; +- zInput = ""; +- }else if( nInput<0 ){ +- nInput = strlen(zInput); +- } +- nChar = nInput+1; +- pCsr = (IcuCursor *)sqlite3_malloc64( +- sizeof(IcuCursor) + /* IcuCursor */ +- ((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */ +- (nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */ +- ); +- if( !pCsr ){ +- return SQLITE_NOMEM; +- } +- memset(pCsr, 0, sizeof(IcuCursor)); +- pCsr->aChar = (UChar *)&pCsr[1]; +- pCsr->aOffset = (int *)&pCsr->aChar[(nChar+3)&~3]; +- +- pCsr->aOffset[iOut] = iInput; +- U8_NEXT(zInput, iInput, nInput, c); +- while( c>0 ){ +- int isError = 0; +- c = u_foldCase(c, opt); +- U16_APPEND(pCsr->aChar, iOut, nChar, c, isError); +- if( isError ){ +- sqlite3_free(pCsr); +- return SQLITE_ERROR; +- } +- pCsr->aOffset[iOut] = iInput; +- +- if( iInputpIter = ubrk_open(UBRK_WORD, p->zLocale, pCsr->aChar, iOut, &status); +- if( !U_SUCCESS(status) ){ +- sqlite3_free(pCsr); +- return SQLITE_ERROR; +- } +- pCsr->nChar = iOut; +- +- ubrk_first(pCsr->pIter); +- *ppCursor = (sqlite3_tokenizer_cursor *)pCsr; +- return SQLITE_OK; +-} +- +-/* +-** Close a tokenization cursor previously opened by a call to icuOpen(). +-*/ +-static int icuClose(sqlite3_tokenizer_cursor *pCursor){ +- IcuCursor *pCsr = (IcuCursor *)pCursor; +- ubrk_close(pCsr->pIter); +- sqlite3_free(pCsr->zBuffer); +- sqlite3_free(pCsr); +- return SQLITE_OK; +-} +- +-/* +-** Extract the next token from a tokenization cursor. +-*/ +-static int icuNext( +- sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by simpleOpen */ +- const char **ppToken, /* OUT: *ppToken is the token text */ +- int *pnBytes, /* OUT: Number of bytes in token */ +- int *piStartOffset, /* OUT: Starting offset of token */ +- int *piEndOffset, /* OUT: Ending offset of token */ +- int *piPosition /* OUT: Position integer of token */ +-){ +- IcuCursor *pCsr = (IcuCursor *)pCursor; +- +- int iStart = 0; +- int iEnd = 0; +- int nByte = 0; +- +- while( iStart==iEnd ){ +- UChar32 c; +- +- iStart = ubrk_current(pCsr->pIter); +- iEnd = ubrk_next(pCsr->pIter); +- if( iEnd==UBRK_DONE ){ +- return SQLITE_DONE; +- } +- +- while( iStartaChar, iWhite, pCsr->nChar, c); +- if( u_isspace(c) ){ +- iStart = iWhite; +- }else{ +- break; +- } +- } +- assert(iStart<=iEnd); +- } +- +- do { +- UErrorCode status = U_ZERO_ERROR; +- if( nByte ){ +- char *zNew = sqlite3_realloc(pCsr->zBuffer, nByte); +- if( !zNew ){ +- return SQLITE_NOMEM; +- } +- pCsr->zBuffer = zNew; +- pCsr->nBuffer = nByte; +- } +- +- u_strToUTF8( +- pCsr->zBuffer, pCsr->nBuffer, &nByte, /* Output vars */ +- &pCsr->aChar[iStart], iEnd-iStart, /* Input vars */ +- &status /* Output success/failure */ +- ); +- } while( nByte>pCsr->nBuffer ); +- +- *ppToken = pCsr->zBuffer; +- *pnBytes = nByte; +- *piStartOffset = pCsr->aOffset[iStart]; +- *piEndOffset = pCsr->aOffset[iEnd]; +- *piPosition = pCsr->iToken++; +- +- return SQLITE_OK; +-} +- +-/* +-** The set of routines that implement the simple tokenizer +-*/ +-static const sqlite3_tokenizer_module icuTokenizerModule = { +- 0, /* iVersion */ +- icuCreate, /* xCreate */ +- icuDestroy, /* xCreate */ +- icuOpen, /* xOpen */ +- icuClose, /* xClose */ +- icuNext, /* xNext */ +- 0, /* xLanguageid */ +-}; +- +-/* +-** Set *ppModule to point at the implementation of the ICU tokenizer. +-*/ +-SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( +- sqlite3_tokenizer_module const**ppModule +-){ +- *ppModule = &icuTokenizerModule; +-} +- +-#endif /* defined(SQLITE_ENABLE_ICU) */ +-#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ +- +-/************** End of fts3_icu.c ********************************************/ + /************** Begin file sqlite3rbu.c **************************************/ + /* + ** 2014 August 30 +@@ -247837,15 +246981,6 @@ static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime + #endif + // hw export the symbols + #ifdef SQLITE_EXPORT_SYMBOLS +-/************** Begin hw export the symbols *****************************************/ +-#if defined(__GNUC__) +-# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) +-#elif defined(_MSC_VER) +-# define EXPORT_SYMBOLS __declspec(dllexport) +-#else +-# define EXPORT_SYMBOLS +-#endif +- + struct sqlite3_api_routines_hw { + int (*initialize)(); + int (*config)(int,...); +diff --git a/src/sqlite3icu.c b/src/sqlite3icu.c +new file mode 100644 +index 0000000..6a581fc +--- /dev/null ++++ b/src/sqlite3icu.c +@@ -0,0 +1,892 @@ ++/****************************************************************************** ++** This file is an amalgamation of many separate C source files from SQLite ++** version 3.40.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 ++** of 5% or more are commonly seen when SQLite is compiled as a single ++** translation unit. ++** ++** This file is all you need to compile SQLite. To use SQLite in other ++** programs, you need this file and the "sqlite3.h" header file that defines ++** the programming interface to the SQLite library. (If you do not have ++** the "sqlite3.h" header file at hand, you will find a copy embedded within ++** the text of this file. Search for "Begin file sqlite3.h" to find the start ++** of the embedded sqlite3.h header file.) Additional code files may be needed ++** if you want a wrapper to interface SQLite with your choice of programming ++** language. The code for the "sqlite3" command-line shell is also in a ++** separate file. This file contains only code for the core SQLite library. ++*/ ++/* ++** 2019.09.02-Complete codec logic for encryption and decryption. ++** Huawei Technologies Co, Ltd. ++*/ ++/************** Begin file icu.c *********************************************/ ++/* ++** 2007 May 6 ++** ++** The author disclaims copyright to this source code. In place of ++** a legal notice, here is a blessing: ++** ++** May you do good and not evil. ++** May you find forgiveness for yourself and forgive others. ++** May you share freely, never taking more than you give. ++** ++************************************************************************* ++** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $ ++** ++** This file implements an integration between the ICU library ++** ("International Components for Unicode", an open-source library ++** for handling unicode data) and SQLite. The integration uses ++** ICU to provide the following to SQLite: ++** ++** * An implementation of the SQL regexp() function (and hence REGEXP ++** operator) using the ICU uregex_XX() APIs. ++** ++** * Implementations of the SQL scalar upper() and lower() functions ++** for case mapping. ++** ++** * Integration of ICU and SQLite collation sequences. ++** ++** * An implementation of the LIKE operator that uses ICU to ++** provide case-independent matching. ++*/ ++#include ++#include ++#include ++#include ++#include ++ ++#include "sqlite3icu.h" ++#include "sqlite3.h" ++ ++#ifdef HARMONY_OS ++#include "common/unicode/putil.h" ++#endif ++ ++#if !defined(SQLITE_CORE) \ ++ || defined(SQLITE_ENABLE_ICU) \ ++ || defined(SQLITE_ENABLE_ICU_COLLATIONS) ++ ++/* Include ICU headers */ ++#include ++#include ++#include ++#include ++ ++#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) ++ /* This case when the file really is being compiled as a loadable ++ ** extension */ ++# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; ++# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; ++# define SQLITE_EXTENSION_INIT3 \ ++ extern const sqlite3_api_routines *sqlite3_api; ++#else ++ /* 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 */ ++# define SQLITE_EXTENSION_INIT3 /*no-op*/ ++#endif ++ ++/* #include */ ++ ++#ifndef SQLITE_CORE ++/* #include "sqlite3ext.h" */ ++ SQLITE_EXTENSION_INIT1 ++#else ++/* #include "sqlite3.h" */ ++#endif ++ ++// hw export the symbols ++#ifdef SQLITE_EXPORT_SYMBOLS ++#if defined(__GNUC__) ++# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) ++#elif defined(_MSC_VER) ++# define EXPORT_SYMBOLS __declspec(dllexport) ++#else ++# define EXPORT_SYMBOLS ++#endif ++#endif ++ ++EXPORT_SYMBOLS SQLITE_API int sqlite3IcuInit(sqlite3 *db); ++#ifdef SQLITE_ENABLE_ICU ++EXPORT_SYMBOLS SQLITE_API void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); ++#endif ++/* ++** This function is called when an ICU function called from within ++** the implementation of an SQL scalar function returns an error. ++** ++** The scalar function context passed as the first argument is ++** loaded with an error message based on the following two args. ++*/ ++static void icuFunctionError( ++ sqlite3_context *pCtx, /* SQLite scalar function context */ ++ const char *zName, /* Name of ICU function that failed */ ++ UErrorCode e /* Error code returned by ICU function */ ++){ ++ char zBuf[128]; ++ sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e)); ++ zBuf[127] = '\0'; ++ sqlite3_result_error(pCtx, zBuf, -1); ++} ++ ++#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) ++ ++/* ++** Maximum length (in bytes) of the pattern in a LIKE or GLOB ++** operator. ++*/ ++#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH ++# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000 ++#endif ++ ++/* ++** Version of sqlite3_free() that is always a function, never a macro. ++*/ ++static void xFree(void *p){ ++ sqlite3_free(p); ++} ++ ++/* ++** This lookup table is used to help decode the first byte of ++** a multi-byte UTF8 character. It is copied here from SQLite source ++** code file utf8.c. ++*/ ++static const unsigned char icuUtf8Trans1[] = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ++ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, ++ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, ++}; ++ ++#define SQLITE_ICU_READ_UTF8(zIn, c) \ ++ c = *(zIn++); \ ++ if( c>=0xc0 ){ \ ++ c = icuUtf8Trans1[c-0xc0]; \ ++ while( (*zIn & 0xc0)==0x80 ){ \ ++ c = (c<<6) + (0x3f & *(zIn++)); \ ++ } \ ++ } ++ ++#define SQLITE_ICU_SKIP_UTF8(zIn) \ ++ assert( *zIn ); \ ++ if( *(zIn++)>=0xc0 ){ \ ++ while( (*zIn & 0xc0)==0x80 ){zIn++;} \ ++ } ++ ++ ++/* ++** Compare two UTF-8 strings for equality where the first string is ++** a "LIKE" expression. Return true (1) if they are the same and ++** false (0) if they are different. ++*/ ++static int icuLikeCompare( ++ const uint8_t *zPattern, /* LIKE pattern */ ++ const uint8_t *zString, /* The UTF-8 string to compare against */ ++ const UChar32 uEsc /* The escape character */ ++){ ++ static const uint32_t MATCH_ONE = (uint32_t)'_'; ++ static const uint32_t MATCH_ALL = (uint32_t)'%'; ++ ++ int prevEscape = 0; /* True if the previous character was uEsc */ ++ ++ while( 1 ){ ++ ++ /* Read (and consume) the next character from the input pattern. */ ++ uint32_t uPattern; ++ SQLITE_ICU_READ_UTF8(zPattern, uPattern); ++ if( uPattern==0 ) break; ++ ++ /* There are now 4 possibilities: ++ ** ++ ** 1. uPattern is an unescaped match-all character "%", ++ ** 2. uPattern is an unescaped match-one character "_", ++ ** 3. uPattern is an unescaped escape character, or ++ ** 4. uPattern is to be handled as an ordinary character ++ */ ++ if( uPattern==MATCH_ALL && !prevEscape && uPattern!=(uint32_t)uEsc ){ ++ /* Case 1. */ ++ uint8_t c; ++ ++ /* Skip any MATCH_ALL or MATCH_ONE characters that follow a ++ ** MATCH_ALL. For each MATCH_ONE, skip one character in the ++ ** test string. ++ */ ++ while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){ ++ if( c==MATCH_ONE ){ ++ if( *zString==0 ) return 0; ++ SQLITE_ICU_SKIP_UTF8(zString); ++ } ++ zPattern++; ++ } ++ ++ if( *zPattern==0 ) return 1; ++ ++ while( *zString ){ ++ if( icuLikeCompare(zPattern, zString, uEsc) ){ ++ return 1; ++ } ++ SQLITE_ICU_SKIP_UTF8(zString); ++ } ++ return 0; ++ ++ }else if( uPattern==MATCH_ONE && !prevEscape && uPattern!=(uint32_t)uEsc ){ ++ /* Case 2. */ ++ if( *zString==0 ) return 0; ++ SQLITE_ICU_SKIP_UTF8(zString); ++ ++ }else if( uPattern==(uint32_t)uEsc && !prevEscape ){ ++ /* Case 3. */ ++ prevEscape = 1; ++ ++ }else{ ++ /* Case 4. */ ++ uint32_t uString; ++ SQLITE_ICU_READ_UTF8(zString, uString); ++ uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT); ++ uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT); ++ if( uString!=uPattern ){ ++ return 0; ++ } ++ prevEscape = 0; ++ } ++ } ++ ++ return *zString==0; ++} ++ ++/* ++** Implementation of the like() SQL function. This function implements ++** the build-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 ++** ++** is implemented as like(B, A). If there is an escape character E, ++** ++** A LIKE B ESCAPE E ++** ++** is mapped to like(B, A, E). ++*/ ++static void icuLikeFunc( ++ sqlite3_context *context, ++ int argc, ++ sqlite3_value **argv ++){ ++ const unsigned char *zA = sqlite3_value_text(argv[0]); ++ const unsigned char *zB = sqlite3_value_text(argv[1]); ++ UChar32 uEsc = 0; ++ ++ /* Limit the length of the LIKE or GLOB pattern to avoid problems ++ ** of deep recursion and N*N behavior in patternCompare(). ++ */ ++ if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){ ++ sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); ++ return; ++ } ++ ++ ++ if( argc==3 ){ ++ /* The escape character string must consist of a single UTF-8 character. ++ ** Otherwise, return an error. ++ */ ++ int nE= sqlite3_value_bytes(argv[2]); ++ const unsigned char *zE = sqlite3_value_text(argv[2]); ++ int i = 0; ++ if( zE==0 ) return; ++ U8_NEXT(zE, i, nE, uEsc); ++ if( i!=nE){ ++ sqlite3_result_error(context, ++ "ESCAPE expression must be a single character", -1); ++ return; ++ } ++ } ++ ++ if( zA && zB ){ ++ sqlite3_result_int(context, icuLikeCompare(zA, zB, uEsc)); ++ } ++} ++ ++/* ++** Function to delete compiled regexp objects. Registered as ++** a destructor function with sqlite3_set_auxdata(). ++*/ ++static void icuRegexpDelete(void *p){ ++ URegularExpression *pExpr = (URegularExpression *)p; ++ uregex_close(pExpr); ++} ++ ++/* ++** Implementation of SQLite REGEXP operator. This scalar function takes ++** two arguments. The first is a regular expression pattern to compile ++** the second is a string to match against that pattern. If either ++** argument is an SQL NULL, then NULL Is returned. Otherwise, the result ++** is 1 if the string matches the pattern, or 0 otherwise. ++** ++** SQLite maps the regexp() function to the regexp() operator such ++** that the following two are equivalent: ++** ++** zString REGEXP zPattern ++** regexp(zPattern, zString) ++** ++** Uses the following ICU regexp APIs: ++** ++** uregex_open() ++** uregex_matches() ++** uregex_close() ++*/ ++static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ ++ UErrorCode status = U_ZERO_ERROR; ++ URegularExpression *pExpr; ++ UBool res; ++ const UChar *zString = sqlite3_value_text16(apArg[1]); ++ ++ (void)nArg; /* Unused parameter */ ++ ++ /* If the left hand side of the regexp operator is NULL, ++ ** then the result is also NULL. ++ */ ++ if( !zString ){ ++ return; ++ } ++ ++ pExpr = sqlite3_get_auxdata(p, 0); ++ if( !pExpr ){ ++ const UChar *zPattern = sqlite3_value_text16(apArg[0]); ++ if( !zPattern ){ ++ return; ++ } ++ pExpr = uregex_open(zPattern, -1, 0, 0, &status); ++ ++ if( U_SUCCESS(status) ){ ++ sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete); ++ pExpr = sqlite3_get_auxdata(p, 0); ++ } ++ if( !pExpr ){ ++ icuFunctionError(p, "uregex_open", status); ++ return; ++ } ++ } ++ ++ /* Configure the text that the regular expression operates on. */ ++ uregex_setText(pExpr, zString, -1, &status); ++ if( !U_SUCCESS(status) ){ ++ icuFunctionError(p, "uregex_setText", status); ++ return; ++ } ++ ++ /* Attempt the match */ ++ res = uregex_matches(pExpr, 0, &status); ++ if( !U_SUCCESS(status) ){ ++ icuFunctionError(p, "uregex_matches", status); ++ return; ++ } ++ ++ /* Set the text that the regular expression operates on to a NULL ++ ** pointer. This is not really necessary, but it is tidier than ++ ** leaving the regular expression object configured with an invalid ++ ** pointer after this function returns. ++ */ ++ uregex_setText(pExpr, 0, 0, &status); ++ ++ /* Return 1 or 0. */ ++ sqlite3_result_int(p, res ? 1 : 0); ++} ++ ++/* ++** Implementations of scalar functions for case mapping - upper() and ++** lower(). Function upper() converts its input to upper-case (ABC). ++** Function lower() converts to lower-case (abc). ++** ++** ICU provides two types of case mapping, "general" case mapping and ++** "language specific". Refer to ICU documentation for the differences ++** between the two. ++** ++** To utilise "general" case mapping, the upper() or lower() scalar ++** functions are invoked with one argument: ++** ++** upper('ABC') -> 'abc' ++** lower('abc') -> 'ABC' ++** ++** To access ICU "language specific" case mapping, upper() or lower() ++** should be invoked with two arguments. The second argument is the name ++** of the locale to use. Passing an empty string ("") or SQL NULL value ++** as the second argument is the same as invoking the 1 argument version ++** of upper() or lower(). ++** ++** lower('I', 'en_us') -> 'i' ++** lower('I', 'tr_tr') -> '\u131' (small dotless i) ++** ++** http://www.icu-project.org/userguide/posix.html#case_mappings ++*/ ++static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ ++ const UChar *zInput; /* Pointer to input string */ ++ UChar *zOutput = 0; /* Pointer to output buffer */ ++ int nInput; /* Size of utf-16 input string in bytes */ ++ int nOut; /* Size of output buffer in bytes */ ++ int cnt; ++ int bToUpper; /* True for toupper(), false for tolower() */ ++ UErrorCode status; ++ const char *zLocale = 0; ++ ++ assert(nArg==1 || nArg==2); ++ bToUpper = (sqlite3_user_data(p)!=0); ++ if( nArg==2 ){ ++ zLocale = (const char *)sqlite3_value_text(apArg[1]); ++ } ++ ++ zInput = sqlite3_value_text16(apArg[0]); ++ if( !zInput ){ ++ return; ++ } ++ nOut = nInput = sqlite3_value_bytes16(apArg[0]); ++ if( nOut==0 ){ ++ sqlite3_result_text16(p, "", 0, SQLITE_STATIC); ++ return; ++ } ++ ++ for(cnt=0; cnt<2; cnt++){ ++ UChar *zNew = sqlite3_realloc(zOutput, nOut); ++ if( zNew==0 ){ ++ sqlite3_free(zOutput); ++ sqlite3_result_error_nomem(p); ++ return; ++ } ++ zOutput = zNew; ++ status = U_ZERO_ERROR; ++ if( bToUpper ){ ++ nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); ++ }else{ ++ nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); ++ } ++ ++ if( U_SUCCESS(status) ){ ++ sqlite3_result_text16(p, zOutput, nOut, xFree); ++ }else if( status==U_BUFFER_OVERFLOW_ERROR ){ ++ assert( cnt==0 ); ++ continue; ++ }else{ ++ icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status); ++ } ++ return; ++ } ++ assert( 0 ); /* Unreachable */ ++} ++ ++#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ ++ ++/* ++** Collation sequence destructor function. The pCtx argument points to ++** a UCollator structure previously allocated using ucol_open(). ++*/ ++static void icuCollationDel(void *pCtx){ ++ UCollator *p = (UCollator *)pCtx; ++ ucol_close(p); ++} ++ ++/* ++** Collation sequence comparison function. The pCtx argument points to ++** a UCollator structure previously allocated using ucol_open(). ++*/ ++static int icuCollationColl( ++ void *pCtx, ++ int nLeft, ++ const void *zLeft, ++ int nRight, ++ const void *zRight ++){ ++ UCollationResult res; ++ UCollator *p = (UCollator *)pCtx; ++ res = ucol_strcoll(p, (UChar *)zLeft, nLeft/2, (UChar *)zRight, nRight/2); ++ switch( res ){ ++ case UCOL_LESS: return -1; ++ case UCOL_GREATER: return +1; ++ case UCOL_EQUAL: return 0; ++ } ++ assert(!"Unexpected return value from ucol_strcoll()"); ++ return 0; ++} ++ ++/* ++** Implementation of the scalar function icu_load_collation(). ++** ++** This scalar function is used to add ICU collation based collation ++** types to an SQLite database connection. It is intended to be called ++** as follows: ++** ++** SELECT icu_load_collation(, ); ++** ++** Where is a string containing an ICU locale identifier (i.e. ++** "en_AU", "tr_TR" etc.) and is the name of the ++** collation sequence to create. ++*/ ++static void icuLoadCollation( ++ sqlite3_context *p, ++ int nArg, ++ sqlite3_value **apArg ++){ ++ sqlite3 *db = (sqlite3 *)sqlite3_user_data(p); ++ UErrorCode status = U_ZERO_ERROR; ++ const char *zLocale; /* Locale identifier - (eg. "jp_JP") */ ++ const char *zName; /* SQL Collation sequence name (eg. "japanese") */ ++ UCollator *pUCollator; /* ICU library collation object */ ++ int rc; /* Return code from sqlite3_create_collation_x() */ ++ ++ assert(nArg==2); ++ (void)nArg; /* Unused parameter */ ++ zLocale = (const char *)sqlite3_value_text(apArg[0]); ++ zName = (const char *)sqlite3_value_text(apArg[1]); ++ ++ if( !zLocale || !zName ){ ++ return; ++ } ++ ++ pUCollator = ucol_open(zLocale, &status); ++ if( !U_SUCCESS(status) ){ ++ icuFunctionError(p, "ucol_open", status); ++ return; ++ } ++ assert(p); ++ ++ rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator, ++ icuCollationColl, icuCollationDel ++ ); ++ if( rc!=SQLITE_OK ){ ++ ucol_close(pUCollator); ++ sqlite3_result_error(p, "Error registering collation function", -1); ++ } ++} ++ ++/* ++** Register the ICU extension functions with database db. ++*/ ++EXPORT_SYMBOLS SQLITE_API int sqlite3IcuInit(sqlite3 *db){ ++# define SQLITEICU_EXTRAFLAGS (SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS) ++ static const struct IcuScalar { ++ const char *zName; /* Function name */ ++ unsigned char nArg; /* Number of arguments */ ++ unsigned int enc; /* Optimal text encoding */ ++ unsigned char iContext; /* sqlite3_user_data() context */ ++ void (*xFunc)(sqlite3_context*,int,sqlite3_value**); ++ } scalars[] = { ++ {"icu_load_collation",2,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}, ++ {"lower", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, ++ {"upper", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, ++ {"upper", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, ++ {"lower", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, ++ {"lower", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, ++ {"upper", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, ++ {"upper", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, ++ {"like", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc}, ++ {"like", 3, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc}, ++#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ ++ }; ++#ifdef HARMONY_OS ++ extern void SetOhosIcuDirectory(); ++ SetOhosIcuDirectory(); ++#endif ++ int rc = SQLITE_OK; ++ int i; ++ ++ for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){ ++ const struct IcuScalar *p = &scalars[i]; ++ rc = sqlite3_create_function( ++ db, p->zName, p->nArg, p->enc, ++ p->iContext ? (void*)db : (void*)0, ++ p->xFunc, 0, 0 ++ ); ++ } ++ ++ return rc; ++} ++ ++#if !SQLITE_CORE ++#ifdef _WIN32 ++__declspec(dllexport) ++#endif ++SQLITE_API int sqlite3_icu_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ SQLITE_EXTENSION_INIT2(pApi) ++ return sqlite3IcuInit(db); ++} ++#endif ++ ++#endif ++ ++/************** End of icu.c *************************************************/ ++/************** Begin file fts3_icu.c ****************************************/ ++/* ++** 2007 June 22 ++** ++** The author disclaims copyright to this source code. In place of ++** a legal notice, here is a blessing: ++** ++** May you do good and not evil. ++** May you find forgiveness for yourself and forgive others. ++** May you share freely, never taking more than you give. ++** ++************************************************************************* ++** This file implements a tokenizer for fts3 based on the ICU library. ++*/ ++/* #include "fts3Int.h" */ ++#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) ++#ifdef SQLITE_ENABLE_ICU ++ ++/* #include */ ++/* #include */ ++/* #include "fts3_tokenizer.h" */ ++ ++#include ++/* #include */ ++/* #include */ ++#include ++ ++typedef struct IcuTokenizer IcuTokenizer; ++typedef struct IcuCursor IcuCursor; ++ ++struct IcuTokenizer { ++ sqlite3_tokenizer base; ++ char *zLocale; ++}; ++ ++struct IcuCursor { ++ sqlite3_tokenizer_cursor base; ++ ++ UBreakIterator *pIter; /* ICU break-iterator object */ ++ int nChar; /* Number of UChar elements in pInput */ ++ UChar *aChar; /* Copy of input using utf-16 encoding */ ++ int *aOffset; /* Offsets of each character in utf-8 input */ ++ ++ int nBuffer; ++ char *zBuffer; ++ ++ int iToken; ++}; ++ ++/* ++** Create a new tokenizer instance. ++*/ ++static int icuCreate( ++ int argc, /* Number of entries in argv[] */ ++ const char * const *argv, /* Tokenizer creation arguments */ ++ sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ ++){ ++ IcuTokenizer *p; ++ int n = 0; ++ ++ if( argc>0 ){ ++ n = strlen(argv[0])+1; ++ } ++ p = (IcuTokenizer *)sqlite3_malloc64(sizeof(IcuTokenizer)+n); ++ if( !p ){ ++ return SQLITE_NOMEM; ++ } ++ memset(p, 0, sizeof(IcuTokenizer)); ++ ++ if( n ){ ++ p->zLocale = (char *)&p[1]; ++ memcpy(p->zLocale, argv[0], n); ++ } ++ ++ *ppTokenizer = (sqlite3_tokenizer *)p; ++ ++ return SQLITE_OK; ++} ++ ++/* ++** Destroy a tokenizer ++*/ ++static int icuDestroy(sqlite3_tokenizer *pTokenizer){ ++ IcuTokenizer *p = (IcuTokenizer *)pTokenizer; ++ sqlite3_free(p); ++ return SQLITE_OK; ++} ++ ++/* ++** Prepare to begin tokenizing a particular string. The input ++** string to be tokenized is pInput[0..nBytes-1]. A cursor ++** used to incrementally tokenize this string is returned in ++** *ppCursor. ++*/ ++static int icuOpen( ++ sqlite3_tokenizer *pTokenizer, /* The tokenizer */ ++ const char *zInput, /* Input string */ ++ int nInput, /* Length of zInput in bytes */ ++ sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ ++){ ++ IcuTokenizer *p = (IcuTokenizer *)pTokenizer; ++ IcuCursor *pCsr; ++ ++ const int32_t opt = U_FOLD_CASE_DEFAULT; ++ UErrorCode status = U_ZERO_ERROR; ++ int nChar; ++ ++ UChar32 c; ++ int iInput = 0; ++ int iOut = 0; ++ ++ *ppCursor = 0; ++ ++ if( zInput==0 ){ ++ nInput = 0; ++ zInput = ""; ++ }else if( nInput<0 ){ ++ nInput = strlen(zInput); ++ } ++ nChar = nInput+1; ++ pCsr = (IcuCursor *)sqlite3_malloc64( ++ sizeof(IcuCursor) + /* IcuCursor */ ++ ((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */ ++ (nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */ ++ ); ++ if( !pCsr ){ ++ return SQLITE_NOMEM; ++ } ++ memset(pCsr, 0, sizeof(IcuCursor)); ++ pCsr->aChar = (UChar *)&pCsr[1]; ++ pCsr->aOffset = (int *)&pCsr->aChar[(nChar+3)&~3]; ++ ++ pCsr->aOffset[iOut] = iInput; ++ U8_NEXT(zInput, iInput, nInput, c); ++ while( c>0 ){ ++ int isError = 0; ++ c = u_foldCase(c, opt); ++ U16_APPEND(pCsr->aChar, iOut, nChar, c, isError); ++ if( isError ){ ++ sqlite3_free(pCsr); ++ return SQLITE_ERROR; ++ } ++ pCsr->aOffset[iOut] = iInput; ++ ++ if( iInputpIter = ubrk_open(UBRK_WORD, p->zLocale, pCsr->aChar, iOut, &status); ++ if( !U_SUCCESS(status) ){ ++ sqlite3_free(pCsr); ++ return SQLITE_ERROR; ++ } ++ pCsr->nChar = iOut; ++ ++ ubrk_first(pCsr->pIter); ++ *ppCursor = (sqlite3_tokenizer_cursor *)pCsr; ++ return SQLITE_OK; ++} ++ ++/* ++** Close a tokenization cursor previously opened by a call to icuOpen(). ++*/ ++static int icuClose(sqlite3_tokenizer_cursor *pCursor){ ++ IcuCursor *pCsr = (IcuCursor *)pCursor; ++ ubrk_close(pCsr->pIter); ++ sqlite3_free(pCsr->zBuffer); ++ sqlite3_free(pCsr); ++ return SQLITE_OK; ++} ++ ++/* ++** Extract the next token from a tokenization cursor. ++*/ ++static int icuNext( ++ sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by simpleOpen */ ++ const char **ppToken, /* OUT: *ppToken is the token text */ ++ int *pnBytes, /* OUT: Number of bytes in token */ ++ int *piStartOffset, /* OUT: Starting offset of token */ ++ int *piEndOffset, /* OUT: Ending offset of token */ ++ int *piPosition /* OUT: Position integer of token */ ++){ ++ IcuCursor *pCsr = (IcuCursor *)pCursor; ++ ++ int iStart = 0; ++ int iEnd = 0; ++ int nByte = 0; ++ ++ while( iStart==iEnd ){ ++ UChar32 c; ++ ++ iStart = ubrk_current(pCsr->pIter); ++ iEnd = ubrk_next(pCsr->pIter); ++ if( iEnd==UBRK_DONE ){ ++ return SQLITE_DONE; ++ } ++ ++ while( iStartaChar, iWhite, pCsr->nChar, c); ++ if( u_isspace(c) ){ ++ iStart = iWhite; ++ }else{ ++ break; ++ } ++ } ++ assert(iStart<=iEnd); ++ } ++ ++ do { ++ UErrorCode status = U_ZERO_ERROR; ++ if( nByte ){ ++ char *zNew = sqlite3_realloc(pCsr->zBuffer, nByte); ++ if( !zNew ){ ++ return SQLITE_NOMEM; ++ } ++ pCsr->zBuffer = zNew; ++ pCsr->nBuffer = nByte; ++ } ++ ++ u_strToUTF8( ++ pCsr->zBuffer, pCsr->nBuffer, &nByte, /* Output vars */ ++ &pCsr->aChar[iStart], iEnd-iStart, /* Input vars */ ++ &status /* Output success/failure */ ++ ); ++ } while( nByte>pCsr->nBuffer ); ++ ++ *ppToken = pCsr->zBuffer; ++ *pnBytes = nByte; ++ *piStartOffset = pCsr->aOffset[iStart]; ++ *piEndOffset = pCsr->aOffset[iEnd]; ++ *piPosition = pCsr->iToken++; ++ ++ return SQLITE_OK; ++} ++ ++/* ++** The set of routines that implement the simple tokenizer ++*/ ++static const sqlite3_tokenizer_module icuTokenizerModule = { ++ 0, /* iVersion */ ++ icuCreate, /* xCreate */ ++ icuDestroy, /* xCreate */ ++ icuOpen, /* xOpen */ ++ icuClose, /* xClose */ ++ icuNext, /* xNext */ ++ 0, /* xLanguageid */ ++}; ++ ++/* ++** Set *ppModule to point at the implementation of the ICU tokenizer. ++*/ ++EXPORT_SYMBOLS SQLITE_API void sqlite3Fts3IcuTokenizerModule( ++ sqlite3_tokenizer_module const**ppModule ++){ ++ *ppModule = &icuTokenizerModule; ++} ++ ++#endif /* defined(SQLITE_ENABLE_ICU) */ ++#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ ++ ++/************** End of fts3_icu.c ********************************************/ +-- +2.47.0.windows.2 + diff --git a/patch/0005-corrupt-detect.patch b/patch/0005-corrupt-detect.patch new file mode 100644 index 0000000..9452740 --- /dev/null +++ b/patch/0005-corrupt-detect.patch @@ -0,0 +1,1216 @@ +From 5a74b245cf3fb022f165e4dcd2524f11fdd054b3 Mon Sep 17 00:00:00 2001 +From: wanghaishuo +Date: Sat, 12 Apr 2025 10:53:34 +0800 +Subject: [PATCH 5/7] corrupt detect + +Signed-off-by: ryne3366 +--- + src/sqlite3.c | 649 +++++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 563 insertions(+), 86 deletions(-) + +diff --git a/src/sqlite3.c b/src/sqlite3.c +index dd89c5a..ad7ce74 100644 +--- a/src/sqlite3.c ++++ b/src/sqlite3.c +@@ -2459,6 +2459,7 @@ struct sqlite3_mem_methods { + #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ + #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ + #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ ++#define SQLITE_CONFIG_CORRUPTION 30 /* xCorruption */ + #define SQLITE_CONFIG_ENABLE_ICU 31 /* boolean */ + /* + ** CAPI3REF: Database Connection Configuration Options +@@ -19554,6 +19555,8 @@ struct Sqlite3Config { + int iOnceResetThreshold; /* When to reset OP_Once counters */ + u32 szSorterRef; /* Min size in bytes to use sorter-refs */ + unsigned int iPrngSeed; /* Alternative fixed seed for the PRNG */ ++ void (*xCorruption)(void *, const void *); ++ void *pCorruptionArg; + /* vvvv--- must be last ---vvv */ + #ifdef SQLITE_DEBUG + sqlite3_int64 aTune[SQLITE_NTUNE]; /* Tuning parameters */ +@@ -19805,6 +19808,57 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprLis + } \ + } + ++#define SQLITE_PRINT_CORRUPT_SIZE (SQLITE_PRINT_BUF_SIZE * 2) ++ ++#define SQLITE_CORRUPT_CONTEXT(N,P,T,O,S,M,R) \ ++ { .nPage=(N), .pgno=(P), .type=(T), \ ++ .zoneRange={(O),(S)}, .zMsg=(M), .reservedArgs=(R) } ++ ++typedef struct { ++ int offset; ++ size_t size; ++}sqlite3CorruptRange; ++ ++typedef enum { ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ CORRUPT_TYPE_PAGE_BTREE_INTERIOR, ++ CORRUPT_TYPE_PAGE_INDEX_LEAF, ++ CORRUPT_TYPE_PAGE_INDEX_INTERIOR, ++ CORRUPT_TYPE_PAGE_OVERFLOW, ++ CORRUPT_TYPE_PAGE_PTR_MAP, ++ CORRUPT_TYPE_PAGE_FREE_LIST, ++ CORRUPT_TYPE_FRAME_WAL, ++ CORRUPT_TYPE_ENTRY_JOURNAL, ++ CORRUPT_TYPE_VDBE, ++ CORRUPT_TYPE_FILE_HEADER, ++ CORRUPT_TYPE_UNKOWN, ++} CorruptType; ++ ++typedef struct { ++ size_t nPage; /* Number of pages */ ++ unsigned int pgno; /* Page number for corrupted page */ ++ CorruptType type; ++ sqlite3CorruptRange zoneRange; ++ const char *zMsg; ++ void *reservedArgs; ++}sqlite3CorruptContext; ++ ++// Encode buffer with base16, return size after encode ++static size_t sqlite3base16Encode(const unsigned char *buffer, size_t bufSize, char *encodeBuf, size_t encodeBufSize) ++{ ++ if (buffer == NULL || bufSize == 0 || encodeBuf == NULL || encodeBufSize == 0) { ++ return 0; ++ } ++ static const char base16Code[] = "0123456789ABCDEF"; ++ size_t i = 0; ++ for (; i < bufSize && (i * 2 < encodeBufSize - 1); i++) { ++ *encodeBuf++ = base16Code[(buffer[i] >> 4) & 0x0F]; ++ *encodeBuf++ = base16Code[buffer[i] & 0x0F]; ++ } ++ *encodeBuf = '\0'; ++ return i * 2; ++} ++ + /* + ** The SQLITE_*_BKPT macros are substitutes for the error codes with + ** the same name but without the _BKPT suffix. These macros invoke +@@ -19813,10 +19867,11 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprLis + ** to set a debugger breakpoint. + */ + SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType); +-SQLITE_PRIVATE int sqlite3CorruptError(int); ++SQLITE_PRIVATE int sqlite3CorruptError(int lineno, sqlite3CorruptContext *context); + SQLITE_PRIVATE int sqlite3MisuseError(int); + SQLITE_PRIVATE int sqlite3CantopenError(int); +-#define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__) ++#define SQLITE_CORRUPT_REPORT(context) sqlite3CorruptError(__LINE__,(context)) ++#define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__,NULL) + #define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__) + #define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__) + #ifdef SQLITE_DEBUG +@@ -19828,12 +19883,13 @@ SQLITE_PRIVATE int sqlite3IoerrnomemError(int); + # define SQLITE_NOMEM_BKPT SQLITE_NOMEM + # define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM + #endif +-#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO) ++#if (defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO)) + SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno); +-# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P)) ++# define SQLITE_CORRUPT_PGNO(P,context) sqlite3CorruptPgnoError(__LINE__,(P)) + #else +-# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__) ++# define SQLITE_CORRUPT_PGNO(P,context) sqlite3CorruptError(__LINE__,(context)) + #endif ++# define SQLITE_CORRUPT_REPORT_PGNO(context) SQLITE_CORRUPT_PGNO((context)->pgno,(context)) + + /* + ** FTS3 and FTS4 both require virtual table support +@@ -22312,6 +22368,8 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { + 0x7ffffffe, /* iOnceResetThreshold */ + SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */ + 0, /* iPrngSeed */ ++ 0, /* xCorruption */ ++ 0, /* pCorruptionArg */ + #ifdef SQLITE_DEBUG + {0,0,0,0,0,0} /* aTune */ + #endif +@@ -58784,7 +58842,7 @@ static int readDbPage(PgHdr *pPg){ + assert( isOpen(pPager->fd) ); + + if( pagerUseWal(pPager) ){ +- rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); ++ rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); // find in wal-index + if( rc ) return rc; + } + if( iFrame ){ +@@ -61324,7 +61382,12 @@ static int getPageNormal( + assert( assert_pager_state(pPager) ); + assert( pPager->hasHeldSharedLock==1 ); + +- if( pgno==0 ) return SQLITE_CORRUPT_BKPT; ++ if( pgno==0 ) { ++ const char *zMsg = "pgno should not be 0"; ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, 0, CORRUPT_TYPE_UNKOWN, ++ -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_REPORT(&context); ++ } + pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3); + if( pBase==0 ){ + pPg = 0; +@@ -61356,7 +61419,11 @@ static int getPageNormal( + ** (2) Never try to fetch the locking page + */ + if( pgno==PAGER_SJ_PGNO(pPager) ){ +- rc = SQLITE_CORRUPT_BKPT; ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "try fetching the locking page(%u)", pgno); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, pgno, CORRUPT_TYPE_UNKOWN, ++ -1, 0, zMsg, NULL); ++ rc = SQLITE_CORRUPT_REPORT(&context); + goto pager_acquire_err; + } + +@@ -61438,7 +61505,10 @@ static int getPageMMap( + ** test in the previous statement, and avoid testing pgno==0 in the + ** common case where pgno is large. */ + if( pgno<=1 && pgno==0 ){ +- return SQLITE_CORRUPT_BKPT; ++ const char *zMsg = "pgno should not be 0"; ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, 0, CORRUPT_TYPE_UNKOWN, ++ -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_REPORT(&context); + } + assert( pPager->eState>=PAGER_READER ); + assert( assert_pager_state(pPager) ); +@@ -63024,7 +63094,11 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i + if( pPgOld ){ + if( NEVER(pPgOld->nRef>1) ){ + sqlite3PagerUnrefNotNull(pPgOld); +- return SQLITE_CORRUPT_BKPT; ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "page(%u) should be no references, ref cnt:%d", pgno, (int)pPgOld->nRef); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, pgno, CORRUPT_TYPE_UNKOWN, ++ -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_REPORT(&context); + } + pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); + if( pPager->tempFile ){ +@@ -64792,7 +64866,13 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ + /* Write the aPgno[] array entry and the hash-table slot. */ + nCollide = idx; + for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ +- if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT; ++ if( (nCollide--)==0 ){ ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "no place for page(%u) to map into WAL, idx:%d", iPage, idx); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, iPage, CORRUPT_TYPE_FRAME_WAL, ++ -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_REPORT(&context); ++ } + } + sLoc.aPgno[idx-1] = iPage; + AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx); +@@ -65745,7 +65825,13 @@ static int walCheckpoint( + ** database plus the amount of data in the wal file, plus the + ** maximum size of the pending-byte page (65536 bytes), then + ** must be corruption somewhere. */ +- rc = SQLITE_CORRUPT_BKPT; ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, ++ "final db size unexpected,nSize=%lld,mxFrame=%u,pageSize=%d,nReq=%lld", ++ nSize, pWal->hdr.mxFrame, szPage, nReq); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, 0, CORRUPT_TYPE_FRAME_WAL, ++ -1, 0, zMsg, NULL); ++ rc = SQLITE_CORRUPT_REPORT(&context); + }else{ + sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT,&nReq); + } +@@ -66856,7 +66942,11 @@ SQLITE_PRIVATE int sqlite3WalFindFrame( + iRead = iFrame; + } + if( (nCollide--)==0 ){ +- return SQLITE_CORRUPT_BKPT; ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "mis-match page(%u) to map into WAL", pgno); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, pgno, CORRUPT_TYPE_FRAME_WAL, ++ -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_REPORT(&context); + } + iKey = walNextHash(iKey); + } +@@ -67597,7 +67687,12 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( + if( rc==SQLITE_OK ){ + + if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ +- rc = SQLITE_CORRUPT_BKPT; ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "mis-match between pageSize=%d and bufferSize=%d, mxFrame=%u", ++ walPagesize(pWal),nBuf,pWal->hdr.mxFrame); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, 0, CORRUPT_TYPE_FRAME_WAL, ++ -1, 0, zMsg, NULL); ++ rc = SQLITE_CORRUPT_REPORT(&context); + }else{ + sqlite3_int64 startTime; + sqlite3OsCurrentTimeInt64(db->pVfs, &startTime); +@@ -69055,7 +69150,7 @@ static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf){ + ** with the page number and filename associated with the (MemPage*). + */ + #ifdef SQLITE_DEBUG +-int corruptPageError(int lineno, MemPage *p){ ++int corruptPageError(int lineno, MemPage *p, sqlite3CorruptContext *context){ + char *zMsg; + sqlite3BeginBenignMalloc(); + zMsg = sqlite3_mprintf("database corruption page %d of %s", +@@ -69066,11 +69161,11 @@ int corruptPageError(int lineno, MemPage *p){ + sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg); + } + sqlite3_free(zMsg); +- return SQLITE_CORRUPT_BKPT; ++ return SQLITE_CORRUPT_REPORT(context); + } +-# define SQLITE_CORRUPT_PAGE(pMemPage) corruptPageError(__LINE__, pMemPage) ++# define SQLITE_CORRUPT_PAGE(context,pMemPage) corruptPageError(__LINE__, (pMemPage),(context)) + #else +-# define SQLITE_CORRUPT_PAGE(pMemPage) SQLITE_CORRUPT_PGNO(pMemPage->pgno) ++# define SQLITE_CORRUPT_PAGE(context,pMemPage) SQLITE_CORRUPT_PGNO((pMemPage)->pgno,(context)) + #endif + + #ifndef SQLITE_OMIT_SHARED_CACHE +@@ -69748,7 +69843,12 @@ static int btreeMoveto( + if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT; + sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey); + if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){ +- rc = SQLITE_CORRUPT_BKPT; ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpected fields in total:%u, should != 0 and < %u", ++ pIdxKey->nField,pKeyInfo->nAllField); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pCur->pBt->nPage, 0, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ -1, 0, zMsg, NULL); ++ rc = SQLITE_CORRUPT_REPORT(&context); + }else{ + rc = sqlite3BtreeIndexMoveto(pCur, pIdxKey, pRes); + } +@@ -69928,7 +70028,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ + assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) ); + + assert( pBt->autoVacuum ); +- if( key==0 ){ ++ if( key==0 ){ // The pgno of each entry on ptrmap page starts from 3, an unexpected pgno indicates data corrupted + *pRC = SQLITE_CORRUPT_BKPT; + return; + } +@@ -69942,12 +70042,24 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ + /* The first byte of the extra data is the MemPage.isInit byte. + ** If that byte is set, it means this page is also being used + ** as a btree page. */ +- *pRC = SQLITE_CORRUPT_BKPT; ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode((unsigned char *)sqlite3PagerGetExtra(pDbPage), 8, xBuffer, sizeof(xBuffer)); ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "page(%u) been initialized before as a btree page, base16:%s", ++ iPtrmap, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, ++ -1, 0, zMsg, NULL); ++ *pRC = SQLITE_CORRUPT_REPORT(&context); + goto ptrmap_exit; + } + offset = PTRMAP_PTROFFSET(iPtrmap, key); + if( offset<0 ){ +- *pRC = SQLITE_CORRUPT_BKPT; ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpect offset in ptrmap page(%u), target:%u, page usableSize=%u", ++ iPtrmap, key, pBt->usableSize); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, ++ -1, 0, zMsg, NULL); ++ *pRC = SQLITE_CORRUPT_REPORT(&context); + goto ptrmap_exit; + } + assert( offset <= (int)pBt->usableSize-5 ); +@@ -69992,7 +70104,12 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ + offset = PTRMAP_PTROFFSET(iPtrmap, key); + if( offset<0 ){ + sqlite3PagerUnref(pDbPage); +- return SQLITE_CORRUPT_BKPT; ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpect offset in ptrmap page(%d), target:%u, page usableSize=%u", ++ iPtrmap, key, pBt->usableSize); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, ++ -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_REPORT(&context); + } + assert( offset <= (int)pBt->usableSize-5 ); + assert( pEType!=0 ); +@@ -70000,7 +70117,15 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ + if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); + + sqlite3PagerUnref(pDbPage); +- if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_PGNO(iPtrmap); ++ if( *pEType<1 || *pEType>5 ){ ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; // 5 bytes for each entry on ptrmap page ++ (void)sqlite3base16Encode(pPtrmap, 5, xBuffer, sizeof(xBuffer)); ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpect entry type:%d, base16:%s", (int)*pEType, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, ++ offset, 5, zMsg, NULL); ++ return SQLITE_CORRUPT_REPORT_PGNO(&context); ++ } + return SQLITE_OK; + } + +@@ -70392,7 +70517,14 @@ static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){ + Pgno ovfl; + if( SQLITE_WITHIN(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){ + testcase( pSrc!=pPage ); +- *pRC = SQLITE_CORRUPT_BKPT; ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; // Output cell header as much as possible, 4 bytes for overflow pgno ++ (void)sqlite3base16Encode(pCell, info.nSize - info.nLocal - 4, xBuffer, sizeof(xBuffer)); ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell overflow, offset=%d, rest=%d, length=%u, base16:%s", ++ (int)(pCell - pPage->aData), (int)(pSrc->aDataEnd - pCell), info.nSize, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ pCell - pPage->aData, info.nSize, zMsg, NULL); ++ *pRC = SQLITE_CORRUPT_REPORT(&context); + return; + } + ovfl = get4byte(&pCell[info.nSize-4]); +@@ -70450,10 +70582,29 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ + ** reconstruct the entire page. */ + if( (int)data[hdr+7]<=nMaxFrag ){ + int iFree = get2byte(&data[hdr+1]); +- if( iFree>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); ++ if( iFree>usableSize-4 ){ ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Output first 8 bytes as it's page header ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset=%d overflow, usableSize=%d, base16:%s", ++ iFree, usableSize, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ 0, 8, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); ++ } + if( iFree ){ + int iFree2 = get2byte(&data[iFree]); +- if( iFree2>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); ++ if( iFree2>usableSize-4 ){ ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode(data, 4, xBuffer, sizeof(xBuffer)); // Output first freeblock's header 4 bytes ++ sqlite3_snprintf(sizeof(zMsg), zMsg, ++ "1st freeblock's next pointer overflow, point:%d, usableSize=%d, base16:%s", ++ iFree2, usableSize, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ iFree, 4, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); ++ } + if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){ + u8 *pEnd = &data[cellOffset + nCell*2]; + u8 *pAddr; +@@ -70461,16 +70612,51 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ + int sz = get2byte(&data[iFree+2]); + int top = get2byte(&data[hdr+5]); + if( top>=iFree ){ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Print first 8 bytes which is page header ++ sqlite3_snprintf(sizeof(zMsg), zMsg, ++ "1st freeblock's offset:%d should > CellContentArea's offset:%d, base16:%s", ++ iFree, top, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ iFree, 8, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + if( iFree2 ){ +- if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PAGE(pPage); ++ if( iFree+sz>iFree2 ){ ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Print first 8 bytes which is page header ++ sqlite3_snprintf(sizeof(zMsg), zMsg, ++ "the 1st 2 freeblocks mis-order, 1st block offset:%d, size:%d, 2nd block offset:%d, base16:%s", ++ iFree, sz, iFree2, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ iFree, 4, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); ++ } + sz2 = get2byte(&data[iFree2+2]); +- if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage); ++ if( iFree2+sz2 > usableSize ){ ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode(data + iFree2, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to 2nd block ++ sqlite3_snprintf(sizeof(zMsg), zMsg, ++ "the 2nd freeblock overflow, offset:%d, size:%d, usableSize:%d, base16:%s", ++ iFree2, sz2, usableSize, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ iFree2, 4, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); ++ } + memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); + sz += sz2; + }else if( iFree+sz>usableSize ){ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode(data + iFree, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to 1st block ++ sqlite3_snprintf(sizeof(zMsg), zMsg, ++ "the 1st freeblock overflow, offset:%d, size:%d, usableSize:%d, base16:%s", iFree, sz, usableSize, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ iFree, 4, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + + cbrk = top+sz; +@@ -70503,13 +70689,24 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ + ** if PRAGMA cell_size_check=ON. + */ + if( pciCellLast ){ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; // Print 4 bytes belong to 1st block ++ (void)sqlite3base16Encode(data + cellOffset + i*2, 2, xBuffer, sizeof(xBuffer)); ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "%d-th cell pointer:%d out of range[%d, %d], base16:%s", ++ i, pc, iCellStart, iCellLast, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ cellOffset + i*2, 2, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + assert( pc>=iCellStart && pc<=iCellLast ); + size = pPage->xCellSize(pPage, &src[pc]); + cbrk -= size; + if( cbrkusableSize ){ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "move %d-th cell from %d using unexpected size:%d", i, pc, size); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + assert( cbrk+size<=usableSize && cbrk>=iCellStart ); + testcase( cbrk+size==usableSize ); +@@ -70523,7 +70720,13 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ + defragment_out: + assert( pPage->nFree>=0 ); + if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, ++ "after defragment, free bytes should not change, fragment bytes:%d, free space:%d, total:%d", ++ (int)data[hdr+7], cbrk-iCellFirst, pPage->nFree); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + assert( cbrk>=iCellFirst ); + put2byte(&data[hdr+5], cbrk); +@@ -70548,7 +70751,7 @@ defragment_out: + ** will be ignored if adding the extra space to the fragmentation count + ** causes the fragmentation count to exceed 60. + */ +-static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ ++static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ // search on B-tree page + const int hdr = pPg->hdrOffset; /* Offset to page header */ + u8 * const aData = pPg->aData; /* Page data */ + int iAddr = hdr + 1; /* Address of ptr to pc */ +@@ -70580,7 +70783,15 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ + return &aData[pc]; + }else if( x+pc > maxPC ){ + /* This slot extends off the end of the usable part of the page */ +- *pRc = SQLITE_CORRUPT_PAGE(pPg); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode(aData + pc, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to free block ++ sqlite3_snprintf(sizeof(zMsg), zMsg, ++ "freeblock rest bytes:%d begin at %d which cost %d, still exceed usableSize:%u, base16:%s", ++ x, pc, nByte, pPg->pBt->usableSize, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPg->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ pc, 4, zMsg, NULL); ++ *pRc = SQLITE_CORRUPT_PAGE(&context, pPg); + return 0; + }else{ + /* The slot remains on the free-list. Reduce its size to account +@@ -70595,14 +70806,25 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ + if( pc<=iAddr ){ + if( pc ){ + /* The next slot in the chain comes before the current slot */ +- *pRc = SQLITE_CORRUPT_PAGE(pPg); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode(pTmp, 2, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to free block ++ sqlite3_snprintf(sizeof(zMsg), zMsg, ++ "the next slot:%d in chain comes before current slot:%d, base16:%s", pc, iAddr, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPg->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ iAddr, 2, zMsg, NULL); ++ *pRc = SQLITE_CORRUPT_PAGE(&context, pPg); + } + return 0; + } + } + if( pc>maxPC+nByte-4 ){ + /* The free slot chain extends off the end of the page */ +- *pRc = SQLITE_CORRUPT_PAGE(pPg); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "free slot:%d overflow, end:%d", pc, maxPC+nByte-4); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPg->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ -1, 0, zMsg, NULL); ++ *pRc = SQLITE_CORRUPT_PAGE(&context, pPg); + } + return 0; + } +@@ -70651,7 +70873,13 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ + if( top==0 && pPage->pBt->usableSize==65536 ){ + top = 65536; + }else{ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Print 8 bytes belong to page header ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpected cellContentArea offset:%d, base16:%s", top, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + } + +@@ -70669,7 +70897,11 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ + assert( pSpace+nByte<=data+pPage->pBt->usableSize ); + *pIdx = g2 = (int)(pSpace-data); + if( g2<=gap ){ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "cellpointers(end:%d) overlap with freeblock(%d)", gap, g2); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + }else{ + return SQLITE_OK; + } +@@ -70748,12 +70980,23 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ + while( (iFreeBlk = get2byte(&data[iPtr]))pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + iPtr = iFreeBlk; + } + if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode(data + iPtr, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to freeblock ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset:%d overflow, base16:%s", (int)iFreeBlk, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, iPtr, 4, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + assert( iFreeBlk>iPtr || iFreeBlk==0 || CORRUPT_DB ); + +@@ -70765,10 +71008,24 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ + */ + if( iFreeBlk && iEnd+3>=iFreeBlk ){ + nFrag = iFreeBlk - iEnd; +- if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage); ++ if( iEnd>iFreeBlk ){ ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset:%d overlaps with pre block's end:%u", ++ (int)iFreeBlk, iEnd); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); ++ } + iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]); + if( iEnd > pPage->pBt->usableSize ){ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode(data + iFreeBlk, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to freeblock ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset:%d, end:%u overflow, usableSize:%u, base16:%s", ++ (int)iFreeBlk, iEnd, pPage->pBt->usableSize, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, iFreeBlk, 4, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + iSize = iEnd - iStart; + iFreeBlk = get2byte(&data[iFreeBlk]); +@@ -70781,13 +71038,27 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ + if( iPtr>hdr+1 ){ + int iPtrEnd = iPtr + get2byte(&data[iPtr+2]); + if( iPtrEnd+3>=iStart ){ +- if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PAGE(pPage); ++ if( iPtrEnd>iStart ){ ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "check pre freeblock end:%d overlaps with the pending free block:%d", ++ iPtrEnd, (int)iStart); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, iPtr, iPtrEnd - iPtr, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); ++ } + nFrag += iStart - iPtrEnd; + iSize = iEnd - iPtr; + iStart = iPtr; + } + } +- if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage); ++ if( nFrag>data[hdr+7] ){ ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "fragment free bytes:%d increase unexpectly, should be %d", ++ (int)nFrag, (int)data[hdr+7]); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); ++ } + data[hdr+7] -= nFrag; + } + pTmp = &data[hdr+5]; +@@ -70796,8 +71067,21 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ + /* The new freeblock is at the beginning of the cell content area, + ** so just extend the cell content area rather than create another + ** freelist entry */ +- if( iStart= the beginning of the CellContentArea:%d", (int)x, (int)iStart); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); ++ } ++ if( iPtr!=hdr+1 ){ ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "1st freeblock's pos incorrect, hdr:%d, iPtr:%d", (int)hdr, (int)iPtr); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); ++ } + put2byte(&data[hdr+1], iFreeBlk); + put2byte(&data[hdr+5], iEnd); + }else{ +@@ -70882,7 +71166,13 @@ static int decodeFlags(MemPage *pPage, int flagByte){ + pPage->pgno, flagByte, pPage->isInit, pPage->intKey, pPage->intKeyLeaf, pPage->leaf, + pPage->childPtrSize, pPage->cellOffset, pPage->nCell, pPage->hdrOffset, pPage->minLocal, pPage->maxLocal, g_lastCkptTime); + #endif /* LOG_DUMP */ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode(pPage->aData, 8, xBuffer, sizeof(xBuffer)); ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "unrecognized flag:%d, base16:%s", flagByte, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + pPage->max1bytePayload = pBt->max1bytePayload; + return SQLITE_OK; +@@ -70933,12 +71223,20 @@ static int btreeComputeFreeSpace(MemPage *pPage){ + /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will + ** always be at least one cell before the first freeblock. + */ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "the 1st freeblock:%d before all cells:%d", pc, top); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + while( 1 ){ + if( pc>iCellLast ){ + /* Freeblock off the end of the page */ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock end:%d out of page range:%d", pc, iCellLast); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + next = get2byte(&data[pc]); + size = get2byte(&data[pc+2]); +@@ -70948,11 +71246,19 @@ static int btreeComputeFreeSpace(MemPage *pPage){ + } + if( next>0 ){ + /* Freeblock not in ascending order */ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "all freeblocks should order by asc, pre:%d, cur:%u", pc, next); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + if( pc+size>(unsigned int)usableSize ){ + /* Last freeblock extends past page end */ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "last freeblock overflow, offset:%d, size:%u", pc, size); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + } + +@@ -70964,7 +71270,13 @@ static int btreeComputeFreeSpace(MemPage *pPage){ + ** area, according to the page header, lies within the page. + */ + if( nFree>usableSize || nFreepBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + pPage->nFree = (u16)(nFree - iCellFirst); + return SQLITE_OK; +@@ -70995,12 +71307,20 @@ static SQLITE_NOINLINE int btreeCellSizeCheck(MemPage *pPage){ + testcase( pc==iCellFirst ); + testcase( pc==iCellLast ); + if( pciCellLast ){ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell pointer:%d indicate out of range:[%d, %d]", pc, iCellFirst, iCellLast); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + sz = pPage->xCellSize(pPage, &data[pc]); + testcase( pc+sz==usableSize ); + if( pc+sz>usableSize ){ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpected cell size:%d,offset:%d, out of range:%d", sz, pc, usableSize); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + } + return SQLITE_OK; +@@ -71032,7 +71352,7 @@ static int btreeInitPage(MemPage *pPage){ + /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating + ** the b-tree page type. */ + if( decodeFlags(pPage, data[0]) ){ +- return SQLITE_CORRUPT_PAGE(pPage); ++ return SQLITE_CORRUPT_PAGE(NULL, pPage); + } + assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); + pPage->maskPage = (u16)(pBt->pageSize - 1); +@@ -71046,7 +71366,12 @@ static int btreeInitPage(MemPage *pPage){ + pPage->nCell = get2byte(&data[3]); + if( pPage->nCell>MX_CELL(pBt) ){ + /* To many cells for a single page. The page must be corrupt */ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "too many cells(%d) for the page:%u, offset:%d, out of range:%u", ++ (int)pPage->nCell, pPage->pgno, (int)pPage->hdrOffset + 3, MX_CELL(pBt)); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + testcase( pPage->nCell==MX_CELL(pBt) ); + /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only +@@ -71201,7 +71526,11 @@ static int getAndInitPage( + assert( pCur==0 || pCur->iPage>0 ); + + if( pgno>btreePagecount(pBt) ){ +- rc = SQLITE_CORRUPT_BKPT; ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "page number(%u) > db file size(%u)", pgno, btreePagecount(pBt)); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ -1, 0, zMsg, NULL); ++ rc = SQLITE_CORRUPT_REPORT(&context); + goto getAndInitPage_error1; + } + rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly); +@@ -71222,7 +71551,12 @@ static int getAndInitPage( + /* 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); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "check btree page, nCell:%u, intKey:%u, cursor->curIntKey:%u", ++ (*ppPage)->nCell, (*ppPage)->intKey, pCur->curIntKey); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ -1, 0, zMsg, NULL); ++ rc = SQLITE_CORRUPT_REPORT_PGNO(&context); + goto getAndInitPage_error2; + } + return SQLITE_OK; +@@ -72656,7 +72990,12 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ + if( eType==PTRMAP_OVERFLOW2 ){ + /* The pointer is always the first 4 bytes of the page in this case. */ + if( get4byte(pPage->aData)!=iFrom ){ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "1st 4 bytes of ovrflow page(%u) point to next(%u), should be %u", ++ pPage->pgno, get4byte(pPage->aData), iFrom); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_PTR_MAP, ++ 0, 4, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + put4byte(pPage->aData, iTo); + }else{ +@@ -72675,7 +73014,13 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ + pPage->xParseCell(pPage, pCell, &info); + if( info.nLocal pPage->aData+pPage->pBt->usableSize ){ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, ++ "btree cell contain ovrflow pointer overflow, offset:%d, size:%u, usableSize:%u", ++ (int)(pCell - pPage->aData), info.nSize, pPage->pBt->usableSize); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_PTR_MAP, pCell - pPage->aData, info.nSize, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + if( iFrom==get4byte(pCell+info.nSize-4) ){ + put4byte(pCell+info.nSize-4, iTo); +@@ -72684,7 +73029,13 @@ 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); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, ++ "btree cell contain child pointer overflow, offset:%d, size:4, usableSize:%u", ++ (int)(pCell - pPage->aData), pPage->pBt->usableSize); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_PTR_MAP, pCell - pPage->aData, 4, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + if( get4byte(pCell)==iFrom ){ + put4byte(pCell, iTo); +@@ -72696,7 +73047,11 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ + if( i==nCell ){ + if( eType!=PTRMAP_BTREE || + get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "missing pointer point to overflow page on btree page(%u)", pPage->pgno); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + put4byte(&pPage->aData[pPage->hdrOffset+8], iTo); + } +@@ -72829,7 +73184,11 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){ + return rc; + } + if( eType==PTRMAP_ROOTPAGE ){ +- return SQLITE_CORRUPT_BKPT; ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "try vacuum root page(%u), should not happened", nFin); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, PTRMAP_PAGENO(pBt, iLastPg), ++ CORRUPT_TYPE_PAGE_PTR_MAP, -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_REPORT(&context); + } + + if( eType==PTRMAP_FREEPAGE ){ +@@ -73907,7 +74266,12 @@ static int accessPayload( + assert( eOp==0 || eOp==1 ); + assert( pCur->eState==CURSOR_VALID ); + if( pCur->ix>=pPage->nCell ){ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell index:%u exceed limit:%u on the page:%u", ++ pCur->ix, pPage->nCell, pPage->pgno); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + assert( cursorHoldsMutex(pCur) ); + +@@ -73922,7 +74286,12 @@ static int accessPayload( + ** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] + ** but is recast into its current form to avoid integer overflow problems + */ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "base on payload size:%u, the max offset(%d) should > %d", ++ pCur->info.nLocal, (int)(aPayload - pPage->aData), (int)(pBt->usableSize - pCur->info.nLocal)); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ 0, 8, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + + /* Check if data must be read/written to/from the btree page itself. */ +@@ -73984,7 +74353,16 @@ static int accessPayload( + assert( rc==SQLITE_OK && amt>0 ); + while( nextPage ){ + /* If required, populate the overflow page-list cache. */ +- if( nextPage > pBt->nPage ) return SQLITE_CORRUPT_BKPT; ++ if( nextPage > pBt->nPage ){ ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode(aPayload + pCur->info.nLocal, 4, xBuffer, sizeof(xBuffer)); ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow page:%u should not exceed the size of database file, base16:%s", ++ nextPage, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ aPayload - pPage->aData + pCur->info.nLocal, 4, zMsg, NULL); ++ return SQLITE_CORRUPT_REPORT(&context); ++ } + assert( pCur->aOverflow[iIdx]==0 + || pCur->aOverflow[iIdx]==nextPage + || CORRUPT_DB ); +@@ -74069,7 +74447,11 @@ static int accessPayload( + + if( rc==SQLITE_OK && amt>0 ){ + /* Overflow chain ends prematurely */ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow chain ends prematurely, rest:%d", amt); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + return rc; + } +@@ -74345,7 +74727,12 @@ static int moveToRoot(BtCursor *pCur){ + ** (or the freelist). */ + assert( pRoot->intKey==1 || pRoot->intKey==0 ); + if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){ +- return SQLITE_CORRUPT_PAGE(pCur->pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "the page(%u) state illegal, isInit:%u, pKeyInfo%s0, intKey:%u", ++ pRoot->pgno, pRoot->isInit, ((pCur->pKeyInfo==0)?"==":"!="), pRoot->intKey); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pCur->pBt->nPage, pRoot->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pCur->pPage); + } + + skip_init: +@@ -74599,7 +74986,11 @@ SQLITE_PRIVATE int sqlite3BtreeTableMoveto( + if( pPage->intKeyLeaf ){ + while( 0x80 <= *(pCell++) ){ + if( pCell>=pPage->aDataEnd ){ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell idx(%d) point to a cell should not out of page", idx); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + } + } +@@ -74882,7 +75273,12 @@ bypass_moveto_root: + testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */ + testcase( nCell==2 ); /* Minimum legal index key size */ + if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){ +- rc = SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "nCell:%d illegal, usableSize:%u, nPage:%u", ++ nCell, pCur->pBt->usableSize, pCur->pBt->nPage); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); ++ rc = SQLITE_CORRUPT_PAGE(&context, pPage); + goto moveto_index_finish; + } + pCellKey = sqlite3Malloc( nCell+nOverrun ); +@@ -75210,7 +75606,13 @@ static int allocateBtreePage( + n = get4byte(&pPage1->aData[36]); + testcase( n==mxPage-1 ); + if( n>=mxPage ){ +- return SQLITE_CORRUPT_BKPT; ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE*3] = {0}; ++ (void)sqlite3base16Encode(pPage1->aData, 100, xBuffer, sizeof(xBuffer)); ++ sqlite3_snprintf(sizeof(zMsg), zMsg, ++ "total pages(%u) in freelist should not over the total size of db file(%u), base16:%s", n, mxPage, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, 1, CORRUPT_TYPE_FILE_HEADER, 36, 4, zMsg, NULL); ++ return SQLITE_CORRUPT_REPORT(&context); + } + if( n>0 ){ + /* There are pages on the freelist. Reuse one of those pages. */ +@@ -75266,7 +75668,12 @@ static int allocateBtreePage( + } + testcase( iTrunk==mxPage ); + if( iTrunk>mxPage || nSearch++ > n ){ +- rc = SQLITE_CORRUPT_PGNO(pPrevTrunk ? pPrevTrunk->pgno : 1); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "freelist trunk page(%u) should <= the size of db(%u)", ++ iTrunk, mxPage); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, (pPrevTrunk ? pPrevTrunk->pgno : 1), ++ CORRUPT_TYPE_PAGE_FREE_LIST, -1, 0, zMsg, NULL); ++ rc = SQLITE_CORRUPT_REPORT_PGNO(&context); + }else{ + rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0); + } +@@ -75295,7 +75702,14 @@ static int allocateBtreePage( + TRACE(("ALLOCATE: %d trunk - %d 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); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode(pTrunk->aData, 8, xBuffer, sizeof(xBuffer)); ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "total leaf pages(%u) on trunk page over limit(%u), base16:%s", ++ k, (u32)(pBt->usableSize/4 - 2), xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, ++ 0, 8, zMsg, NULL); ++ rc = SQLITE_CORRUPT_REPORT_PGNO(&context); + goto end_allocate_page; + #ifndef SQLITE_OMIT_AUTOVACUUM + }else if( searchList +@@ -75329,7 +75743,14 @@ static int allocateBtreePage( + MemPage *pNewTrunk; + Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); + if( iNewTrunk>mxPage ){ +- rc = SQLITE_CORRUPT_PGNO(iTrunk); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode(pTrunk->aData, 12, xBuffer, sizeof(xBuffer)); ++ sqlite3_snprintf(sizeof(zMsg), zMsg, ++ "leaf page's pgno(%u) on trunk page exceed db file size(%u), base16:%s", iNewTrunk, mxPage, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, ++ 8, 4, zMsg, NULL); ++ rc = SQLITE_CORRUPT_REPORT_PGNO(&context); + goto end_allocate_page; + } + testcase( iNewTrunk==mxPage ); +@@ -75394,7 +75815,14 @@ static int allocateBtreePage( + iPage = get4byte(&aData[8+closest*4]); + testcase( iPage==mxPage ); + if( iPage>mxPage || iPage<2 ){ +- rc = SQLITE_CORRUPT_PGNO(iTrunk); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode(aData+8+closest*4, 4, xBuffer, sizeof(xBuffer)); ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "leaf page's pgno(%u) out of range:[3, %d], base16:%s", ++ iPage, mxPage, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, ++ 8+closest*4, 4, zMsg, NULL); ++ rc = SQLITE_CORRUPT_REPORT_PGNO(&context); + goto end_allocate_page; + } + testcase( iPage==mxPage ); +@@ -75579,7 +76007,14 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ + nLeaf = get4byte(&pTrunk->aData[4]); + assert( pBt->usableSize>32 ); + if( nLeaf > (u32)pBt->usableSize/4 - 2 ){ +- rc = SQLITE_CORRUPT_BKPT; ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode(pTrunk->aData, 4, xBuffer, sizeof(xBuffer)); ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "the number of leaf page(%u) on trunk page(%d) exceed limit, base16:%s", ++ nLeaf, iTrunk, xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, ++ 0, 4, zMsg, NULL); ++ rc = SQLITE_CORRUPT_REPORT(&context); + goto freepage_out; + } + if( nLeaf < (u32)pBt->usableSize/4 - 8 ){ +@@ -75668,7 +76103,12 @@ static SQLITE_NOINLINE int clearCellOverflow( + testcase( pCell + (pInfo->nSize-1) == pPage->aDataEnd ); + if( pCell + pInfo->nSize > pPage->aDataEnd ){ + /* Cell extends past end of page */ +- return SQLITE_CORRUPT_PAGE(pPage); ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow end of page, pgno:%u, offset:%d, size:%u, usableSize:%u", ++ pPage->pgno, (int)(pCell - pPage->aData), pInfo->nSize, pPage->pBt->usableSize); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(btreePagecount(pPage->pBt), pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_PAGE(&context, pPage); + } + ovflPgno = get4byte(pCell + pInfo->nSize - 4); + pBt = pPage->pBt; +@@ -75685,7 +76125,14 @@ static SQLITE_NOINLINE int clearCellOverflow( + /* 0 is not a legal page number and page 1 cannot be an + ** overflow page. Therefore if ovflPgno<2 or past the end of the + ** file the database must be corrupt. */ +- return SQLITE_CORRUPT_BKPT; ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; ++ (void)sqlite3base16Encode(pCell + pInfo->nSize - 4, 4, xBuffer, sizeof(xBuffer)); ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow page's pgno(%u) illegal, out of range:[2, %u], base16:%s", ++ ovflPgno, btreePagecount(pBt), xBuffer); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(btreePagecount(pBt), pPage->pgno, ++ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_REPORT(&context); + } + if( nOvfl ){ + rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext); +@@ -75958,7 +76405,12 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ + testcase( pc==(u32)get2byte(&data[hdr+5]) ); + testcase( pc+sz==pPage->pBt->usableSize ); + if( pc+sz > pPage->pBt->usableSize ){ +- *pRC = SQLITE_CORRUPT_BKPT; ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell offset:%u size:%d, idx:%d overflow, usableSize:%u", ++ pc, sz, idx, pPage->pBt->usableSize); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ -1, 0, zMsg, NULL); ++ *pRC = SQLITE_CORRUPT_REPORT(&context); + return; + } + rc = freeSpace(pPage, pc, sz); +@@ -77868,7 +78320,14 @@ 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; ++ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; ++ sqlite3_snprintf(sizeof(zMsg), zMsg, ++ "cell payload cursor point to(%d), size:%u overlaps with non-cell content area:[%u, %d]", ++ (int)(pCur->info.pPayload - pPage->aData), pCur->info.nLocal, pPage->cellOffset, ++ (int)(pPage->aDataEnd - pPage->aData)); ++ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, ++ -1, 0, zMsg, NULL); ++ return SQLITE_CORRUPT_REPORT(&context); + } + /* Overwrite the local portion first */ + rc = btreeOverwriteContent(pPage, pCur->info.pPayload, pX, +@@ -83064,7 +83523,7 @@ static int growOpArray(Vdbe *v, int nOp){ + ** + ** Other useful labels for breakpoints include: + ** test_trace_breakpoint(pc,pOp) +-** sqlite3CorruptError(lineno) ++** sqlite3CorruptError(lineno,context) + ** sqlite3MisuseError(lineno) + ** sqlite3CantopenError(lineno) + */ +@@ -90722,7 +91181,7 @@ SQLITE_API int sqlite3_found_count = 0; + ** + ** Other useful labels for breakpoints include: + ** test_addop_breakpoint(pc,pOp) +-** sqlite3CorruptError(lineno) ++** sqlite3CorruptError(lineno,context) + ** sqlite3MisuseError(lineno) + ** sqlite3CantopenError(lineno) + */ +@@ -174509,6 +174968,12 @@ SQLITE_API int sqlite3_config(int op, ...){ + break; + } + #endif /* SQLITE_OMIT_DESERIALIZE */ ++ case SQLITE_CONFIG_CORRUPTION: { ++ typedef void(*CORRUPTION_FUNC_t)(void*, const void*); ++ sqlite3GlobalConfig.xCorruption = va_arg(ap, CORRUPTION_FUNC_t); ++ sqlite3GlobalConfig.pCorruptionArg = va_arg(ap, void*); ++ break; ++ } + + default: { + rc = SQLITE_ERROR; +@@ -177587,9 +178052,21 @@ SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType){ + zType, lineno, 20+sqlite3_sourceid()); + return iErr; + } +-SQLITE_PRIVATE int sqlite3CorruptError(int lineno){ ++SQLITE_PRIVATE int sqlite3CorruptError(int lineno, sqlite3CorruptContext *context){ + testcase( sqlite3GlobalConfig.xLog!=0 ); +- return sqlite3ReportError(SQLITE_CORRUPT, lineno, "database corruption"); ++ if (context!=NULL && sqlite3GlobalConfig.xCorruption != 0) { ++ char zMsg[SQLITE_PRINT_BUF_SIZE] = {0}; /* Complete corruption log message */ ++ sqlite3_snprintf(sizeof(zMsg), zMsg, "pgno:%u,type:%d,range:{%d,%d},line:%d", ++ context->pgno, (int)context->type, (int)context->zoneRange.offset, (int)context->zoneRange.size, lineno); ++ sqlite3GlobalConfig.xCorruption(sqlite3GlobalConfig.pCorruptionArg, zMsg); ++ } ++ char zCorruptMsg[SQLITE_PRINT_BUF_SIZE * 10] = {0}; ++ if (context!=NULL && context->zMsg != NULL){ ++ sqlite3_snprintf(sizeof(zCorruptMsg), zCorruptMsg, "database corruption, %s", context->zMsg); ++ } else { ++ sqlite3_snprintf(sizeof(zCorruptMsg), zCorruptMsg, "database corruption"); ++ } ++ return sqlite3ReportError(SQLITE_CORRUPT, lineno, zCorruptMsg); + } + SQLITE_PRIVATE int sqlite3MisuseError(int lineno){ + testcase( sqlite3GlobalConfig.xLog!=0 ); +-- +2.47.0.windows.2 + diff --git a/patch/0006-support-check-pages.patch b/patch/0006-support-check-pages.patch new file mode 100644 index 0000000..b41f2d9 --- /dev/null +++ b/patch/0006-support-check-pages.patch @@ -0,0 +1,1080 @@ +From c55af5823f6913cb4a5534f4319b6d22d4e51135 Mon Sep 17 00:00:00 2001 +From: wanghaishuo +Date: Sat, 12 Apr 2025 10:59:29 +0800 +Subject: [PATCH 6/7] support check pages + +Signed-off-by: ryne3366 +--- + ext/misc/cksumvfs.c | 916 ++++++++++++++++++++++++++++++++++++++++++++ + src/sqlite3.c | 99 ++++- + 2 files changed, 1008 insertions(+), 7 deletions(-) + create mode 100644 ext/misc/cksumvfs.c + +diff --git a/ext/misc/cksumvfs.c b/ext/misc/cksumvfs.c +new file mode 100644 +index 0000000..6f4c55c +--- /dev/null ++++ b/ext/misc/cksumvfs.c +@@ -0,0 +1,916 @@ ++/* ++** 2020-04-20 ++** ++** The author disclaims copyright to this source code. In place of ++** a legal notice, here is a blessing: ++** ++** May you do good and not evil. ++** May you find forgiveness for yourself and forgive others. ++** May you share freely, never taking more than you give. ++** ++****************************************************************************** ++** ++** This file implements a VFS shim that writes a checksum on each page ++** of an SQLite database file. When reading pages, the checksum is verified ++** and an error is raised if the checksum is incorrect. ++** ++** COMPILING ++** ++** This extension requires SQLite 3.32.0 or later. It uses the ++** sqlite3_database_file_object() interface which was added in ++** version 3.32.0, so it will not link with an earlier version of ++** SQLite. ++** ++** To build this extension as a separately loaded shared library or ++** DLL, use compiler command-lines similar to the following: ++** ++** (linux) gcc -fPIC -shared cksumvfs.c -o cksumvfs.so ++** (mac) clang -fPIC -dynamiclib cksumvfs.c -o cksumvfs.dylib ++** (windows) cl cksumvfs.c -link -dll -out:cksumvfs.dll ++** ++** You may want to add additional compiler options, of course, ++** according to the needs of your project. ++** ++** If you want to statically link this extension with your product, ++** then compile it like any other C-language module but add the ++** "-DSQLITE_CKSUMVFS_STATIC" option so that this module knows that ++** it is being statically linked rather than dynamically linked ++** ++** LOADING ++** ++** To load this extension as a shared library, you first have to ++** bring up a dummy SQLite database connection to use as the argument ++** to the sqlite3_load_extension() API call. Then you invoke the ++** sqlite3_load_extension() API and shutdown the dummy database ++** connection. All subsequent database connections that are opened ++** will include this extension. For example: ++** ++** sqlite3 *db; ++** sqlite3_open(":memory:", &db); ++** sqlite3_load_extension(db, "./cksumvfs"); ++** sqlite3_close(db); ++** ++** If this extension is compiled with -DSQLITE_CKSUMVFS_STATIC and ++** statically linked against the application, initialize it using ++** a single API call as follows: ++** ++** sqlite3_register_cksumvfs(); ++** ++** Cksumvfs is a VFS Shim. When loaded, "cksmvfs" becomes the new ++** default VFS and it uses the prior default VFS as the next VFS ++** down in the stack. This is normally what you want. However, in ++** complex situations where multiple VFS shims are being loaded, ++** it might be important to ensure that cksumvfs is loaded in the ++** correct order so that it sequences itself into the default VFS ++** Shim stack in the right order. ++** ++** USING ++** ++** Open database connections using the sqlite3_open() or ++** sqlite3_open_v2() interfaces, as normal. Ordinary database files ++** (without a checksum) will operate normally. Databases with ++** checksums will return an SQLITE_IOERR_DATA error if a page is ++** encountered that contains an invalid checksum. ++** ++** Checksumming only works on databases that have a reserve-bytes ++** value of exactly 8. The default value for reserve-bytes is 0. ++** Hence, newly created database files will omit the checksum by ++** default. To create a database that includes a checksum, change ++** the reserve-bytes value to 8 by runing: ++** ++** int n = 8; ++** sqlite3_file_control(db, 0, SQLITE_FCNTL_RESERVE_BYTES, &n); ++** ++** If you do this immediately after creating a new database file, ++** before anything else has been written into the file, then that ++** might be all that you need to do. Otherwise, the API call ++** above should be followed by: ++** ++** sqlite3_exec(db, "VACUUM", 0, 0, 0); ++** ++** It never hurts to run the VACUUM, even if you don't need it. ++** If the database is in WAL mode, you should shutdown and ++** reopen all database connections before continuing. ++** ++** From the CLI, use the ".filectrl reserve_bytes 8" command, ++** followed by "VACUUM;". ++** ++** Note that SQLite allows the number of reserve-bytes to be ++** increased but not decreased. So if a database file already ++** has a reserve-bytes value greater than 8, there is no way to ++** activate checksumming on that database, other than to dump ++** and restore the database file. Note also that other extensions ++** might also make use of the reserve-bytes. Checksumming will ++** be incompatible with those other extensions. ++** ++** VERIFICATION OF CHECKSUMS ++** ++** If any checksum is incorrect, the "PRAGMA quick_check" command ++** will find it. To verify that checksums are actually enabled ++** and running, use the following query: ++** ++** SELECT count(*), verify_checksum(data) ++** FROM sqlite_dbpage ++** GROUP BY 2; ++** ++** There are three possible outputs form the verify_checksum() ++** function: 1, 0, and NULL. 1 is returned if the checksum is ++** correct. 0 is returned if the checksum is incorrect. NULL ++** is returned if the page is unreadable. If checksumming is ++** enabled, the read will fail if the checksum is wrong, so the ++** usual result from verify_checksum() on a bad checksum is NULL. ++** ++** If everything is OK, the query above should return a single ++** row where the second column is 1. Any other result indicates ++** either that there is a checksum error, or checksum validation ++** is disabled. ++** ++** CONTROLLING CHECKSUM VERIFICATION ++** ++** The cksumvfs extension implements a new PRAGMA statement that can ++** be used to disable, re-enable, or query the status of checksum ++** verification: ++** ++** PRAGMA checksum_verification; -- query status ++** PRAGMA checksum_verification=OFF; -- disable verification ++** PRAGMA checksum_verification=ON; -- re-enable verification ++** ++** The "checksum_verification" pragma will return "1" (true) or "0" ++** (false) if checksum verification is enabled or disabled, respectively. ++** "Verification" in this context means the feature that causes ++** SQLITE_IOERR_DATA errors if a checksum mismatch is detected while ++** reading. Checksums are always kept up-to-date as long as the ++** reserve-bytes value of the database is 8, regardless of the setting ++** of this pragma. Checksum verification can be disabled (for example) ++** to do forensic analysis of a database that has previously reported ++** a checksum error. ++** ++** The "checksum_verification" pragma will always respond with "0" if ++** the database file does not have a reserve-bytes value of 8. The ++** pragma will return no rows at all if the cksumvfs extension is ++** not loaded. ++** ++** IMPLEMENTATION NOTES ++** ++** The checksum is stored in the last 8 bytes of each page. This ++** module only operates if the "bytes of reserved space on each page" ++** value at offset 20 the SQLite database header is exactly 8. If ++** the reserved-space value is not 8, this module is a no-op. ++*/ ++#if defined(SQLITE_AMALGAMATION) && !defined(SQLITE_CKSUMVFS_STATIC) ++# define SQLITE_CKSUMVFS_STATIC ++#endif ++#ifdef SQLITE_CKSUMVFS_STATIC ++# include "sqlite3.h" ++#else ++# include "sqlite3ext.h" ++ SQLITE_EXTENSION_INIT1 ++#endif ++#include ++#include ++ ++// hw export the symbols ++#ifdef SQLITE_EXPORT_SYMBOLS ++#if defined(__GNUC__) ++# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) ++#elif defined(_MSC_VER) ++# define EXPORT_SYMBOLS __declspec(dllexport) ++#else ++# define EXPORT_SYMBOLS ++#endif ++#endif ++ ++/* ++** Forward declaration of objects used by this utility ++*/ ++typedef struct sqlite3_vfs CksmVfs; ++typedef struct CksmFile CksmFile; ++ ++/* ++** Useful datatype abbreviations ++*/ ++#if !defined(SQLITE_AMALGAMATION) ++ typedef unsigned char u8; ++ typedef unsigned int u32; ++#endif ++ ++/* Access to a lower-level VFS that (might) implement dynamic loading, ++** access to randomness, etc. ++*/ ++#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) ++#define ORIGFILE(p) ((sqlite3_file*)(((CksmFile*)(p))+1)) ++ ++/* An open file */ ++struct CksmFile { ++ sqlite3_file base; /* IO methods */ ++ const char *zFName; /* Original name of the file */ ++ char computeCksm; /* True to compute checksums. ++ ** Always true if reserve size is 8. */ ++ char verifyCksm; /* True to verify checksums */ ++ char isWal; /* True if processing a WAL file */ ++ char inCkpt; /* Currently doing a checkpoint */ ++ CksmFile *pPartner; /* Ptr from WAL to main-db, or from main-db to WAL */ ++}; ++ ++/* ++** Methods for CksmFile ++*/ ++static int cksmClose(sqlite3_file*); ++static int cksmRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); ++static int cksmWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); ++static int cksmTruncate(sqlite3_file*, sqlite3_int64 size); ++static int cksmSync(sqlite3_file*, int flags); ++static int cksmFileSize(sqlite3_file*, sqlite3_int64 *pSize); ++static int cksmLock(sqlite3_file*, int); ++static int cksmUnlock(sqlite3_file*, int); ++static int cksmCheckReservedLock(sqlite3_file*, int *pResOut); ++static int cksmFileControl(sqlite3_file*, int op, void *pArg); ++static int cksmSectorSize(sqlite3_file*); ++static int cksmDeviceCharacteristics(sqlite3_file*); ++static int cksmShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**); ++static int cksmShmLock(sqlite3_file*, int offset, int n, int flags); ++static void cksmShmBarrier(sqlite3_file*); ++static int cksmShmUnmap(sqlite3_file*, int deleteFlag); ++static int cksmFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); ++static int cksmUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p); ++ ++/* ++** Methods for CksmVfs ++*/ ++static int cksmOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); ++static int cksmDelete(sqlite3_vfs*, const char *zName, int syncDir); ++static int cksmAccess(sqlite3_vfs*, const char *zName, int flags, int *); ++static int cksmFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); ++static void *cksmDlOpen(sqlite3_vfs*, const char *zFilename); ++static void cksmDlError(sqlite3_vfs*, int nByte, char *zErrMsg); ++static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void); ++static void cksmDlClose(sqlite3_vfs*, void*); ++static int cksmRandomness(sqlite3_vfs*, int nByte, char *zOut); ++static int cksmSleep(sqlite3_vfs*, int microseconds); ++static int cksmCurrentTime(sqlite3_vfs*, double*); ++static int cksmGetLastError(sqlite3_vfs*, int, char *); ++static int cksmCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); ++static int cksmSetSystemCall(sqlite3_vfs*, const char*,sqlite3_syscall_ptr); ++static sqlite3_syscall_ptr cksmGetSystemCall(sqlite3_vfs*, const char *z); ++static const char *cksmNextSystemCall(sqlite3_vfs*, const char *zName); ++ ++static sqlite3_vfs cksm_vfs = { ++ 3, /* iVersion (set when registered) */ ++ 0, /* szOsFile (set when registered) */ ++ 1024, /* mxPathname */ ++ 0, /* pNext */ ++ "cksmvfs", /* zName */ ++ 0, /* pAppData (set when registered) */ ++ cksmOpen, /* xOpen */ ++ cksmDelete, /* xDelete */ ++ cksmAccess, /* xAccess */ ++ cksmFullPathname, /* xFullPathname */ ++ cksmDlOpen, /* xDlOpen */ ++ cksmDlError, /* xDlError */ ++ cksmDlSym, /* xDlSym */ ++ cksmDlClose, /* xDlClose */ ++ cksmRandomness, /* xRandomness */ ++ cksmSleep, /* xSleep */ ++ cksmCurrentTime, /* xCurrentTime */ ++ cksmGetLastError, /* xGetLastError */ ++ cksmCurrentTimeInt64, /* xCurrentTimeInt64 */ ++ cksmSetSystemCall, /* xSetSystemCall */ ++ cksmGetSystemCall, /* xGetSystemCall */ ++ cksmNextSystemCall /* xNextSystemCall */ ++}; ++ ++static const sqlite3_io_methods cksm_io_methods = { ++ 3, /* iVersion */ ++ cksmClose, /* xClose */ ++ cksmRead, /* xRead */ ++ cksmWrite, /* xWrite */ ++ cksmTruncate, /* xTruncate */ ++ cksmSync, /* xSync */ ++ cksmFileSize, /* xFileSize */ ++ cksmLock, /* xLock */ ++ cksmUnlock, /* xUnlock */ ++ cksmCheckReservedLock, /* xCheckReservedLock */ ++ cksmFileControl, /* xFileControl */ ++ cksmSectorSize, /* xSectorSize */ ++ cksmDeviceCharacteristics, /* xDeviceCharacteristics */ ++ cksmShmMap, /* xShmMap */ ++ cksmShmLock, /* xShmLock */ ++ cksmShmBarrier, /* xShmBarrier */ ++ cksmShmUnmap, /* xShmUnmap */ ++ cksmFetch, /* xFetch */ ++ cksmUnfetch /* xUnfetch */ ++}; ++ ++/* Do byte swapping on a unsigned 32-bit integer */ ++#define BYTESWAP32(x) ( \ ++ (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \ ++ + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \ ++) ++ ++/* Compute a checksum on a buffer */ ++static void cksmCompute( ++ u8 *a, /* Content to be checksummed */ ++ int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */ ++ u8 *aOut /* OUT: Final 8-byte checksum value output */ ++){ ++ u32 s1 = 0, s2 = 0; ++ u32 *aData = (u32*)a; ++ u32 *aEnd = (u32*)&a[nByte]; ++ u32 x = 1; ++ ++ assert( nByte>=8 ); ++ assert( (nByte&0x00000007)==0 ); ++ assert( nByte<=65536 ); ++ ++ if( 1 == *(u8*)&x ){ ++ /* Little-endian */ ++ do { ++ s1 += *aData++ + s2; ++ s2 += *aData++ + s1; ++ }while( aData65536 || (nByte & (nByte-1))!=0 ) return; ++ cksmCompute(data, nByte-8, cksum); ++ sqlite3_result_int(context, memcmp(data+nByte-8,cksum,8)==0); ++} ++ ++#ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME ++/* ++** SQL function: initialize_cksumvfs(SCHEMANAME) ++** ++** This SQL functions (whose name is actually determined at compile-time ++** by the value of the SQLITE_CKSUMVFS_INIT_FUNCNAME macro) invokes: ++** ++** sqlite3_file_control(db, SCHEMANAME, SQLITE_FCNTL_RESERVE_BYTE, &n); ++** ++** In order to set the reserve bytes value to 8, so that cksumvfs will ++** operation. This feature is provided (if and only if the ++** SQLITE_CKSUMVFS_INIT_FUNCNAME compile-time option is set to a string ++** which is the name of the SQL function) so as to provide the ability ++** to invoke the file-control in programming languages that lack ++** direct access to the sqlite3_file_control() interface (ex: Java). ++** ++** This interface is undocumented, apart from this comment. Usage ++** example: ++** ++** 1. Compile with -DSQLITE_CKSUMVFS_INIT_FUNCNAME="ckvfs_init" ++** 2. Run: "SELECT cksum_init('main'); VACUUM;" ++*/ ++static void cksmInitFunc( ++ sqlite3_context *context, ++ int argc, ++ sqlite3_value **argv ++){ ++ int nByte = 8; ++ const char *zSchemaName = (const char*)sqlite3_value_text(argv[0]); ++ sqlite3 *db = sqlite3_context_db_handle(context); ++ sqlite3_file_control(db, zSchemaName, SQLITE_FCNTL_RESERVE_BYTES, &nByte); ++ /* Return NULL */ ++} ++#endif /* SQLITE_CKSUMBFS_INIT_FUNCNAME */ ++ ++/* ++** Close a cksm-file. ++*/ ++static int cksmClose(sqlite3_file *pFile){ ++ CksmFile *p = (CksmFile *)pFile; ++ if( p->pPartner ){ ++ assert( p->pPartner->pPartner==p ); ++ p->pPartner->pPartner = 0; ++ p->pPartner = 0; ++ } ++ pFile = ORIGFILE(pFile); ++ return pFile->pMethods->xClose(pFile); ++} ++ ++/* ++** Set the computeCkSm and verifyCksm flags, if they need to be ++** changed. ++*/ ++static void cksmSetFlags(CksmFile *p, int hasCorrectReserveSize){ ++ if( hasCorrectReserveSize!=p->computeCksm ){ ++ p->computeCksm = p->verifyCksm = hasCorrectReserveSize; ++ if( p->pPartner ){ ++ p->pPartner->verifyCksm = hasCorrectReserveSize; ++ p->pPartner->computeCksm = hasCorrectReserveSize; ++ } ++ } ++} ++ ++static void EncodeReservedBytesIntoBase16(const u8 *reserved, int len, char *encodeStr, int maxLen){ ++ static const char baseCode[] = "0123456789ABCDEF"; ++ for(int i=0; i> 4) & 0x0F]; ++ *encodeStr++ = baseCode[reserved[i] & 0x0F]; ++ } ++ *encodeStr = '0'; ++} ++ ++/* ++** Read data from a cksm-file. ++*/ ++static int cksmRead( ++ sqlite3_file *pFile, ++ void *zBuf, ++ int iAmt, ++ sqlite_int64 iOfst ++){ ++ int rc; ++ CksmFile *p = (CksmFile *)pFile; ++ pFile = ORIGFILE(pFile); ++ rc = pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst); ++ if( rc==SQLITE_OK ){ ++ if( iOfst==0 && iAmt>=100 && ( ++ memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0 ++ )){ ++ u8 *d = (u8*)zBuf; ++ char hasCorrectReserveSize = (d[20]==8); ++ cksmSetFlags(p, hasCorrectReserveSize); ++ } ++ /* Verify the checksum if ++ ** (1) the size indicates that we are dealing with a complete ++ ** database page, only support pageSize:4K ++ ** (2) checksum verification is enabled ++ ** (3) we are not in the middle of checkpoint ++ */ ++ if( iAmt==4096 /* (1) */ ++ && p->verifyCksm /* (2) */ ++ && !p->inCkpt /* (3) */ ++ ){ ++ u8 cksum[8]; ++ cksmCompute((u8*)zBuf, iAmt-8, cksum); ++ if( memcmp((u8*)zBuf+iAmt-8, cksum, 8)!=0 ){ ++ char expect[18] = {0}; ++ char actual[18] = {0}; ++ EncodeReservedBytesIntoBase16((u8 *)zBuf+iAmt-8, 8, expect, 18); ++ EncodeReservedBytesIntoBase16(cksum, 8, actual, 18); ++ sqlite3_log(SQLITE_IOERR_DATA, "checksum fault offset %lld of \"%s\", amt:%d, expect:%s, actual:%s", ++ iOfst, p->zFName, iAmt, expect, actual); ++ rc = SQLITE_IOERR_DATA; ++ } ++ } ++ } ++ return rc; ++} ++ ++/* ++** Write data to a cksm-file. ++*/ ++static int cksmWrite( ++ sqlite3_file *pFile, ++ const void *zBuf, ++ int iAmt, ++ sqlite_int64 iOfst ++){ ++ CksmFile *p = (CksmFile *)pFile; ++ pFile = ORIGFILE(pFile); ++ if( iOfst==0 && iAmt>=100 && ( ++ memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0 ++ )){ ++ u8 *d = (u8*)zBuf; ++ char hasCorrectReserveSize = (d[20]==8); ++ cksmSetFlags(p, hasCorrectReserveSize); ++ } ++ /* If the write size is appropriate for a database page and if ++ ** checksums where ever enabled, then it will be safe to compute ++ ** the checksums. The reserve byte size might have increased, but ++ ** it will never decrease. And because it cannot decrease, the ++ ** checksum will not overwrite anything. ++ */ ++ if( iAmt==4096 ++ && p->computeCksm ++ && !p->inCkpt ++ ){ ++ cksmCompute((u8*)zBuf, iAmt-8, ((u8*)zBuf)+iAmt-8); ++ } ++ return pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst); ++} ++ ++/* ++** Truncate a cksm-file. ++*/ ++static int cksmTruncate(sqlite3_file *pFile, sqlite_int64 size){ ++ pFile = ORIGFILE(pFile); ++ return pFile->pMethods->xTruncate(pFile, size); ++} ++ ++/* ++** Sync a cksm-file. ++*/ ++static int cksmSync(sqlite3_file *pFile, int flags){ ++ pFile = ORIGFILE(pFile); ++ return pFile->pMethods->xSync(pFile, flags); ++} ++ ++/* ++** Return the current file-size of a cksm-file. ++*/ ++static int cksmFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ ++ CksmFile *p = (CksmFile *)pFile; ++ pFile = ORIGFILE(p); ++ return pFile->pMethods->xFileSize(pFile, pSize); ++} ++ ++/* ++** Lock a cksm-file. ++*/ ++static int cksmLock(sqlite3_file *pFile, int eLock){ ++ pFile = ORIGFILE(pFile); ++ return pFile->pMethods->xLock(pFile, eLock); ++} ++ ++/* ++** Unlock a cksm-file. ++*/ ++static int cksmUnlock(sqlite3_file *pFile, int eLock){ ++ pFile = ORIGFILE(pFile); ++ return pFile->pMethods->xUnlock(pFile, eLock); ++} ++ ++/* ++** Check if another file-handle holds a RESERVED lock on a cksm-file. ++*/ ++static int cksmCheckReservedLock(sqlite3_file *pFile, int *pResOut){ ++ pFile = ORIGFILE(pFile); ++ return pFile->pMethods->xCheckReservedLock(pFile, pResOut); ++} ++ ++/* ++** File control method. For custom operations on a cksm-file. ++*/ ++static int cksmFileControl(sqlite3_file *pFile, int op, void *pArg){ ++ int rc; ++ CksmFile *p = (CksmFile*)pFile; ++ pFile = ORIGFILE(pFile); ++ if( op==SQLITE_FCNTL_PRAGMA ){ ++ char **azArg = (char**)pArg; ++ assert( azArg[1]!=0 ); ++ if( sqlite3_stricmp(azArg[1],"checksum_verification")==0 ){ ++ char *zArg = azArg[2]; ++ if( zArg!=0 ){ ++ if( (zArg[0]>='1' && zArg[0]<='9') ++ || sqlite3_strlike("enable%",zArg,0)==0 ++ || sqlite3_stricmp("yes",zArg)==0 ++ || sqlite3_stricmp("on",zArg)==0 ++ ){ ++ p->verifyCksm = p->computeCksm; ++ }else{ ++ p->verifyCksm = 0; ++ } ++ if( p->pPartner ) p->pPartner->verifyCksm = p->verifyCksm; ++ } ++ azArg[0] = sqlite3_mprintf("%d",p->verifyCksm); ++ return SQLITE_OK; ++ }else if( p->computeCksm && azArg[2]!=0 ++ && sqlite3_stricmp(azArg[1], "page_size")==0 ){ ++ /* Do not allow page size changes on a checksum database */ ++ return SQLITE_OK; ++ } ++ }else if( op==SQLITE_FCNTL_CKPT_START || op==SQLITE_FCNTL_CKPT_DONE ){ ++ p->inCkpt = op==SQLITE_FCNTL_CKPT_START; ++ if( p->pPartner ) p->pPartner->inCkpt = p->inCkpt; ++ }else if( op==SQLITE_FCNTL_CKSM_FILE ){ ++ /* This VFS needs to obtain a pointer to the corresponding database ++ ** file handle from within xOpen() calls to open wal files. To do this, ++ ** it uses the sqlite3_database_file_object() API to obtain a pointer ++ ** to the file-handle used by SQLite to access the db file. This is ++ ** fine if cksmvfs happens to be the top-level VFS, but not if there ++ ** are one or more wrapper VFS. To handle this case, this file-control ++ ** is used to extract the cksmvfs file-handle from any wrapper file ++ ** handle. */ ++ sqlite3_file **ppFile = (sqlite3_file**)pArg; ++ *ppFile = (sqlite3_file*)p; ++ return SQLITE_OK; ++ } ++ rc = pFile->pMethods->xFileControl(pFile, op, pArg); ++ if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){ ++ *(char**)pArg = sqlite3_mprintf("cksm/%z", *(char**)pArg); ++ } ++ return rc; ++} ++ ++/* ++** Return the sector-size in bytes for a cksm-file. ++*/ ++static int cksmSectorSize(sqlite3_file *pFile){ ++ pFile = ORIGFILE(pFile); ++ return pFile->pMethods->xSectorSize(pFile); ++} ++ ++/* ++** Return the device characteristic flags supported by a cksm-file. ++*/ ++static int cksmDeviceCharacteristics(sqlite3_file *pFile){ ++ pFile = ORIGFILE(pFile); ++ return pFile->pMethods->xDeviceCharacteristics(pFile); ++} ++ ++/* Create a shared memory file mapping */ ++static int cksmShmMap( ++ sqlite3_file *pFile, ++ int iPg, ++ int pgsz, ++ int bExtend, ++ void volatile **pp ++){ ++ pFile = ORIGFILE(pFile); ++ return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp); ++} ++ ++/* Perform locking on a shared-memory segment */ ++static int cksmShmLock(sqlite3_file *pFile, int offset, int n, int flags){ ++ pFile = ORIGFILE(pFile); ++ return pFile->pMethods->xShmLock(pFile,offset,n,flags); ++} ++ ++/* Memory barrier operation on shared memory */ ++static void cksmShmBarrier(sqlite3_file *pFile){ ++ pFile = ORIGFILE(pFile); ++ pFile->pMethods->xShmBarrier(pFile); ++} ++ ++/* Unmap a shared memory segment */ ++static int cksmShmUnmap(sqlite3_file *pFile, int deleteFlag){ ++ pFile = ORIGFILE(pFile); ++ return pFile->pMethods->xShmUnmap(pFile,deleteFlag); ++} ++ ++/* Fetch a page of a memory-mapped file */ ++static int cksmFetch( ++ sqlite3_file *pFile, ++ sqlite3_int64 iOfst, ++ int iAmt, ++ void **pp ++){ ++ CksmFile *p = (CksmFile *)pFile; ++ if( p->computeCksm ){ ++ *pp = 0; ++ return SQLITE_OK; ++ } ++ pFile = ORIGFILE(pFile); ++ if( pFile->pMethods->iVersion>2 && pFile->pMethods->xFetch ){ ++ return pFile->pMethods->xFetch(pFile, iOfst, iAmt, pp); ++ } ++ *pp = 0; ++ return SQLITE_OK; ++} ++ ++/* Release a memory-mapped page */ ++static int cksmUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ ++ pFile = ORIGFILE(pFile); ++ if( pFile->pMethods->iVersion>2 && pFile->pMethods->xUnfetch ){ ++ return pFile->pMethods->xUnfetch(pFile, iOfst, pPage); ++ } ++ return SQLITE_OK; ++} ++ ++/* ++** Open a cksm file handle. ++*/ ++static int cksmOpen( ++ sqlite3_vfs *pVfs, ++ const char *zName, ++ sqlite3_file *pFile, ++ int flags, ++ int *pOutFlags ++){ ++ CksmFile *p; ++ sqlite3_file *pSubFile; ++ sqlite3_vfs *pSubVfs; ++ int rc; ++ pSubVfs = ORIGVFS(pVfs); ++ if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){ ++ return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags); ++ } ++ p = (CksmFile*)pFile; ++ memset(p, 0, sizeof(*p)); ++ pSubFile = ORIGFILE(pFile); ++ pFile->pMethods = &cksm_io_methods; ++ rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags); ++ if( rc ) goto cksm_open_done; ++ if( flags & SQLITE_OPEN_WAL ){ ++ sqlite3_file *pDb = sqlite3_database_file_object(zName); ++ rc = pDb->pMethods->xFileControl(pDb, SQLITE_FCNTL_CKSM_FILE, (void*)&pDb); ++ assert( rc==SQLITE_OK ); ++ p->pPartner = (CksmFile*)pDb; ++ assert( p->pPartner->pPartner==0 ); ++ p->pPartner->pPartner = p; ++ p->isWal = 1; ++ p->computeCksm = p->pPartner->computeCksm; ++ }else{ ++ p->isWal = 0; ++ p->computeCksm = 0; ++ } ++ p->zFName = zName; ++cksm_open_done: ++ if( rc ) pFile->pMethods = 0; ++ return rc; ++} ++ ++/* ++** All other VFS methods are pass-thrus. ++*/ ++static int cksmDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ ++ return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync); ++} ++static int cksmAccess( ++ sqlite3_vfs *pVfs, ++ const char *zPath, ++ int flags, ++ int *pResOut ++){ ++ return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut); ++} ++static int cksmFullPathname( ++ sqlite3_vfs *pVfs, ++ const char *zPath, ++ int nOut, ++ char *zOut ++){ ++ return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut); ++} ++static void *cksmDlOpen(sqlite3_vfs *pVfs, const char *zPath){ ++ return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath); ++} ++static void cksmDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ ++ ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg); ++} ++static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ ++ return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym); ++} ++static void cksmDlClose(sqlite3_vfs *pVfs, void *pHandle){ ++ ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle); ++} ++static int cksmRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ ++ return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut); ++} ++static int cksmSleep(sqlite3_vfs *pVfs, int nMicro){ ++ return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro); ++} ++static int cksmCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ ++ return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut); ++} ++static int cksmGetLastError(sqlite3_vfs *pVfs, int a, char *b){ ++ return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b); ++} ++static int cksmCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){ ++ sqlite3_vfs *pOrig = ORIGVFS(pVfs); ++ int rc; ++ assert( pOrig->iVersion>=2 ); ++ if( pOrig->xCurrentTimeInt64 ){ ++ rc = pOrig->xCurrentTimeInt64(pOrig, p); ++ }else{ ++ double r; ++ rc = pOrig->xCurrentTime(pOrig, &r); ++ *p = (sqlite3_int64)(r*86400000.0); ++ } ++ return rc; ++} ++static int cksmSetSystemCall( ++ sqlite3_vfs *pVfs, ++ const char *zName, ++ sqlite3_syscall_ptr pCall ++){ ++ return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall); ++} ++static sqlite3_syscall_ptr cksmGetSystemCall( ++ sqlite3_vfs *pVfs, ++ const char *zName ++){ ++ return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName); ++} ++static const char *cksmNextSystemCall(sqlite3_vfs *pVfs, const char *zName){ ++ return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName); ++} ++ ++/* Register the verify_checksum() SQL function. ++*/ ++static int cksmRegisterFunc( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ int rc; ++ if( db==0 ) return SQLITE_OK; ++ rc = sqlite3_create_function(db, "verify_checksum", 1, ++ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, ++ 0, cksmVerifyFunc, 0, 0); ++#ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME ++ (void)sqlite3_create_function(db, SQLITE_CKSUMVFS_INIT_FUNCNAME, 1, ++ SQLITE_UTF8|SQLITE_DIRECTONLY, ++ 0, cksmInitFunc, 0, 0); ++#endif ++ return rc; ++} ++ ++/* ++** Register the cksum VFS as the default VFS for the system. ++** Also make arrangements to automatically register the "verify_checksum()" ++** SQL function on each new database connection. ++*/ ++static int cksmRegisterVfs(void){ ++ int rc = SQLITE_OK; ++ sqlite3_vfs *pOrig; ++ if( sqlite3_vfs_find("cksmvfs")!=0 ) return SQLITE_OK; ++ pOrig = sqlite3_vfs_find(0); ++ if( pOrig==0 ) return SQLITE_ERROR; ++ cksm_vfs.iVersion = pOrig->iVersion; ++ cksm_vfs.pAppData = pOrig; ++ cksm_vfs.szOsFile = pOrig->szOsFile + sizeof(CksmFile); ++ rc = sqlite3_vfs_register(&cksm_vfs, 1); ++ if( rc==SQLITE_OK ){ ++ rc = sqlite3_auto_extension((void(*)(void))cksmRegisterFunc); ++ } ++ return rc; ++} ++ ++#if defined(SQLITE_CKSUMVFS_STATIC) ++/* This variant of the initializer runs when the extension is ++** statically linked. ++*/ ++int sqlite3_register_cksumvfs(const char *NotUsed){ ++ (void)NotUsed; ++ return cksmRegisterVfs(); ++} ++int sqlite3_unregister_cksumvfs(void){ ++ if( sqlite3_vfs_find("cksmvfs") ){ ++ sqlite3_vfs_unregister(&cksm_vfs); ++ sqlite3_cancel_auto_extension((void(*)(void))cksmRegisterFunc); ++ } ++ return SQLITE_OK; ++} ++#endif /* defined(SQLITE_CKSUMVFS_STATIC */ ++ ++#if !defined(SQLITE_CKSUMVFS_STATIC) ++/* This variant of the initializer function is used when the ++** extension is shared library to be loaded at run-time. ++*/ ++#ifdef _WIN32 ++__declspec(dllexport) ++#endif ++/* ++** This routine is called by sqlite3_load_extension() when the ++** extension is first loaded. ++***/ ++int sqlite3_cksumvfs_init( ++ sqlite3 *db, ++ char **pzErrMsg, ++ const sqlite3_api_routines *pApi ++){ ++ int rc; ++ SQLITE_EXTENSION_INIT2(pApi); ++ (void)pzErrMsg; /* not used */ ++ rc = cksmRegisterFunc(db, 0, 0); ++ if( rc==SQLITE_OK ){ ++ rc = cksmRegisterVfs(); ++ } ++ if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; ++ return rc; ++} ++#endif /* !defined(SQLITE_CKSUMVFS_STATIC) */ ++ ++#ifdef SQLITE_CKSUMVFS_STATIC ++struct sqlite3_api_routines_cksumvfs { ++ int (*register_cksumvfs)(const char *); ++ int (*unregister_cksumvfs)(); ++}; ++typedef struct sqlite3_api_routines_cksumvfs sqlite3_api_routines_cksumvfs; ++static const sqlite3_api_routines_cksumvfs sqlite3CksumvfsApis = { ++ sqlite3_register_cksumvfs, ++ sqlite3_unregister_cksumvfs ++}; ++ ++EXPORT_SYMBOLS const sqlite3_api_routines_cksumvfs *sqlite3_export_cksumvfs_symbols = &sqlite3CksumvfsApis; ++#endif +diff --git a/src/sqlite3.c b/src/sqlite3.c +index ad7ce74..f59ac55 100644 +--- a/src/sqlite3.c ++++ b/src/sqlite3.c +@@ -57046,17 +57046,70 @@ static int jrnlBufferSize(Pager *pPager){ + ** and debugging only. + */ + #ifdef SQLITE_CHECK_PAGES +-/* +-** Return a 32-bit hash of the page data for pPage. +-*/ +-static u32 pager_datahash(int nByte, unsigned char *pData){ ++#if defined (__arm__) || defined (__aarch64__) ++#include ++u32 deep_fast_hash_arm(void *src, int srcLen){ ++ uint16_t chunkSize = srcLen/4; ++ uint8_t *u8p_src = (uint8_t *)src; ++ uint16x8_t m_prime = vdupq_n_u16(44497); ++ uint16x8_t m_res0 = vdupq_n_u16(0); ++ uint16x8_t m_res1 = vdupq_n_u16(0); ++ uint16x8_t m_res2 = vdupq_n_u16(0); ++ uint16x8_t m_res3 = vdupq_n_u16(0); ++ uint16x8_t m_res4 = vdupq_n_u16(0); ++ uint16x8_t m_res5 = vdupq_n_u16(0); ++ uint16x8_t m_res6 = vdupq_n_u16(0); ++ uint16x8_t m_res7 = vdupq_n_u16(0); ++ ++ for(int i=0; ipPager->pageSize, (unsigned char *)pPage->pData); + } +@@ -57072,8 +57125,15 @@ static void pager_set_pagehash(PgHdr *pPage){ + #define CHECK_PAGE(x) checkPage(x) + static void checkPage(PgHdr *pPg){ + Pager *pPager = pPg->pPager; +- assert( pPager->eState!=PAGER_ERROR ); +- assert( (pPg->flags&PGHDR_DIRTY) || pPg->pageHash==pager_pagehash(pPg) ); ++ if( pPager->eState==PAGER_ERROR ){ ++ return; ++ } ++ if( pPg->flags&PGHDR_DIRTY ) { ++ return; ++ } ++ if( pPg->pgno!=1 && pPg->pageHash!=pager_pagehash(pPg) ){ ++ sqlite3_log(SQLITE_CORRUPT, "cache corruption occurs through checking page(%u)", pPg->pgno); ++ } + } + + #else +@@ -178288,12 +178348,16 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo + *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager); + rc = SQLITE_OK; + }else if( op==SQLITE_FCNTL_RESERVE_BYTES ){ ++#ifndef SQLITE_CKSUMVFS_STATIC ++ rc = SQLITE_OK; ++#else + int iNew = *(int*)pArg; + *(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree); + if( iNew>=0 && iNew<=255 ){ + sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0); + } + rc = SQLITE_OK; ++#endif + }else if( op==SQLITE_FCNTL_RESET_CACHE ){ + sqlite3BtreeClearCache(pBtree); + rc = SQLITE_OK; +@@ -247458,6 +247522,27 @@ static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime + #endif + // hw export the symbols + #ifdef SQLITE_EXPORT_SYMBOLS ++#ifndef SQLITE_CKSUMVFS_STATIC ++int sqlite3_register_cksumvfs(const char *NotUsed){ ++ return SQLITE_MISUSE; ++} ++int sqlite3_unregister_cksumvfs(void){ ++ return SQLITE_MISUSE; ++} ++ ++struct sqlite3_api_routines_cksumvfs { ++ int (*register_cksumvfs)(const char *); ++ int (*unregister_cksumvfs)(); ++}; ++typedef struct sqlite3_api_routines_cksumvfs sqlite3_api_routines_cksumvfs; ++static const sqlite3_api_routines_cksumvfs sqlite3CksumvfsApis = { ++ sqlite3_register_cksumvfs, ++ sqlite3_unregister_cksumvfs ++}; ++ ++EXPORT_SYMBOLS const sqlite3_api_routines_cksumvfs *sqlite3_export_cksumvfs_symbols = &sqlite3CksumvfsApis; ++#endif ++ + struct sqlite3_api_routines_hw { + int (*initialize)(); + int (*config)(int,...); +-- +2.47.0.windows.2 + diff --git a/patch/0007-current-bugs-fixes.patch b/patch/0007-current-bugs-fixes.patch new file mode 100644 index 0000000..676e8c6 --- /dev/null +++ b/patch/0007-current-bugs-fixes.patch @@ -0,0 +1,83 @@ +From 064dc5a3f136f5135b3ae9d07a1662a2a569d98a Mon Sep 17 00:00:00 2001 +From: wanghaishuo +Date: Sat, 12 Apr 2025 11:13:36 +0800 +Subject: [PATCH 7/7] current bugs fixes + +Signed-off-by: ryne3366 +--- + src/sqlite3.c | 35 ++++++++++++++++++++++++++++------- + 1 file changed, 28 insertions(+), 7 deletions(-) + +diff --git a/src/sqlite3.c b/src/sqlite3.c +index f59ac55..fedd390 100644 +--- a/src/sqlite3.c ++++ b/src/sqlite3.c +@@ -43267,6 +43267,9 @@ static int unixOpen( + flags |= SQLITE_OPEN_READONLY; + openFlags |= O_RDONLY; + isReadonly = 1; ++#ifdef LOG_DUMP ++ sqlite3_log(SQLITE_WARNING, "Try open file readonly sysno %d", errno); ++#endif + fd = robust_open(zName, openFlags, openMode); + } + } +@@ -246320,7 +246323,7 @@ static int PragmaMetaDoubleWrie(sqlite3 *db, int iDb, Parse *parse, const char * + sqlite3_mutex_enter(db->mutex); + // only support enabled meta double write + int rc = MetaDwrOpenAndCheck(pBt); +- if (rc != SQLITE_OK) { ++ if (rc != SQLITE_OK && rc != SQLITE_PERM) { + parse->nErr++; + parse->rc = rc; + } +@@ -246776,6 +246779,29 @@ static inline const char *GetMetaFilePath(Pager *pPager) + return pPager->metaFd == NULL ? NULL : ((const char *)pPager->metaFd + ROUND8(pPager->pVfs->szOsFile)); + } + ++static int MetaDwrCheckPerm(sqlite3_vfs *pVfs, u8 openCreate, char *metaPath) { ++ int exists = 0; ++ int rc = sqlite3OsAccess(pVfs, metaPath, SQLITE_ACCESS_EXISTS, &exists); ++ if (rc != SQLITE_OK) { ++ return rc; ++ } ++ if (!exists && !openCreate) { ++ return SQLITE_PERM; ++ } ++#ifdef HARMONY_OS ++ // check if the path have enough permission ++ rc = osAccess(metaPath, W_OK|R_OK); ++ if (rc == 0 || errno == ENOENT) { ++ return SQLITE_OK; ++ } ++ rc = SQLITE_PERM; ++ if (openCreate) { ++ sqlite3_log(SQLITE_WARNING_DUMP, "Meta double write disabled, sysno %d", errno); ++ } ++#endif ++ return rc; ++} ++ + static int MetaDwrOpenFile(Pager *pPager, u8 openCreate) { + if (pPager->metaFd || pPager->zFilename == NULL) { + return SQLITE_OK; +@@ -246792,15 +246818,10 @@ static int MetaDwrOpenFile(Pager *pPager, u8 openCreate) { + return SQLITE_NOMEM_BKPT; + } + sqlite3_snprintf(size, metaPath, "%s-dwr", pPager->zFilename); +- int exists = 0; +- int rc = sqlite3OsAccess(pVfs, metaPath, SQLITE_ACCESS_EXISTS, &exists); ++ int rc = MetaDwrCheckPerm(pVfs, openCreate, metaPath); + if (rc != SQLITE_OK) { + goto INIT_META_OUT; + } +- if (!exists && !openCreate) { +- sqlite3_free(metaFd); +- goto INIT_META_OUT; +- } + u32 flags = (SQLITE_OPEN_READWRITE | SQLITE_OPEN_SUPER_JOURNAL); + if (openCreate) { + flags |= SQLITE_OPEN_CREATE; +-- +2.47.0.windows.2 + diff --git a/src/sqlite3.c b/src/sqlite3.c index fedd390..3469f92 100644 --- a/src/sqlite3.c +++ b/src/sqlite3.c @@ -779,7 +779,6 @@ SQLITE_API int sqlite3_exec( #define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ #define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ #define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ -#define SQLITE_META_RECOVERED 66 /* meta page recovered*/ /* end-of-error-codes */ /* @@ -871,7 +870,6 @@ SQLITE_API int sqlite3_exec( #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) -#define SQLITE_WARNING_DUMP (SQLITE_WARNING | (2<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) #define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */ @@ -2459,8 +2457,7 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ -#define SQLITE_CONFIG_CORRUPTION 30 /* xCorruption */ -#define SQLITE_CONFIG_ENABLE_ICU 31 /* boolean */ + /* ** CAPI3REF: Database Connection Configuration Options ** @@ -2835,11 +2832,6 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); */ SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); -#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -#define SQLITE_DBCONFIG_SET_SHAREDBLOCK 2004 -#define SQLITE_DBCONFIG_USE_SHAREDBLOCK 2005 -#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ - /* ** CAPI3REF: Set the Last Insert Rowid value. ** METHOD: sqlite3 @@ -3194,17 +3186,6 @@ SQLITE_API int sqlite3_get_table( ); SQLITE_API void sqlite3_free_table(char **result); -// hw export the symbols -#ifdef SQLITE_EXPORT_SYMBOLS -#if defined(__GNUC__) -# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) -#elif defined(_MSC_VER) -# define EXPORT_SYMBOLS __declspec(dllexport) -#else -# define EXPORT_SYMBOLS -#endif -#endif // SQLITE_EXPORT_SYMBOLS - /* ** CAPI3REF: Formatted String Printing Functions ** @@ -5193,10 +5174,6 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); */ SQLITE_API int sqlite3_step(sqlite3_stmt*); -#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK -SQLITE_API int sqlite3_set_droptable_handle(sqlite3*, void (*xFunc)(sqlite3*,const char*,const char*)); -#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ - /* ** CAPI3REF: Number of columns in a result set ** METHOD: sqlite3_stmt @@ -6462,44 +6439,6 @@ SQLITE_API int sqlite3_collation_needed16( void(*)(void*,sqlite3*,int eTextRep,const void*) ); -#ifdef SQLITE_HAS_CODEC -/* -** Specify the key for an encrypted database. This routine should be -** called right after sqlite3_open(). -** -** The code to implement this API is not available in the public release -** of SQLite. -*/ -SQLITE_API int sqlite3_key( - sqlite3 *db, /* Database to be rekeyed */ - const void *pKey, int nKey /* The key */ -); -SQLITE_API int sqlite3_key_v2( - sqlite3 *db, /* Database to be rekeyed */ - const char *zDbName, /* Name of the database */ - const void *pKey, int nKey /* The key */ -); - -/* -** Change the key on an open database. If the current database is not -** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the -** database is decrypted. -** -** The code to implement this API is not available in the public release -** of SQLite. -*/ -SQLITE_API int sqlite3_rekey( - sqlite3 *db, /* Database to be rekeyed */ - const void *pKey, int nKey /* The new key */ -); -SQLITE_API int sqlite3_rekey_v2( - sqlite3 *db, /* Database to be rekeyed */ - const char *zDbName, /* Name of the database */ - const void *pKey, int nKey /* The new key */ -); - -#endif /* SQLITE_HAS_CODEC */ - #ifdef SQLITE_ENABLE_CEROD /* ** Specify the activation key for a CEROD database. Unless @@ -9933,27 +9872,6 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); */ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); -#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -typedef struct Sqlite3SharedBlockMethods Sqlite3SharedBlockMethods; -struct Sqlite3SharedBlockMethods { - int iVersion; - void* pContext; - int countAllRows; - int startPos; - int requiredPos; - int (*xAddRow)(void* pCtx, int addedRows); - int (*xReset)(void* pCtx, int startPos); - int (*xFinish)(void* pCtx, int addedRows, int totalRows); - int (*xPutString)(void *pCtx, int addedRows, int column, const char* text, int len); - int (*xPutLong)(void *pCtx, int addedRows, int column, sqlite3_int64 value); - int (*xPutDouble)(void *pCtx, int addedRows, int column, double value); - int (*xPutBlob)(void *pCtx, int addedRows, int column, const void* blob, int len); - int (*xPutNull)(void *pCtx, int addedRows, int column); - int (*xPutOther)(void *pCtx, int addedRows, int column); - /* Additional methods may be added in future releases */ -}; -#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ - /* ** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE ** @@ -14977,6 +14895,7 @@ typedef int VList; # define SQLITE_OS_UNIX 0 #endif + #endif /* SQLITE_OS_SETUP_H */ /************** End of os_setup.h ********************************************/ @@ -14995,6 +14914,13 @@ typedef int VList; # 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 */ @@ -15308,9 +15234,6 @@ SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); /* Functions used to configure a Pager object. */ SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *); SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int); -#ifdef SQLITE_HAS_CODEC -SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager*, Pager*); -#endif /* SQLITE_HAS_CODEC */ SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager*, Pgno); SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int); SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int); @@ -15407,10 +15330,6 @@ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno); SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16); -#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) -SQLITE_PRIVATE void *sqlite3PagerCodec(DbPage *); -#endif /* defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) */ - /* Functions to support testing and debugging. */ #if !defined(NDEBUG) || defined(SQLITE_TEST) SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*); @@ -17014,21 +16933,6 @@ SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**); */ #define SQLITE_MAX_DB (SQLITE_MAX_ATTACHED+2) -#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK -typedef void (*sqlite3_xDropTableHandle)(sqlite3*, const char*, const char*); -#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ - -#if defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) -typedef struct CodecParameter { - int kdfIter; - int pageSize; - u8 cipher; - u8 hmacAlgo; - u8 kdfAlgo; - u8 reserved; -} CodecParameter; -#endif /* defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) */ - /* ** Each database connection is an instance of the following structure. */ @@ -17172,15 +17076,6 @@ struct sqlite3 { #ifdef SQLITE_USER_AUTHENTICATION sqlite3_userauth auth; /* User authentication information */ #endif -#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK - unsigned int isDropTable; - char *mDropTableName; - char *mDropSchemaName; - sqlite3_xDropTableHandle xDropTableHandle; /* User drop table callback */ -#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ -#if defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) - CodecParameter codecParm; -#endif /* defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) */ }; /* @@ -19555,8 +19450,6 @@ struct Sqlite3Config { int iOnceResetThreshold; /* When to reset OP_Once counters */ u32 szSorterRef; /* Min size in bytes to use sorter-refs */ unsigned int iPrngSeed; /* Alternative fixed seed for the PRNG */ - void (*xCorruption)(void *, const void *); - void *pCorruptionArg; /* vvvv--- must be last ---vvv */ #ifdef SQLITE_DEBUG sqlite3_int64 aTune[SQLITE_NTUNE]; /* Tuning parameters */ @@ -19808,57 +19701,6 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprLis } \ } -#define SQLITE_PRINT_CORRUPT_SIZE (SQLITE_PRINT_BUF_SIZE * 2) - -#define SQLITE_CORRUPT_CONTEXT(N,P,T,O,S,M,R) \ - { .nPage=(N), .pgno=(P), .type=(T), \ - .zoneRange={(O),(S)}, .zMsg=(M), .reservedArgs=(R) } - -typedef struct { - int offset; - size_t size; -}sqlite3CorruptRange; - -typedef enum { - CORRUPT_TYPE_PAGE_BTREE_LEAF, - CORRUPT_TYPE_PAGE_BTREE_INTERIOR, - CORRUPT_TYPE_PAGE_INDEX_LEAF, - CORRUPT_TYPE_PAGE_INDEX_INTERIOR, - CORRUPT_TYPE_PAGE_OVERFLOW, - CORRUPT_TYPE_PAGE_PTR_MAP, - CORRUPT_TYPE_PAGE_FREE_LIST, - CORRUPT_TYPE_FRAME_WAL, - CORRUPT_TYPE_ENTRY_JOURNAL, - CORRUPT_TYPE_VDBE, - CORRUPT_TYPE_FILE_HEADER, - CORRUPT_TYPE_UNKOWN, -} CorruptType; - -typedef struct { - size_t nPage; /* Number of pages */ - unsigned int pgno; /* Page number for corrupted page */ - CorruptType type; - sqlite3CorruptRange zoneRange; - const char *zMsg; - void *reservedArgs; -}sqlite3CorruptContext; - -// Encode buffer with base16, return size after encode -static size_t sqlite3base16Encode(const unsigned char *buffer, size_t bufSize, char *encodeBuf, size_t encodeBufSize) -{ - if (buffer == NULL || bufSize == 0 || encodeBuf == NULL || encodeBufSize == 0) { - return 0; - } - static const char base16Code[] = "0123456789ABCDEF"; - size_t i = 0; - for (; i < bufSize && (i * 2 < encodeBufSize - 1); i++) { - *encodeBuf++ = base16Code[(buffer[i] >> 4) & 0x0F]; - *encodeBuf++ = base16Code[buffer[i] & 0x0F]; - } - *encodeBuf = '\0'; - return i * 2; -} - /* ** The SQLITE_*_BKPT macros are substitutes for the error codes with ** the same name but without the _BKPT suffix. These macros invoke @@ -19867,11 +19709,10 @@ static size_t sqlite3base16Encode(const unsigned char *buffer, size_t bufSize, c ** to set a debugger breakpoint. */ SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType); -SQLITE_PRIVATE int sqlite3CorruptError(int lineno, sqlite3CorruptContext *context); +SQLITE_PRIVATE int sqlite3CorruptError(int); SQLITE_PRIVATE int sqlite3MisuseError(int); SQLITE_PRIVATE int sqlite3CantopenError(int); -#define SQLITE_CORRUPT_REPORT(context) sqlite3CorruptError(__LINE__,(context)) -#define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__,NULL) +#define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__) #define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__) #define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__) #ifdef SQLITE_DEBUG @@ -19883,13 +19724,12 @@ SQLITE_PRIVATE int sqlite3IoerrnomemError(int); # define SQLITE_NOMEM_BKPT SQLITE_NOMEM # define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM #endif -#if (defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO)) +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO) SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno); -# define SQLITE_CORRUPT_PGNO(P,context) sqlite3CorruptPgnoError(__LINE__,(P)) +# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P)) #else -# define SQLITE_CORRUPT_PGNO(P,context) sqlite3CorruptError(__LINE__,(context)) +# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__) #endif -# define SQLITE_CORRUPT_REPORT_PGNO(context) SQLITE_CORRUPT_PGNO((context)->pgno,(context)) /* ** FTS3 and FTS4 both require virtual table support @@ -20206,14 +20046,7 @@ SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u32,Select*); SQLITE_PRIVATE void sqlite3AddReturning(Parse*,ExprList*); SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*, sqlite3_vfs**,char**,char **); -#ifdef SQLITE_HAS_CODEC -SQLITE_PRIVATE int sqlite3CodecQueryParameters(sqlite3*,const char*,const char*); -#else -# define sqlite3CodecQueryParameters(A,B,C) 0 -#endif /* SQLITE_HAS_CODEC */ -#if defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) -SQLITE_PRIVATE void sqlite3CodecResetParameters(CodecParameter *p); -#endif /* defined(SQLITE_HAS_CODEC) && defined(SQLITE_CODEC_ATTACH_CHANGED) */ +#define sqlite3CodecQueryParameters(A,B,C) 0 SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*); #ifdef SQLITE_UNTESTABLE @@ -21265,10 +21098,6 @@ SQLITE_API extern int sqlite3_open_file_count; #define OpenCounter(X) #endif /* defined(SQLITE_TEST) */ -#ifdef FDSAN_ENABLE -#define SQLITE_FDSAN_TAG 5351 -#endif /* FDSAN_ENABLE */ - #endif /* !defined(_OS_COMMON_H_) */ /************** End of os_common.h *******************************************/ @@ -21651,9 +21480,6 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_FTS5_NO_WITHOUT_ROWID "FTS5_NO_WITHOUT_ROWID", #endif -#if SQLITE_HAS_CODEC - "HAS_CODEC", -#endif #if HAVE_ISNAN || SQLITE_HAVE_ISNAN "HAVE_ISNAN", #endif @@ -21662,9 +21488,6 @@ static const char * const sqlite3azCompileOpt[] = { "HOMEGROWN_RECURSIVE_MUTEX=" CTIMEOPT_VAL(SQLITE_HOMEGROWN_RECURSIVE_MUTEX), # endif #endif -#if SQLITE_SHARED_BLOCK_OPTIMIZATION - "SHARED_BLOCK_OPTIMIZATION", -#endif #ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS "IGNORE_AFP_LOCK_ERRORS", #endif @@ -22234,16 +22057,9 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { ** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally ** disabled. The default value may be changed by compiling with the ** SQLITE_USE_URI symbol defined. -** -** URI filenames are enabled by default if SQLITE_HAS_CODEC is -** enabled. */ #ifndef SQLITE_USE_URI -# ifdef SQLITE_HAS_CODEC -# define SQLITE_USE_URI 1 -# else -# define SQLITE_USE_URI 0 -# endif /* SQLITE_HAS_CODEC */ +# define SQLITE_USE_URI 0 #endif /* EVIDENCE-OF: R-38720-18127 The default setting is determined by the @@ -22368,8 +22184,6 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { 0x7ffffffe, /* iOnceResetThreshold */ SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */ 0, /* iPrngSeed */ - 0, /* xCorruption */ - 0, /* pCorruptionArg */ #ifdef SQLITE_DEBUG {0,0,0,0,0,0} /* aTune */ #endif @@ -22983,13 +22797,6 @@ struct Vdbe { int nScan; /* Entries in aScan[] */ ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */ #endif -#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION - Sqlite3SharedBlockMethods *pSharedBlock; - int totalRows; - int blockFull; - int startPos; - int addedRows; -#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ }; /* @@ -31356,11 +31163,7 @@ SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ */ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ StrAccum acc; /* String accumulator */ -#ifndef LOG_DUMP char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ -#else - char zMsg[SQLITE_PRINT_BUF_SIZE*10]; /* Complete log message */ -#endif /* !LOG_DUMP */ sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); sqlite3_str_vappendf(&acc, zFormat, ap); @@ -35038,7 +34841,7 @@ SQLITE_PRIVATE u8 sqlite3HexToInt(int h){ return (u8)(h & 0xf); } -#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) +#if !defined(SQLITE_OMIT_BLOB_LITERAL) /* ** Convert a BLOB literal of the form "x'hhhhhh'" into its binary ** value. Return a pointer to its binary value. Space to hold the @@ -35059,7 +34862,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){ } return zBlob; } -#endif /* !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) */ +#endif /* !SQLITE_OMIT_BLOB_LITERAL */ /* ** Log an error that is an API call on a connection pointer that should @@ -36859,45 +36662,6 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){ #endif /************** End of os_kv.c ***********************************************/ -/************** Define dump function *****************************************/ -#if SQLITE_OS_UNIX -#define DB_LOCK_NUM 3 -#define WAL_LOCK_NUM 9 -// 8 wal lock, 1 SHM_DMS lock, 1 TRX lock -#define MAX_LOCK_NUM (WAL_LOCK_NUM + 1) -#define SHM_DMS_IDX (WAL_LOCK_NUM - 1) -#define TRX_LOCK_IDX WAL_LOCK_NUM -#define LOCK_BY_PROCESS 1 -#define LOCK_BY_THREAD 0 -#define DUMP_BUF_MAX_LEN 180 -#define DUMP_MAX_STR_LEN 21 - -typedef struct LocalLockStatus { - u8 busyLockIdx; - u8 busyLockType; - u8 lockByProcess; - u8 reserved; - u32 lockLen; - u32 busyLine; - int curTid; - u8 lockStatus[MAX_LOCK_NUM]; // last index is trx lock -} LocalLockStatus; -__thread LocalLockStatus g_lockStatus = {0}; - -#define MARK_LAST_BUSY_LINE(rc) {if ((rc)==SQLITE_BUSY || (rc) == SQLITE_LOCKED) g_lockStatus.busyLine = __LINE__;} -static void ResetLockStatus(void); -static void TryRecordTid(int *tidBuf, int ofs, int lockLen); -static void TryClearTid(int *tidBuf, int ofs, int lockLen); -static void MarkLockBusy(u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess); -static void MarkLockStatus(u32 lockIdx, u32 lockLen, u8 lockType); -static void MarkLockStatusByRc(int rc, u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess); -#else -#define MARK_LAST_BUSY_LINE(rc) -#define ResetLockStatus(void) -#define MarkLockBusy(A, B, C, D) -#define MarkLockStatusByRc(A, B, C, D, E) -#endif -/************** End define dump function *************************************/ /************** Begin file os_unix.c *****************************************/ /* ** 2004 May 22 @@ -37259,29 +37023,6 @@ static pid_t randomnessPid = 0; #define F2FS_FEATURE_ATOMIC_WRITE 0x0004 #endif /* __linux__ */ -#ifdef HARMONY_OS -#define HMFS_MONITOR_FL 0x00000002 -#define HMFS_IOCTL_HW_GET_FLAGS _IOR(0xf5, 70, unsigned int) -#define HMFS_IOCTL_HW_SET_FLAGS _IOR(0xf5, 71, unsigned int) - -static void enableDbFileDelMonitor(int32_t fd) -{ - unsigned int flags = 0; - int ret = ioctl(fd, HMFS_IOCTL_HW_GET_FLAGS, &flags); - if (ret < 0) { - return; - } - if (flags & HMFS_MONITOR_FL) { - return; - } - flags |= HMFS_MONITOR_FL; - ret = ioctl(fd, HMFS_IOCTL_HW_SET_FLAGS, &flags); - if (ret < 0) { - sqlite3_log(SQLITE_WARNING, "Fd %d enable del monitor go wrong, errno = %d", fd, errno); - } -} - -#endif /* HARMONY_OS */ /* ** Different Unix systems declare open() in different ways. Same use @@ -37292,29 +37033,7 @@ static void enableDbFileDelMonitor(int32_t fd) ** which always has the same well-defined interface. */ static int posixOpen(const char *zFile, int flags, int mode){ - int fd = open(zFile, flags, mode); -#ifdef FDSAN_ENABLE - if( fd >= 0 ){ - fdsan_exchange_owner_tag(fd, 0, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, SQLITE_FDSAN_TAG)); - } -#endif /* FDSAN_ENABLE */ -#ifdef HARMONY_OS - if( fd >= 0 ){ - enableDbFileDelMonitor(fd); - } -#endif /* HARMONY_OS */ - return fd; -} - -/* -** Change close to posixClose, use fdsan_close_with_tag when fdsan enable. -*/ -static int posixClose(int fd) { -#ifdef FDSAN_ENABLE - return fdsan_close_with_tag(fd, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, SQLITE_FDSAN_TAG)); -#else - return close(fd); -#endif /* FDSAN_ENABLE */ + return open(zFile, flags, mode); } /* Forward reference */ @@ -37335,7 +37054,7 @@ static struct unix_syscall { { "open", (sqlite3_syscall_ptr)posixOpen, 0 }, #define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent) - { "close", (sqlite3_syscall_ptr)posixClose, 0 }, + { "close", (sqlite3_syscall_ptr)close, 0 }, #define osClose ((int(*)(int))aSyscall[1].pCurrent) { "access", (sqlite3_syscall_ptr)access, 0 }, @@ -38329,9 +38048,6 @@ static int findInodeInfo( #if defined(EOVERFLOW) && defined(SQLITE_DISABLE_LFS) if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS; #endif -#ifdef LOG_DUMP - sqlite3_log(SQLITE_IOERR, "findInodeInfo-osFstat, fd[%d], errno[%d], osFstat[%d]", fd, errno, rc); -#endif /* LOG_DUMP */ return SQLITE_IOERR; } @@ -38350,17 +38066,11 @@ static int findInodeInfo( do{ rc = osWrite(fd, "S", 1); }while( rc<0 && errno==EINTR ); if( rc!=1 ){ storeLastErrno(pFile, errno); -#ifdef LOG_DUMP - sqlite3_log(SQLITE_IOERR, "findInodeInfo-osWrite, fd[%d], errno[%d], osFstat[%d]", fd, errno, rc); -#endif /* LOG_DUMP */ return SQLITE_IOERR; } rc = osFstat(fd, &statbuf); if( rc!=0 ){ storeLastErrno(pFile, errno); -#ifdef LOG_DUMP - sqlite3_log(SQLITE_IOERR, "findInodeInfo-msdos-osFstat, fd[%d], errno[%d], osFstat[%d]", fd, errno, rc); -#endif /* LOG_DUMP */ return SQLITE_IOERR; } } @@ -38672,7 +38382,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){ if( pFile->eFileLock>=eFileLock ){ OSTRACE(("LOCK %d %s ok (already held) (unix)\n", pFile->h, azFileLock(eFileLock))); - MarkLockStatus(TRX_LOCK_IDX, 1, eFileLock); return SQLITE_OK; } @@ -38697,7 +38406,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){ (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK)) ){ rc = SQLITE_BUSY; - MarkLockBusy(TRX_LOCK_IDX, 1, eFileLock, LOCK_BY_THREAD); goto end_lock; } @@ -38713,7 +38421,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){ pFile->eFileLock = SHARED_LOCK; pInode->nShared++; pInode->nLock++; - MarkLockStatus(TRX_LOCK_IDX, 1, eFileLock); goto end_lock; } @@ -38735,11 +38442,11 @@ static int unixLock(sqlite3_file *id, int eFileLock){ if( rc!=SQLITE_BUSY ){ storeLastErrno(pFile, tErrno); } - MarkLockStatusByRc(rc, TRX_LOCK_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS); goto end_lock; } } + /* If control gets to this point, then actually go ahead and make ** operating system calls for the specified lock. */ @@ -38755,7 +38462,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); } - MarkLockStatusByRc(rc, TRX_LOCK_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS); + /* Drop the temporary PENDING lock */ lock.l_start = PENDING_BYTE; lock.l_len = 1L; @@ -38780,7 +38487,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){ /* We are trying for an exclusive lock but another thread in this ** same process is still holding a shared lock. */ rc = SQLITE_BUSY; - MarkLockBusy(TRX_LOCK_IDX, 1, eFileLock, LOCK_BY_THREAD); }else{ /* The request was for a RESERVED or EXCLUSIVE lock. It is ** assumed that there is a SHARED or greater lock on the file @@ -38805,7 +38511,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){ storeLastErrno(pFile, tErrno); } } - MarkLockStatusByRc(rc, TRX_LOCK_IDX, 1, eFileLock, LOCK_BY_PROCESS); } @@ -39003,6 +38708,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ pFile->eFileLock = NO_LOCK; } } + /* Decrement the count of locks against this same file. When the ** count reaches zero, close any other file descriptors whose close ** was deferred because of outstanding locks. @@ -39526,9 +39232,6 @@ static int flockUnlock(sqlite3_file *id, int eFileLock) { #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS return SQLITE_OK; #endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ -#ifdef LOG_DUMP - sqlite3_log(SQLITE_IOERR_UNLOCK, "IOERR_UNLOCK fd[%d], eFileLock[%d]", pFile->h, eFileLock); -#endif /* LOG_DUMP */ return SQLITE_IOERR_UNLOCK; }else{ pFile->eFileLock = NO_LOCK; @@ -40356,14 +40059,8 @@ static int unixRead( #ifdef EDEVERR case EDEVERR: #endif -#ifdef LOG_DUMP - sqlite3_log(SQLITE_IOERR_CORRUPTFS, "unixRead-EDEVERR, fd:[%d], amt[%d], got[%d], offset[%lld]", pFile->h, amt, got, offset); -#endif /* LOG_DUMP */ return SQLITE_IOERR_CORRUPTFS; } -#ifdef LOG_DUMP - sqlite3_log(SQLITE_IOERR_READ, "unixRead-got<0, fd: [%d], amt[%d], got[%d], offset[%lld]", pFile->h, amt, got, offset); -#endif /* LOG_DUMP */ return SQLITE_IOERR_READ; }else{ storeLastErrno(pFile, 0); /* not a system error */ @@ -40505,19 +40202,9 @@ static int unixWrite( if( amt>wrote ){ if( wrote<0 && pFile->lastErrno!=ENOSPC ){ /* lastErrno set by seekAndWrite */ -#ifdef LOG_DUMP - sqlite3_log(SQLITE_IOERR_WRITE, - "unixWrite, lastErrno set by seekAndWrite, fd[%d], offset[%lld], wrote[%d], amt[%d], lastErrno[%d]", - pFile->h, offset, wrote, amt, pFile->lastErrno); -#endif /* LOG_DUMP */ return SQLITE_IOERR_WRITE; }else{ storeLastErrno(pFile, 0); /* not a system error */ -#ifdef LOG_DUMP - sqlite3_log(SQLITE_FULL, - "unixWrite, not a system error, fd[%d], offset[%lld], wrote[%d], amt[%d], lastErrno[%d]", - pFile->h, offset, wrote, amt, pFile->lastErrno); -#endif /* LOG_DUMP */ return SQLITE_FULL; } } @@ -40871,14 +40558,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ do{ err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size); }while( err==EINTR ); - if( err && err!=EINVAL ) { -#ifdef LOG_DUMP - sqlite3_log(SQLITE_IOERR_WRITE, - "fcntlSizeHint-fallocate, fd[%d], bufSize[%lld], nSize[%lld] err[%d]", - pFile->h, buf.st_size, nSize, err); -#endif /* LOG_DUMP */ - return SQLITE_IOERR_WRITE; - } + if( err && err!=EINVAL ) return SQLITE_IOERR_WRITE; #else /* If the OS does not have posix_fallocate(), fake it. Write a ** single byte to the last byte in each block that falls entirely @@ -40897,14 +40577,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ for(/*no-op*/; iWrite=nSize ) iWrite = nSize - 1; nWrite = seekAndWrite(pFile, iWrite, "", 1); - if( nWrite!=1 ) { -#ifdef LOG_DUMP - sqlite3_log(SQLITE_IOERR_WRITE, - "fcntlSizeHint-seekAndWrite, fd[%d], nWrite[%d], nSize[%d], nBlk[%d], iWrite[%lld]", - pFile->h, nWrite, nSize, nBlk, iWrite); -#endif /* LOG_DUMP */ - return SQLITE_IOERR_WRITE; - } + if( nWrite!=1 ) return SQLITE_IOERR_WRITE; } #endif } @@ -40959,29 +40632,14 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ #if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: { int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE); -#ifdef LOG_DUMP - if( rc ){ - sqlite3_log(SQLITE_IOERR_BEGIN_ATOMIC, "unixFileControl-begin, fd[%d], op[%d]", pFile->h, op); - } -#endif /* LOG_DUMP */ return rc ? SQLITE_IOERR_BEGIN_ATOMIC : SQLITE_OK; } case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: { int rc = osIoctl(pFile->h, F2FS_IOC_COMMIT_ATOMIC_WRITE); -#ifdef LOG_DUMP - if( rc ){ - sqlite3_log(SQLITE_IOERR_COMMIT_ATOMIC, "unixFileControl-commit, fd[%d], op[%d]", pFile->h, op); - } -#endif /* LOG_DUMP */ return rc ? SQLITE_IOERR_COMMIT_ATOMIC : SQLITE_OK; } case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: { int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE); -#ifdef LOG_DUMP - if( rc ){ - sqlite3_log(SQLITE_IOERR_ROLLBACK_ATOMIC, "unixFileControl-rollback, fd[%d], op[%d]", pFile->h, op); - } -#endif /* LOG_DUMP */ return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK; } #endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ @@ -41299,7 +40957,6 @@ struct unixShmNode { int nRef; /* Number of unixShm objects pointing to this */ unixShm *pFirst; /* All unixShm objects pointing to this */ int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */ - int aLockTid[SQLITE_SHM_NLOCK]; #ifdef SQLITE_DEBUG u8 exclMask; /* Mask of exclusive locks held */ u8 sharedMask; /* Mask of shared locks held */ @@ -41542,8 +41199,6 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ rc = SQLITE_READONLY_CANTINIT; }else{ rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1); - MarkLockStatusByRc(rc, SHM_DMS_IDX, 1, EXCLUSIVE_LOCK, LOCK_BY_PROCESS); - MARK_LAST_BUSY_LINE(rc); /* 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 @@ -41555,15 +41210,11 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ } }else if( lock.l_type==F_WRLCK ){ rc = SQLITE_BUSY; - MarkLockStatusByRc(rc, SHM_DMS_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS); - MARK_LAST_BUSY_LINE(rc); } if( rc==SQLITE_OK ){ assert( lock.l_type==F_UNLCK || lock.l_type==F_RDLCK ); rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1); - MarkLockStatusByRc(rc, SHM_DMS_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS); - MARK_LAST_BUSY_LINE(rc); } return rc; } @@ -41934,22 +41585,11 @@ static int unixShmLock( int *aLock; p = pDbFd->pShm; - if( p==0 ) { -#ifdef LOG_DUMP - sqlite3_log(SQLITE_IOERR_SHMLOCK, "unixShmLock-pShm, fd[%d], ofst[%d], n[%d], flags[%d]", pDbFd->h, ofst, n, flags); -#endif - return SQLITE_IOERR_SHMLOCK; - } + if( p==0 ) return SQLITE_IOERR_SHMLOCK; pShmNode = p->pShmNode; - if( NEVER(pShmNode==0) ) { -#ifdef LOG_DUMP - sqlite3_log(SQLITE_IOERR_SHMLOCK, "unixShmLock-pShmNode, fd[%d], ofst[%d], n[%d], flags[%d]", pDbFd->h, ofst, n, flags); -#endif - return SQLITE_IOERR_SHMLOCK; - } + if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK; aLock = pShmNode->aLock; - int *aLockTid = pShmNode->aLockTid; - u8 useProcessLock = LOCK_BY_THREAD; + assert( pShmNode==pDbFd->pInode->pShmNode ); assert( pShmNode->pInode==pDbFd->pInode ); assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK ); @@ -42004,17 +41644,15 @@ static int unixShmLock( if( rc==SQLITE_OK ){ memset(&aLock[ofst], 0, sizeof(int)*n); } - useProcessLock = LOCK_BY_PROCESS; }else if( ALWAYS(p->sharedMask & (1<1 ); aLock[ofst]--; } - MarkLockStatusByRc(rc, ofst, n, NO_LOCK, useProcessLock); + /* Undo the local locks */ if( rc==SQLITE_OK ){ p->exclMask &= ~mask; p->sharedMask &= ~mask; - TryClearTid(aLockTid, ofst, n); } } }else if( flags & SQLITE_SHM_SHARED ){ @@ -42025,14 +41663,12 @@ static int unixShmLock( rc = SQLITE_BUSY; }else if( aLock[ofst]==0 ){ rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n); - useProcessLock = LOCK_BY_PROCESS; } - MarkLockStatusByRc(rc, ofst, n, SHARED_LOCK, useProcessLock); + /* Get the local shared locks */ if( rc==SQLITE_OK ){ p->sharedMask |= mask; aLock[ofst]++; - TryRecordTid(aLockTid, ofst, n); } } }else{ @@ -42051,17 +41687,14 @@ static int unixShmLock( ** also update the in-memory values. */ if( rc==SQLITE_OK ){ rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n); - useProcessLock = LOCK_BY_PROCESS; if( rc==SQLITE_OK ){ assert( (p->sharedMask & mask)==0 ); p->exclMask |= mask; for(ii=ofst; iipShmMutex); @@ -43267,9 +42900,6 @@ static int unixOpen( flags |= SQLITE_OPEN_READONLY; openFlags |= O_RDONLY; isReadonly = 1; -#ifdef LOG_DUMP - sqlite3_log(SQLITE_WARNING, "Try open file readonly sysno %d", errno); -#endif fd = robust_open(zName, openFlags, openMode); } } @@ -43329,9 +42959,6 @@ static int unixOpen( if( fstatfs(fd, &fsInfo) == -1 ){ storeLastErrno(p, errno); robust_close(p, fd, __LINE__); -#ifdef LOG_DUMP - sqlite3_log(SQLITE_IOERR_ACCESS, "unixOpen, fd[%d], flags[%d], errno[%d]", fd, errno, flags); -#endif /* LOG_DUMP */ return SQLITE_IOERR_ACCESS; } if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) { @@ -43472,184 +43099,6 @@ static int unixAccess( return SQLITE_OK; } -#ifdef HARMONY_OS -/* -** If the last component of the pathname in z[0]..z[j-1] is something -** other than ".." then back it out and return true. If the last -** component is empty or if it is ".." then return false. -*/ -static int unixBackupDir(const char *z, int *pJ){ - int j = *pJ; - int i; - if( j<=0 ) return 0; - for(i=j-1; i>0 && z[i-1]!='/'; i--){} - if( i==0 ) return 0; - if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0; - *pJ = i-1; - return 1; -} - -/* -** Convert a relative pathname into a full pathname. Also -** simplify the pathname as follows: -** -** Remove all instances of /./ -** Remove all isntances of /X/../ for any X -*/ -static int mkFullPathname( - const char *zPath, /* Input path */ - char *zOut, /* Output buffer */ - int nOut /* Allocated size of buffer zOut */ -){ - int nPath = sqlite3Strlen30(zPath); - int iOff = 0; - int i, j; - if( zPath[0]!='/' ){ - if( osGetcwd(zOut, nOut-2)==0 ){ - return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); - } - iOff = sqlite3Strlen30(zOut); - zOut[iOff++] = '/'; - } - if( (iOff+nPath+1)>nOut ){ - /* SQLite assumes that xFullPathname() nul-terminates the output buffer - ** even if it returns an error. */ - zOut[iOff] = '\0'; - return SQLITE_CANTOPEN_BKPT; - } - sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath); - - /* Remove duplicate '/' characters. Except, two // at the beginning - ** of a pathname is allowed since this is important on windows. */ - for(i=j=1; zOut[i]; i++){ - zOut[j++] = zOut[i]; - while( zOut[i]=='/' && zOut[i+1]=='/' ) i++; - } - zOut[j] = 0; - - assert( zOut[0]=='/' ); - for(i=j=0; zOut[i]; i++){ - if( zOut[i]=='/' ){ - /* Skip over internal "/." directory components */ - if( zOut[i+1]=='.' && zOut[i+2]=='/' ){ - i += 1; - continue; - } - - /* If this is a "/.." directory component then back out the - ** previous term of the directory if it is something other than "..". - */ - if( zOut[i+1]=='.' - && zOut[i+2]=='.' - && zOut[i+3]=='/' - && unixBackupDir(zOut, &j) - ){ - i += 2; - continue; - } - } - if( ALWAYS(j>=0) ) zOut[j] = zOut[i]; - j++; - } - if( NEVER(j==0) ) zOut[j++] = '/'; - zOut[j] = 0; - return SQLITE_OK; -} - -/* -** Turn a relative pathname into a full pathname. The relative path -** is stored as a nul-terminated string in the buffer pointed to by -** zPath. -** -** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes -** (in this case, MAX_PATHNAME bytes). The full-path is written to -** this buffer before returning. -*/ -static int unixFullPathname( - sqlite3_vfs *pVfs, /* Pointer to vfs object */ - const char *zPath, /* Possibly relative input path */ - int nOut, /* Size of output buffer in bytes */ - char *zOut /* Output buffer */ -){ -#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT) - return mkFullPathname(zPath, zOut, nOut); -#else - int rc = SQLITE_OK; - int nByte; - int nLink = 0; /* Number of symbolic links followed so far */ - const char *zIn = zPath; /* Input path for each iteration of loop */ - char *zDel = 0; - - assert( pVfs->mxPathname==MAX_PATHNAME ); - UNUSED_PARAMETER(pVfs); - - /* It's odd to simulate an io-error here, but really this is just - ** using the io-error infrastructure to test that SQLite handles this - ** function failing. This function could fail if, for example, the - ** current working directory has been unlinked. - */ - SimulateIOError( return SQLITE_ERROR ); - - do { - - /* Call stat() on path zIn. Set bLink to true if the path is a symbolic - ** link, or false otherwise. */ - int bLink = 0; - struct stat buf; - if( osLstat(zIn, &buf)!=0 ){ - if( errno!=ENOENT ){ - rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn); - } - }else{ - bLink = S_ISLNK(buf.st_mode); - } - - if( bLink ){ - nLink++; - if( zDel==0 ){ - zDel = sqlite3_malloc(nOut); - if( zDel==0 ) rc = SQLITE_NOMEM_BKPT; - }else if( nLink>=SQLITE_MAX_SYMLINKS ){ - rc = SQLITE_CANTOPEN_BKPT; - } - - if( rc==SQLITE_OK ){ - nByte = osReadlink(zIn, zDel, nOut-1); - if( nByte<0 ){ - rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn); - }else{ - if( zDel[0]!='/' ){ - int n; - for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--); - if( nByte+n+1>nOut ){ - rc = SQLITE_CANTOPEN_BKPT; - }else{ - memmove(&zDel[n], zDel, nByte+1); - memcpy(zDel, zIn, n); - nByte += n; - } - } - zDel[nByte] = '\0'; - } - } - - zIn = zDel; - } - - assert( rc!=SQLITE_OK || zIn!=zOut || zIn[0]=='/' ); - if( rc==SQLITE_OK && zIn!=zOut ){ - rc = mkFullPathname(zIn, zOut, nOut); - } - if( bLink==0 ) break; - zIn = zOut; - }while( rc==SQLITE_OK ); - - sqlite3_free(zDel); - if( rc==SQLITE_OK && nLink ) rc = SQLITE_OK_SYMLINK; - return rc; -#endif /* HAVE_READLINK && HAVE_LSTAT */ -} -#else /* ** A pathname under construction */ @@ -43707,7 +43156,7 @@ static void appendOnePathElement( }else if( S_ISLNK(buf.st_mode) ){ ssize_t got; char zLnk[SQLITE_MAX_PATHLEN+2]; - if( pPath->nSymlink++ > SQLITE_MAX_SYMLINKS ){ + if( pPath->nSymlink++ > SQLITE_MAX_SYMLINK ){ pPath->rc = SQLITE_CANTOPEN_BKPT; return; } @@ -43781,7 +43230,6 @@ static int unixFullPathname( if( path.nSymlink ) return SQLITE_OK_SYMLINK; return SQLITE_OK; } -#endif #ifndef SQLITE_OMIT_LOAD_EXTENSION /* @@ -44188,9 +43636,6 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){ if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){ OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n", lPath, errno, osGetpid(0))); -#ifdef LOG_DUMP - sqlite3_log(SQLITE_IOERR_LOCK, "proxyGetLockPath len[%d], dbLen[%d], i[%d]", len, dbLen, i); -#endif /* LOG_DUMP */ return SQLITE_IOERR_LOCK; } len = strlcat(lPath, "sqliteplocks", maxLen); @@ -44309,9 +43754,6 @@ static int proxyCreateUnixFile( case EACCES: return SQLITE_PERM; case EIO: -#ifdef LOG_DUMP - sqlite3_log(SQLITE_IOERR_LOCK, "proxyCreateUnixFile-EIO, fd[%d]", fd); -#endif /* LOG_DUMP */ return SQLITE_IOERR_LOCK; /* even though it is the conch */ default: return SQLITE_CANTOPEN_BKPT; @@ -44480,9 +43922,6 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ struct stat buf; if( osFstat(conchFile->h, &buf) ){ storeLastErrno(pFile, errno); -#ifdef LOG_DUMP - sqlite3_log(SQLITE_IOERR_LOCK, "proxyConchLock pFile fd[%d], conchFile fd[%d], lastErrno[%d]", pFile->h, conchFile->h, errno); -#endif /* LOG_DUMP */ return SQLITE_IOERR_LOCK; } @@ -44503,9 +43942,6 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0); if( len<0 ){ storeLastErrno(pFile, errno); -#ifdef LOG_DUMP - sqlite3_log(SQLITE_IOERR_LOCK, "proxyConchLock tries 2, pFile fd[%d], conchFile fd[%d], lastErrno[%d]", pFile->h, conchFile->h, errno); -#endif /* LOG_DUMP */ return SQLITE_IOERR_LOCK; } if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){ @@ -44580,9 +44016,6 @@ static int proxyTakeConch(unixFile *pFile){ if( readLen<0 ){ /* I/O error: lastErrno set by seekAndRead */ storeLastErrno(pFile, conchFile->lastErrno); -#ifdef LOG_DUMP - sqlite3_log(SQLITE_IOERR_READ, "proxyTakeConch pFile fd[%d], conchFile fd[%d], lastErrno[%d]", pFile->h, conchFile->h, conchFile->lastErrno); -#endif /* LOG_DUMP */ rc = SQLITE_IOERR_READ; goto end_takeconch; }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) || @@ -52445,6 +51878,13 @@ end_deserialize: return rc; } +/* +** Return true if the VFS is the memvfs. +*/ +SQLITE_PRIVATE int sqlite3IsMemdb(const sqlite3_vfs *pVfs){ + return pVfs==&memdb_vfs; +} + /* ** This routine is called when the extension is loaded. ** Register the new VFS. @@ -56161,20 +55601,6 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ */ #define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1) -#ifdef SQLITE_HAS_CODEC -/* -** A macro used for invoking the codec if there is one -*/ -# define CODEC1(P,D,N,X,E) \ - if( P->xCodec && P->xCodec(P->pCodec,D,N,X)==0 ){ E; } -# define CODEC2(P,D,N,X,E,O) \ - if( P->xCodec==0 ){ O=(char*)D; }else \ - if( (O=(char*)(P->xCodec(P->pCodec,D,N,X)))==0 ){ E; } -#else -# define CODEC1(P,D,N,X,E) /* NO-OP */ -# define CODEC2(P,D,N,X,E,O) O=(char*)D -#endif /* SQLITE_HAS_CODEC */ - /* ** The maximum allowed sector size. 64KiB. If the xSectorsize() method ** returns a value larger than this, then MAX_SECTOR_SIZE is used instead. @@ -56210,26 +55636,6 @@ struct PagerSavepoint { #endif }; -#if !defined(SQLITE_OS_UNIX) && defined(SQLITE_META_DWR) -#undef SQLITE_META_DWR -#endif - -#ifdef SQLITE_META_DWR -static int PragmaMetaDoubleWrie(sqlite3 *db, int iDb, Parse *parse, const char *zLeft, const char *zRight); -typedef struct MetaDwrHdr MetaDwrHdr; -static int MetaDwrWriteHeader(Pager *pPager, MetaDwrHdr *hdr); -static int MetaDwrUpdateMetaPages(Btree *pBt); -static void MetaDwrPagerRelease(Pager *pPager); -static int MetaDwrOpenFile(Pager *pPager, u8 openCreate); -static void MetaDwrCheckVacuum(BtShared *pBt); -static int MetaDwrRecoverAndBeginTran(Btree *pBt, int wrflag, int *pSchemaVersion); -static int MetaDwrOpenAndCheck(Btree *pBt); -static void MetaDwrDisable(Btree *pBt); -#define META_HEADER_CHANGED 1 -#define META_SCHEMA_CHANGED 2 -#define META_IN_RECOVERY 1 -#define META_RECOVER_SUCCESS 2 -#endif /* ** Bits of the Pager.doNotSpill flag. See further description below. */ @@ -56483,25 +55889,12 @@ struct Pager { #endif void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */ int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */ -#ifdef SQLITE_HAS_CODEC - void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ - void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */ - void (*xCodecFree)(void*); /* Destructor for the codec */ - void *pCodec; /* First argument to xCodec... methods */ -#endif /* SQLITE_HAS_CODEC */ char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ PCache *pPCache; /* Pointer to page cache object */ #ifndef SQLITE_OMIT_WAL Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */ char *zWal; /* File name for write-ahead log */ #endif -#ifdef SQLITE_META_DWR - u8 metaChanged; - sqlite3_file *metaFd; - MetaDwrHdr *metaHdr; - void *metaMapPage; - int (*xGetMethod)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */ -#endif }; /* @@ -56617,9 +56010,6 @@ static const unsigned char aJournalMagic[] = { SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){ if( pPager->fd->pMethods==0 ) return 0; if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; -#ifdef SQLITE_HAS_CODEC - if( pPager->xCodec!=0 ) return 0; -#endif /* SQLITE_HAS_CODEC */ #ifndef SQLITE_OMIT_WAL if( pPager->pWal ){ u32 iRead = 0; @@ -56853,19 +56243,11 @@ static void setGetterMethod(Pager *pPager){ if( pPager->errCode ){ pPager->xGet = getPageError; #if SQLITE_MAX_MMAP_SIZE>0 - }else if( USEFETCH(pPager) -#ifdef SQLITE_HAS_CODEC - && pPager->xCodec==0 -#endif /* SQLITE_HAS_CODEC */ - ){ + }else if( USEFETCH(pPager) ){ pPager->xGet = getPageMMap; #endif /* SQLITE_MAX_MMAP_SIZE>0 */ }else{ -#ifdef SQLITE_META_DWR - pPager->xGet = pPager->xGetMethod ? pPager->xGetMethod : getPageNormal; -#else pPager->xGet = getPageNormal; -#endif } } @@ -57049,70 +56431,17 @@ static int jrnlBufferSize(Pager *pPager){ ** and debugging only. */ #ifdef SQLITE_CHECK_PAGES -#if defined (__arm__) || defined (__aarch64__) -#include -u32 deep_fast_hash_arm(void *src, int srcLen){ - uint16_t chunkSize = srcLen/4; - uint8_t *u8p_src = (uint8_t *)src; - uint16x8_t m_prime = vdupq_n_u16(44497); - uint16x8_t m_res0 = vdupq_n_u16(0); - uint16x8_t m_res1 = vdupq_n_u16(0); - uint16x8_t m_res2 = vdupq_n_u16(0); - uint16x8_t m_res3 = vdupq_n_u16(0); - uint16x8_t m_res4 = vdupq_n_u16(0); - uint16x8_t m_res5 = vdupq_n_u16(0); - uint16x8_t m_res6 = vdupq_n_u16(0); - uint16x8_t m_res7 = vdupq_n_u16(0); - - for(int i=0; ipPager->pageSize, (unsigned char *)pPage->pData); } @@ -57128,15 +56457,8 @@ static void pager_set_pagehash(PgHdr *pPage){ #define CHECK_PAGE(x) checkPage(x) static void checkPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; - if( pPager->eState==PAGER_ERROR ){ - return; - } - if( pPg->flags&PGHDR_DIRTY ) { - return; - } - if( pPg->pgno!=1 && pPg->pageHash!=pager_pagehash(pPg) ){ - sqlite3_log(SQLITE_CORRUPT, "cache corruption occurs through checking page(%u)", pPg->pgno); - } + assert( pPager->eState!=PAGER_ERROR ); + assert( (pPg->flags&PGHDR_DIRTY) || pPg->pageHash==pager_pagehash(pPg) ); } #else @@ -57976,14 +57298,7 @@ static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){ } sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize); } -#ifdef SQLITE_META_DWR - if (bCommit && pPager->metaChanged != 0) { - sqlite3BeginBenignMalloc(); - (void)MetaDwrWriteHeader(pPager, pPager->metaHdr); - sqlite3EndBenignMalloc(); - pPager->metaChanged = 0; - } -#endif + if( pagerUseWal(pPager) ){ /* Drop the WAL write-lock, if any. Also, if the connection was in ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE @@ -58079,32 +57394,6 @@ static u32 pager_cksum(Pager *pPager, const u8 *aData){ return cksum; } -#ifdef SQLITE_HAS_CODEC -/* -** Report the current page size and number of reserved bytes back -** to the codec. -*/ -static void pagerReportSize(Pager *pPager){ - if( pPager->xCodecSizeChng ){ - pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize, - (int)pPager->nReserve); - } -} -/* -** Make sure the number of reserved bits is the same in the destination -** pager as it is in the source. This comes up when a VACUUM changes the -** number of reserved bits to the "optimal" amount. -*/ -SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager *pDest, Pager *pSrc){ - if( pDest->nReserve!=pSrc->nReserve ){ - pDest->nReserve = pSrc->nReserve; - pagerReportSize(pDest); - } -} -#else -# define pagerReportSize(X) /* No-op if we do not support a codec */ -#endif - /* ** Read a single page from either the journal file (if isMainJrnl==1) or ** from the sub-journal (if isMainJrnl==0) and playback that page. @@ -58156,11 +57445,6 @@ static int pager_playback_one_page( char *aData; /* Temporary storage for the page */ sqlite3_file *jfd; /* The file descriptor for the journal file */ int isSynced; /* True if journal page is synced */ -#ifdef SQLITE_HAS_CODEC - /* The jrnlEnc flag is true if Journal pages should be passed through - ** the codec. It is false for pure in-memory journals. */ - const int jrnlEnc = (isMainJrnl || pPager->subjInMemory==0); -#endif /* SQLITE_HAS_CODEC */ assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */ assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */ @@ -58290,26 +57574,12 @@ static int pager_playback_one_page( ** is if the data was just read from an in-memory sub-journal. In that ** case it must be encrypted here before it is copied into the database ** file. */ -#ifdef SQLITE_HAS_CODEC - if( !jrnlEnc ){ - CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData); - rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); - CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT); - }else -#endif /* SQLITE_HAS_CODEC */ rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); if( pgno>pPager->dbFileSize ){ pPager->dbFileSize = pgno; } if( pPager->pBackup ){ -#ifdef SQLITE_HAS_CODEC - if( jrnlEnc ){ - CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT); - sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); - CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT,aData); - }else -#endif /* SQLITE_HAS_CODEC */ sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); } }else if( !isMainJrnl && pPg==0 ){ @@ -58360,10 +57630,6 @@ static int pager_playback_one_page( if( pgno==1 ){ memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers)); } -#if SQLITE_HAS_CODEC - /* Decode the page just read from disk */ - if( jrnlEnc ){ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT); } -#endif /* SQLITE_HAS_CODEC */ sqlite3PcacheRelease(pPg); } return rc; @@ -58905,7 +58171,7 @@ static int readDbPage(PgHdr *pPg){ assert( isOpen(pPager->fd) ); if( pagerUseWal(pPager) ){ - rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); // find in wal-index + rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); if( rc ) return rc; } if( iFrame ){ @@ -58940,8 +58206,6 @@ static int readDbPage(PgHdr *pPg){ memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers)); } } - CODEC1(pPager, pPg->pData, pPg->pgno, 3, rc = SQLITE_NOMEM_BKPT); - PAGER_INCR(sqlite3_pager_readdb_count); PAGER_INCR(pPager->nRead); IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno)); @@ -60060,9 +59324,6 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,a); pPager->pWal = 0; } -#endif -#ifdef SQLITE_META_DWR - MetaDwrPagerRelease(pPager); #endif pager_reset(pPager); if( MEMDB ){ @@ -60092,10 +59353,6 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ sqlite3OsClose(pPager->fd); sqlite3PageFree(pTmp); sqlite3PcacheClose(pPager->pPCache); -#ifdef SQLITE_HAS_CODEC - if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec); -#endif /* SQLITE_HAS_CODEC */ - assert( !pPager->aSavepoint && !pPager->pInJournal ); assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) ); @@ -60164,7 +59421,6 @@ static int syncJournal(Pager *pPager, int newHdr){ assert( !pagerUseWal(pPager) ); rc = sqlite3PagerExclusiveLock(pPager); - MARK_LAST_BUSY_LINE(rc); if( rc!=SQLITE_OK ) return rc; if( !pPager->noSync ){ @@ -60347,7 +59603,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ assert( (pList->flags&PGHDR_NEED_SYNC)==0 ); if( pList->pgno==1 ) pager_write_changecounter(pList); - CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM_BKPT, pData); + pData = pList->pData; /* Write out the page data. */ rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset); @@ -60436,11 +59692,6 @@ static int subjournalPage(PgHdr *pPg){ void *pData = pPg->pData; i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize); char *pData2; -#if SQLITE_HAS_CODEC - if( !pPager->subjInMemory ){ - CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2); - }else -#endif /* SQLITE_HAS_CODEC */ pData2 = pData; PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno)); rc = write32bits(pPager->sjfd, offset, pPg->pgno); @@ -60909,11 +60160,7 @@ act_like_temp_file: rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb, !memDb?pagerStress:0, (void *)pPager, pPager->pPCache); } -#ifdef SQLITE_META_DWR - if( rc==SQLITE_OK && !memDb && !readOnly){ - (void)MetaDwrOpenFile(pPager, 0); - } -#endif + /* If an error occurred above, free the Pager structure and close the file. */ if( rc!=SQLITE_OK ){ @@ -61076,7 +60323,6 @@ static int hasHotJournal(Pager *pPager, int *pExists){ sqlite3OsDelete(pVfs, pPager->zJournal, 0); if( !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK); } - MARK_LAST_BUSY_LINE(rc); sqlite3EndBenignMalloc(); }else{ /* The journal file exists and no other connection has a reserved @@ -61166,7 +60412,6 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ assert( pPager->tempFile==0 || pPager->eLock==EXCLUSIVE_LOCK ); rc = pager_wait_on_lock(pPager, SHARED_LOCK); - MARK_LAST_BUSY_LINE(rc); if( rc!=SQLITE_OK ){ assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK ); goto failed; @@ -61203,7 +60448,6 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ ** downgraded to SHARED_LOCK before this function returns. */ rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); - MARK_LAST_BUSY_LINE(rc); if( rc!=SQLITE_OK ){ goto failed; } @@ -61345,6 +60589,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ if( pPager->tempFile==0 && pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){ rc = pagerPagecount(pPager, &pPager->dbSize); } + failed: if( rc!=SQLITE_OK ){ assert( !MEMDB ); @@ -61445,12 +60690,7 @@ static int getPageNormal( assert( assert_pager_state(pPager) ); assert( pPager->hasHeldSharedLock==1 ); - if( pgno==0 ) { - const char *zMsg = "pgno should not be 0"; - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, 0, CORRUPT_TYPE_UNKOWN, - -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_REPORT(&context); - } + if( pgno==0 ) return SQLITE_CORRUPT_BKPT; pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3); if( pBase==0 ){ pPg = 0; @@ -61482,11 +60722,7 @@ static int getPageNormal( ** (2) Never try to fetch the locking page */ if( pgno==PAGER_SJ_PGNO(pPager) ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "try fetching the locking page(%u)", pgno); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, pgno, CORRUPT_TYPE_UNKOWN, - -1, 0, zMsg, NULL); - rc = SQLITE_CORRUPT_REPORT(&context); + rc = SQLITE_CORRUPT_BKPT; goto pager_acquire_err; } @@ -61559,19 +60795,13 @@ static int getPageMMap( ); assert( USEFETCH(pPager) ); -#ifdef SQLITE_HAS_CODEC - assert( pPager->xCodec==0 ); -#endif /* SQLITE_HAS_CODEC */ /* Optimization note: Adding the "pgno<=1" term before "pgno==0" here ** allows the compiler optimizer to reuse the results of the "pgno>1" ** test in the previous statement, and avoid testing pgno==0 in the ** common case where pgno is large. */ if( pgno<=1 && pgno==0 ){ - const char *zMsg = "pgno should not be 0"; - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, 0, CORRUPT_TYPE_UNKOWN, - -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_REPORT(&context); + return SQLITE_CORRUPT_BKPT; } assert( pPager->eState>=PAGER_READER ); assert( assert_pager_state(pPager) ); @@ -61829,7 +61059,6 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory */ if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){ rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); - MARK_LAST_BUSY_LINE(rc); if( rc!=SQLITE_OK ){ return rc; } @@ -61842,7 +61071,6 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory ** holds the write-lock. If possible, the upper layer will call it. */ rc = sqlite3WalBeginWriteTransaction(pPager->pWal); - MARK_LAST_BUSY_LINE(rc); }else{ /* Obtain a RESERVED lock on the database file. If the exFlag parameter ** is true, then immediately upgrade this to an EXCLUSIVE lock. The @@ -61850,10 +61078,8 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory ** lock, but not when obtaining the RESERVED lock. */ rc = pagerLockDb(pPager, RESERVED_LOCK); - MARK_LAST_BUSY_LINE(rc); if( rc==SQLITE_OK && exFlag ){ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); - MARK_LAST_BUSY_LINE(rc); } } @@ -61899,7 +61125,7 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){ assert( pPg->pgno!=PAGER_SJ_PGNO(pPager) ); assert( pPager->journalHdr<=pPager->journalOff ); - CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2); + pData2 = pPg->pData; cksum = pager_cksum(pPager, (u8*)pData2); /* Even if an IO or diskfull error occurs while journalling the @@ -62264,7 +61490,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){ if( DIRECT_MODE ){ const void *zBuf; assert( pPager->dbFileSize>0 ); - CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM_BKPT, zBuf); + zBuf = pPgHdr->pData; if( rc==SQLITE_OK ){ rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0); pPager->aStat[PAGER_STAT_WRITE]++; @@ -62624,6 +61850,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){ pPager->eState = PAGER_READER; return SQLITE_OK; } + PAGERTRACE(("COMMIT %d\n", PAGERID(pPager))); rc = pager_end_transaction(pPager, pPager->setSuper, 1); return pager_error(pPager, rc); @@ -63015,48 +62242,6 @@ SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){ return pPager->zJournal; } -#ifdef SQLITE_HAS_CODEC -/* -** Set or retrieve the codec for this pager -*/ -SQLITE_PRIVATE void sqlite3PagerSetCodec( - Pager *pPager, - void *(*xCodec)(void*,void*,Pgno,int), - void (*xCodecSizeChng)(void*,int,int), - void (*xCodecFree)(void*), - void *pCodec -){ - if( pPager->xCodecFree ){ - pPager->xCodecFree(pPager->pCodec); - }else{ - pager_reset(pPager); - } - pPager->xCodec = pPager->memDb ? 0 : xCodec; - pPager->xCodecSizeChng = xCodecSizeChng; - pPager->xCodecFree = xCodecFree; - pPager->pCodec = pCodec; - setGetterMethod(pPager); - pagerReportSize(pPager); -} -SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){ - return pPager->pCodec; -} - -/* -** This function is called by the wal module when writing page content -** into the log file. -** -** This function returns a pointer to a buffer containing the encrypted -** page content. If a malloc fails, this function may return NULL. -*/ -SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){ - void *aData = 0; - CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData); - return aData; -} - -#endif /* SQLITE_HAS_CODEC */ - #ifndef SQLITE_OMIT_AUTOVACUUM /* ** Move the page pPg to location pgno in the file. @@ -63157,11 +62342,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i if( pPgOld ){ if( NEVER(pPgOld->nRef>1) ){ sqlite3PagerUnrefNotNull(pPgOld); - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "page(%u) should be no references, ref cnt:%d", pgno, (int)pPgOld->nRef); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, pgno, CORRUPT_TYPE_UNKOWN, - -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_REPORT(&context); + return SQLITE_CORRUPT_BKPT; } pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); if( pPager->tempFile ){ @@ -63357,7 +62538,6 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ if( pPager->eState==PAGER_READER ){ assert( rc==SQLITE_OK ); rc = pagerLockDb(pPager, RESERVED_LOCK); - MARK_LAST_BUSY_LINE(rc); } if( rc==SQLITE_OK ){ sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); @@ -63522,7 +62702,6 @@ static int pagerOpenWal(Pager *pPager){ */ if( pPager->exclusiveMode ){ rc = pagerExclusiveLock(pPager); - MARK_LAST_BUSY_LINE(rc); } /* Open the connection to the log file. If this operation fails, @@ -63606,7 +62785,6 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){ if( !pPager->pWal ){ int logexists = 0; rc = pagerLockDb(pPager, SHARED_LOCK); - MARK_LAST_BUSY_LINE(rc); if( rc==SQLITE_OK ){ rc = sqlite3OsAccess( pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &logexists @@ -63622,7 +62800,6 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){ */ if( rc==SQLITE_OK && pPager->pWal ){ rc = pagerExclusiveLock(pPager); - MARK_LAST_BUSY_LINE(rc); if( rc==SQLITE_OK ){ rc = sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize, (u8*)pPager->pTmpSpace); @@ -64929,13 +64106,7 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ /* Write the aPgno[] array entry and the hash-table slot. */ nCollide = idx; for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ - if( (nCollide--)==0 ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "no place for page(%u) to map into WAL, idx:%d", iPage, idx); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, iPage, CORRUPT_TYPE_FRAME_WAL, - -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_REPORT(&context); - } + if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT; } sLoc.aPgno[idx-1] = iPage; AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx); @@ -65003,7 +64174,6 @@ static int walIndexRecover(Wal *pWal){ iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock; rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock); if( rc ){ - MARK_LAST_BUSY_LINE(rc); return rc; } @@ -65767,11 +64937,6 @@ static void walRestartHdr(Wal *pWal, u32 salt1){ assert( pInfo->aReadMark[0]==0 ); } -#ifdef SQLITE_HDR_CHECK -static int checkHeaderValid(Pager *pager, u8 *zBuf, const char *logStr); -static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf); -#endif /* SQLITE_HDR_CHECK */ - /* ** Copy as much content as we can from the WAL back into the database file ** in response to an sqlite3_wal_checkpoint() request or the equivalent. @@ -65844,7 +65009,6 @@ static int walCheckpoint( if( mxSafeFrame>y ){ assert( y<=pWal->hdr.mxFrame ); rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1); - MARK_LAST_BUSY_LINE(rc); if( rc==SQLITE_OK ){ u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED); AtomicStore(pInfo->aReadMark+i, iMark); @@ -65888,13 +65052,7 @@ static int walCheckpoint( ** database plus the amount of data in the wal file, plus the ** maximum size of the pending-byte page (65536 bytes), then ** must be corruption somewhere. */ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, - "final db size unexpected,nSize=%lld,mxFrame=%u,pageSize=%d,nReq=%lld", - nSize, pWal->hdr.mxFrame, szPage, nReq); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, 0, CORRUPT_TYPE_FRAME_WAL, - -1, 0, zMsg, NULL); - rc = SQLITE_CORRUPT_REPORT(&context); + rc = SQLITE_CORRUPT_BKPT; }else{ sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT,&nReq); } @@ -65919,10 +65077,6 @@ static int walCheckpoint( if( rc!=SQLITE_OK ) break; iOffset = (iDbpage-1)*(i64)szPage; testcase( IS_BIG_INT(iOffset) ); -#ifdef SQLITE_HDR_CHECK - rc = checkDbHeaderValid(db, iDbpage, zBuf); - if( rc!=SQLITE_OK ) break; -#endif /* SQLITE_HDR_CHECK */ rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); if( rc!=SQLITE_OK ) break; } @@ -65945,9 +65099,8 @@ static int walCheckpoint( /* Release the reader lock held while backfilling */ walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1); - } else { - MARK_LAST_BUSY_LINE(rc); } + if( rc==SQLITE_BUSY ){ /* Reset the return code so as not to report a checkpoint failure ** just because there are active readers. */ @@ -65964,13 +65117,11 @@ static int walCheckpoint( assert( pWal->writeLock ); if( pInfo->nBackfillhdr.mxFrame ){ rc = SQLITE_BUSY; - MARK_LAST_BUSY_LINE(rc); }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){ u32 salt1; sqlite3_randomness(4, &salt1); assert( pInfo->nBackfill==pWal->hdr.mxFrame ); rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1); - MARK_LAST_BUSY_LINE(rc); if( rc==SQLITE_OK ){ if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){ /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as @@ -66068,8 +65219,6 @@ SQLITE_PRIVATE int sqlite3WalClose( walLimitSize(pWal, 0); } } - } else { - MARK_LAST_BUSY_LINE(rc); } walIndexClose(pWal, isDelete); @@ -66224,7 +65373,6 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ walUnlockShared(pWal, WAL_WRITE_LOCK); rc = SQLITE_READONLY_RECOVERY; } - MARK_LAST_BUSY_LINE(rc); }else{ int bWriteLock = pWal->writeLock; if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){ @@ -66245,7 +65393,6 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); } } - MARK_LAST_BUSY_LINE(rc); } } @@ -66265,7 +65412,6 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ ** writer truncated the WAL out from under it. If that happens, it ** indicates that a writer has fixed the SHM file for us, so retry */ if( rc==SQLITE_IOERR_SHORT_READ ) rc = WAL_RETRY; - MARK_LAST_BUSY_LINE(rc); } pWal->exclusiveMode = WAL_NORMAL_MODE; } @@ -66497,7 +65643,6 @@ 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 void DumpLocksByWal(Wal *pWal); static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */ u32 mxReadMark; /* Largest aReadMark[] value */ @@ -66535,9 +65680,6 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ return SQLITE_PROTOCOL; } if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39; -#if SQLITE_OS_UNIX - if( cnt>=15 ) DumpLocksByWal(pWal); -#endif /* SQLITE_OS_UNIX */ sqlite3OsSleep(pWal->pVfs, nDelay); } @@ -66564,14 +65706,11 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** must be zeroed before the requested page is returned. */ rc = WAL_RETRY; - MARK_LAST_BUSY_LINE(SQLITE_BUSY); }else if( SQLITE_OK==(rc = walLockShared(pWal, WAL_RECOVER_LOCK)) ){ walUnlockShared(pWal, WAL_RECOVER_LOCK); rc = WAL_RETRY; - MARK_LAST_BUSY_LINE(SQLITE_BUSY); }else if( rc==SQLITE_BUSY ){ rc = SQLITE_BUSY_RECOVERY; - MARK_LAST_BUSY_LINE(SQLITE_BUSY); } } if( rc!=SQLITE_OK ){ @@ -66594,7 +65733,6 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** and can be safely ignored. */ rc = walLockShared(pWal, WAL_READ_LOCK(0)); - MARK_LAST_BUSY_LINE(SQLITE_BUSY); walShmBarrier(pWal); if( rc==SQLITE_OK ){ if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){ @@ -66612,7 +65750,6 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** it finished. Leaving a corrupt image in the database file. */ walUnlockShared(pWal, WAL_READ_LOCK(0)); - MARK_LAST_BUSY_LINE(SQLITE_BUSY); return WAL_RETRY; } pWal->readLock = 0; @@ -66657,7 +65794,6 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ }else if( rc!=SQLITE_BUSY ){ return rc; } - MARK_LAST_BUSY_LINE(rc); } } if( mxI==0 ){ @@ -66667,7 +65803,6 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ rc = walLockShared(pWal, WAL_READ_LOCK(mxI)); if( rc ){ - MARK_LAST_BUSY_LINE(rc); return rc==SQLITE_BUSY ? WAL_RETRY : rc; } /* Now that the read-lock has been obtained, check that neither the @@ -66710,7 +65845,6 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){ walUnlockShared(pWal, WAL_READ_LOCK(mxI)); - MARK_LAST_BUSY_LINE(rc); return WAL_RETRY; }else{ assert( mxReadMark<=pWal->hdr.mxFrame ); @@ -66837,7 +65971,6 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ (void)walEnableBlocking(pWal); rc = walLockShared(pWal, WAL_CKPT_LOCK); walDisableBlocking(pWal); - MARK_LAST_BUSY_LINE(rc); if( rc!=SQLITE_OK ){ return rc; @@ -67005,11 +66138,7 @@ SQLITE_PRIVATE int sqlite3WalFindFrame( iRead = iFrame; } if( (nCollide--)==0 ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "mis-match page(%u) to map into WAL", pgno); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, pgno, CORRUPT_TYPE_FRAME_WAL, - -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_REPORT(&context); + return SQLITE_CORRUPT_BKPT; } iKey = walNextHash(iKey); } @@ -67342,18 +66471,7 @@ static int walWriteOneFrame( int rc; /* Result code from subfunctions */ void *pData; /* Data actually written */ u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */ -#ifdef SQLITE_HDR_CHECK - if( pPage->pgno==1 ){ - rc = checkHeaderValid(pPage->pPager, pPage->pData, "walWrite"); - if( rc!=SQLITE_OK ) return rc; - } -#endif /* SQLITE_HDR_CHECK */ - -#ifdef SQLITE_HAS_CODEC - if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT; -#else pData = pPage->pData; -#endif /* SQLITE_HAS_CODEC */ walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame); rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset); if( rc ) return rc; @@ -67536,11 +66654,7 @@ SQLITE_PRIVATE int sqlite3WalFrames( if( pWal->iReCksum==0 || iWriteiReCksum ){ pWal->iReCksum = iWrite; } -#ifdef SQLITE_HAS_CODEC - if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM; -#else pData = p->pData; -#endif /* SQLITE_HAS_CODEC */ rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff); if( rc ) return rc; p->flags &= ~PGHDR_WAL_APPEND; @@ -67651,10 +66765,6 @@ SQLITE_PRIVATE int sqlite3WalFrames( return rc; } -#ifdef LOG_DUMP -static sqlite3_int64 g_lastCkptTime = 0; -#endif /* LOG_DUMP */ - /* ** This routine is called to implement sqlite3_wal_checkpoint() and ** related interfaces. @@ -67665,7 +66775,6 @@ static sqlite3_int64 g_lastCkptTime = 0; ** If parameter xBusy is not NULL, it is a pointer to a busy-handler ** callback. In this case this function runs a blocking checkpoint. */ -static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime); SQLITE_PRIVATE int sqlite3WalCheckpoint( Wal *pWal, /* Wal connection */ sqlite3 *db, /* Check this handle's interrupt flag */ @@ -67707,7 +66816,6 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( ** it will not be invoked in this case. */ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); - MARK_LAST_BUSY_LINE(rc); testcase( rc==SQLITE_BUSY ); testcase( rc!=SQLITE_OK && xBusy2!=0 ); if( rc==SQLITE_OK ){ @@ -67724,7 +66832,6 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( */ if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){ rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1); - MARK_LAST_BUSY_LINE(rc); if( rc==SQLITE_OK ){ pWal->writeLock = 1; }else if( rc==SQLITE_BUSY ){ @@ -67750,19 +66857,9 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( if( rc==SQLITE_OK ){ if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "mis-match between pageSize=%d and bufferSize=%d, mxFrame=%u", - walPagesize(pWal),nBuf,pWal->hdr.mxFrame); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, 0, CORRUPT_TYPE_FRAME_WAL, - -1, 0, zMsg, NULL); - rc = SQLITE_CORRUPT_REPORT(&context); - }else{ - sqlite3_int64 startTime; - sqlite3OsCurrentTimeInt64(db->pVfs, &startTime); + rc = SQLITE_CORRUPT_BKPT; + }else{ rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf); - if (rc == SQLITE_OK){ - walLogCheckpointInfo(pWal, db, startTime); - } } /* If no error occurred, set the output variables. */ @@ -67791,12 +66888,6 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1); pWal->ckptLock = 0; } -#ifdef LOG_DUMP - if( rc ){ - sqlite3_log(SQLITE_NOTICE, "ckpt rc[%d]", rc); - } - sqlite3OsCurrentTimeInt64(db->pVfs, &g_lastCkptTime); -#endif /* LOG_DUMP */ WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok")); #ifdef SQLITE_ENABLE_SETLK_TIMEOUT if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY; @@ -68479,10 +67570,6 @@ struct BtShared { #endif u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ int nPreformatSize; /* Size of last cell written by TransferRow() */ -#ifdef SQLITE_META_DWR - u32 maxMetaPage; - u32 metaRecoverStatus; -#endif }; /* @@ -69177,32 +68264,6 @@ SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){ } #endif -#ifdef SQLITE_HDR_CHECK -static int checkHeaderValid(Pager *pager, u8 *zBuf, const char *logStr){ -#ifdef SQLITE_HAS_CODEC - if( pager==NULL || pager->pCodec ){ - return SQLITE_OK; - } -#endif /* SQLITE_HAS_CODEC */ - if( zBuf && strncmp((const char *)zBuf, zMagicHeader, 16)!=0 ){ - sqlite3_log(SQLITE_NOTADB, "[%s]wrong header format, memory might be overwritten!", logStr); - return SQLITE_NOTADB; - } - return SQLITE_OK; -} - -static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf){ - if( iDbpage==1 && db->aDb ){ - Btree *p = db->aDb[0].pBt; - if( p && p->pBt ){ - Pager *pager = sqlite3BtreePager(p); - return checkHeaderValid(pager, zBuf, "ckpt"); - } - } - return SQLITE_OK; -} -#endif /* SQLITE_HDR_CHECK */ - /* ** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single ** (MemPage*) as an argument. The (MemPage*) must not be NULL. @@ -69213,7 +68274,7 @@ static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf){ ** with the page number and filename associated with the (MemPage*). */ #ifdef SQLITE_DEBUG -int corruptPageError(int lineno, MemPage *p, sqlite3CorruptContext *context){ +int corruptPageError(int lineno, MemPage *p){ char *zMsg; sqlite3BeginBenignMalloc(); zMsg = sqlite3_mprintf("database corruption page %d of %s", @@ -69224,11 +68285,11 @@ int corruptPageError(int lineno, MemPage *p, sqlite3CorruptContext *context){ sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg); } sqlite3_free(zMsg); - return SQLITE_CORRUPT_REPORT(context); + return SQLITE_CORRUPT_BKPT; } -# define SQLITE_CORRUPT_PAGE(context,pMemPage) corruptPageError(__LINE__, (pMemPage),(context)) +# define SQLITE_CORRUPT_PAGE(pMemPage) corruptPageError(__LINE__, pMemPage) #else -# define SQLITE_CORRUPT_PAGE(context,pMemPage) SQLITE_CORRUPT_PGNO((pMemPage)->pgno,(context)) +# define SQLITE_CORRUPT_PAGE(pMemPage) SQLITE_CORRUPT_PGNO(pMemPage->pgno) #endif #ifndef SQLITE_OMIT_SHARED_CACHE @@ -69906,12 +68967,7 @@ static int btreeMoveto( if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT; sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey); if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpected fields in total:%u, should != 0 and < %u", - pIdxKey->nField,pKeyInfo->nAllField); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pCur->pBt->nPage, 0, CORRUPT_TYPE_PAGE_BTREE_LEAF, - -1, 0, zMsg, NULL); - rc = SQLITE_CORRUPT_REPORT(&context); + rc = SQLITE_CORRUPT_BKPT; }else{ rc = sqlite3BtreeIndexMoveto(pCur, pIdxKey, pRes); } @@ -70091,7 +69147,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) ); assert( pBt->autoVacuum ); - if( key==0 ){ // The pgno of each entry on ptrmap page starts from 3, an unexpected pgno indicates data corrupted + if( key==0 ){ *pRC = SQLITE_CORRUPT_BKPT; return; } @@ -70105,24 +69161,12 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ /* The first byte of the extra data is the MemPage.isInit byte. ** If that byte is set, it means this page is also being used ** as a btree page. */ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode((unsigned char *)sqlite3PagerGetExtra(pDbPage), 8, xBuffer, sizeof(xBuffer)); - sqlite3_snprintf(sizeof(zMsg), zMsg, "page(%u) been initialized before as a btree page, base16:%s", - iPtrmap, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, - -1, 0, zMsg, NULL); - *pRC = SQLITE_CORRUPT_REPORT(&context); + *pRC = SQLITE_CORRUPT_BKPT; goto ptrmap_exit; } offset = PTRMAP_PTROFFSET(iPtrmap, key); if( offset<0 ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpect offset in ptrmap page(%u), target:%u, page usableSize=%u", - iPtrmap, key, pBt->usableSize); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, - -1, 0, zMsg, NULL); - *pRC = SQLITE_CORRUPT_REPORT(&context); + *pRC = SQLITE_CORRUPT_BKPT; goto ptrmap_exit; } assert( offset <= (int)pBt->usableSize-5 ); @@ -70167,12 +69211,7 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ offset = PTRMAP_PTROFFSET(iPtrmap, key); if( offset<0 ){ sqlite3PagerUnref(pDbPage); - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpect offset in ptrmap page(%d), target:%u, page usableSize=%u", - iPtrmap, key, pBt->usableSize); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, - -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_REPORT(&context); + return SQLITE_CORRUPT_BKPT; } assert( offset <= (int)pBt->usableSize-5 ); assert( pEType!=0 ); @@ -70180,15 +69219,7 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); sqlite3PagerUnref(pDbPage); - if( *pEType<1 || *pEType>5 ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; // 5 bytes for each entry on ptrmap page - (void)sqlite3base16Encode(pPtrmap, 5, xBuffer, sizeof(xBuffer)); - sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpect entry type:%d, base16:%s", (int)*pEType, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, - offset, 5, zMsg, NULL); - return SQLITE_CORRUPT_REPORT_PGNO(&context); - } + if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_PGNO(iPtrmap); return SQLITE_OK; } @@ -70580,14 +69611,7 @@ static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){ Pgno ovfl; if( SQLITE_WITHIN(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){ testcase( pSrc!=pPage ); - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; // Output cell header as much as possible, 4 bytes for overflow pgno - (void)sqlite3base16Encode(pCell, info.nSize - info.nLocal - 4, xBuffer, sizeof(xBuffer)); - sqlite3_snprintf(sizeof(zMsg), zMsg, "cell overflow, offset=%d, rest=%d, length=%u, base16:%s", - (int)(pCell - pPage->aData), (int)(pSrc->aDataEnd - pCell), info.nSize, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - pCell - pPage->aData, info.nSize, zMsg, NULL); - *pRC = SQLITE_CORRUPT_REPORT(&context); + *pRC = SQLITE_CORRUPT_BKPT; return; } ovfl = get4byte(&pCell[info.nSize-4]); @@ -70645,29 +69669,10 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ ** reconstruct the entire page. */ if( (int)data[hdr+7]<=nMaxFrag ){ int iFree = get2byte(&data[hdr+1]); - if( iFree>usableSize-4 ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Output first 8 bytes as it's page header - sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset=%d overflow, usableSize=%d, base16:%s", - iFree, usableSize, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - 0, 8, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); - } + if( iFree>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); if( iFree ){ int iFree2 = get2byte(&data[iFree]); - if( iFree2>usableSize-4 ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode(data, 4, xBuffer, sizeof(xBuffer)); // Output first freeblock's header 4 bytes - sqlite3_snprintf(sizeof(zMsg), zMsg, - "1st freeblock's next pointer overflow, point:%d, usableSize=%d, base16:%s", - iFree2, usableSize, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - iFree, 4, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); - } + if( iFree2>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){ u8 *pEnd = &data[cellOffset + nCell*2]; u8 *pAddr; @@ -70675,51 +69680,16 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ int sz = get2byte(&data[iFree+2]); int top = get2byte(&data[hdr+5]); if( top>=iFree ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Print first 8 bytes which is page header - sqlite3_snprintf(sizeof(zMsg), zMsg, - "1st freeblock's offset:%d should > CellContentArea's offset:%d, base16:%s", - iFree, top, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - iFree, 8, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } if( iFree2 ){ - if( iFree+sz>iFree2 ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Print first 8 bytes which is page header - sqlite3_snprintf(sizeof(zMsg), zMsg, - "the 1st 2 freeblocks mis-order, 1st block offset:%d, size:%d, 2nd block offset:%d, base16:%s", - iFree, sz, iFree2, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - iFree, 4, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); - } + if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PAGE(pPage); sz2 = get2byte(&data[iFree2+2]); - if( iFree2+sz2 > usableSize ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode(data + iFree2, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to 2nd block - sqlite3_snprintf(sizeof(zMsg), zMsg, - "the 2nd freeblock overflow, offset:%d, size:%d, usableSize:%d, base16:%s", - iFree2, sz2, usableSize, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - iFree2, 4, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); - } + if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage); memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); sz += sz2; }else if( iFree+sz>usableSize ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode(data + iFree, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to 1st block - sqlite3_snprintf(sizeof(zMsg), zMsg, - "the 1st freeblock overflow, offset:%d, size:%d, usableSize:%d, base16:%s", iFree, sz, usableSize, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - iFree, 4, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } cbrk = top+sz; @@ -70752,24 +69722,13 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ ** if PRAGMA cell_size_check=ON. */ if( pciCellLast ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; // Print 4 bytes belong to 1st block - (void)sqlite3base16Encode(data + cellOffset + i*2, 2, xBuffer, sizeof(xBuffer)); - sqlite3_snprintf(sizeof(zMsg), zMsg, "%d-th cell pointer:%d out of range[%d, %d], base16:%s", - i, pc, iCellStart, iCellLast, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - cellOffset + i*2, 2, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } assert( pc>=iCellStart && pc<=iCellLast ); size = pPage->xCellSize(pPage, &src[pc]); cbrk -= size; if( cbrkusableSize ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "move %d-th cell from %d using unexpected size:%d", i, pc, size); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } assert( cbrk+size<=usableSize && cbrk>=iCellStart ); testcase( cbrk+size==usableSize ); @@ -70783,13 +69742,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ defragment_out: assert( pPage->nFree>=0 ); if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, - "after defragment, free bytes should not change, fragment bytes:%d, free space:%d, total:%d", - (int)data[hdr+7], cbrk-iCellFirst, pPage->nFree); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } assert( cbrk>=iCellFirst ); put2byte(&data[hdr+5], cbrk); @@ -70814,7 +69767,7 @@ defragment_out: ** will be ignored if adding the extra space to the fragmentation count ** causes the fragmentation count to exceed 60. */ -static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ // search on B-tree page +static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ const int hdr = pPg->hdrOffset; /* Offset to page header */ u8 * const aData = pPg->aData; /* Page data */ int iAddr = hdr + 1; /* Address of ptr to pc */ @@ -70846,15 +69799,7 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ // search on B-tree return &aData[pc]; }else if( x+pc > maxPC ){ /* This slot extends off the end of the usable part of the page */ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode(aData + pc, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to free block - sqlite3_snprintf(sizeof(zMsg), zMsg, - "freeblock rest bytes:%d begin at %d which cost %d, still exceed usableSize:%u, base16:%s", - x, pc, nByte, pPg->pBt->usableSize, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPg->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - pc, 4, zMsg, NULL); - *pRc = SQLITE_CORRUPT_PAGE(&context, pPg); + *pRc = SQLITE_CORRUPT_PAGE(pPg); return 0; }else{ /* The slot remains on the free-list. Reduce its size to account @@ -70869,25 +69814,14 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ // search on B-tree if( pc<=iAddr ){ if( pc ){ /* The next slot in the chain comes before the current slot */ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode(pTmp, 2, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to free block - sqlite3_snprintf(sizeof(zMsg), zMsg, - "the next slot:%d in chain comes before current slot:%d, base16:%s", pc, iAddr, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPg->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - iAddr, 2, zMsg, NULL); - *pRc = SQLITE_CORRUPT_PAGE(&context, pPg); + *pRc = SQLITE_CORRUPT_PAGE(pPg); } return 0; } } if( pc>maxPC+nByte-4 ){ /* The free slot chain extends off the end of the page */ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "free slot:%d overflow, end:%d", pc, maxPC+nByte-4); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPg->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - -1, 0, zMsg, NULL); - *pRc = SQLITE_CORRUPT_PAGE(&context, pPg); + *pRc = SQLITE_CORRUPT_PAGE(pPg); } return 0; } @@ -70936,13 +69870,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ if( top==0 && pPage->pBt->usableSize==65536 ){ top = 65536; }else{ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Print 8 bytes belong to page header - sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpected cellContentArea offset:%d, base16:%s", top, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } } @@ -70960,11 +69888,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ assert( pSpace+nByte<=data+pPage->pBt->usableSize ); *pIdx = g2 = (int)(pSpace-data); if( g2<=gap ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "cellpointers(end:%d) overlap with freeblock(%d)", gap, g2); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); }else{ return SQLITE_OK; } @@ -71043,23 +69967,12 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ while( (iFreeBlk = get2byte(&data[iPtr]))pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } iPtr = iFreeBlk; } if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode(data + iPtr, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to freeblock - sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset:%d overflow, base16:%s", (int)iFreeBlk, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, iPtr, 4, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } assert( iFreeBlk>iPtr || iFreeBlk==0 || CORRUPT_DB ); @@ -71071,24 +69984,10 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ */ if( iFreeBlk && iEnd+3>=iFreeBlk ){ nFrag = iFreeBlk - iEnd; - if( iEnd>iFreeBlk ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset:%d overlaps with pre block's end:%u", - (int)iFreeBlk, iEnd); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); - } + if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage); iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]); if( iEnd > pPage->pBt->usableSize ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode(data + iFreeBlk, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to freeblock - sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset:%d, end:%u overflow, usableSize:%u, base16:%s", - (int)iFreeBlk, iEnd, pPage->pBt->usableSize, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, iFreeBlk, 4, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } iSize = iEnd - iStart; iFreeBlk = get2byte(&data[iFreeBlk]); @@ -71101,27 +70000,13 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ if( iPtr>hdr+1 ){ int iPtrEnd = iPtr + get2byte(&data[iPtr+2]); if( iPtrEnd+3>=iStart ){ - if( iPtrEnd>iStart ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "check pre freeblock end:%d overlaps with the pending free block:%d", - iPtrEnd, (int)iStart); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, iPtr, iPtrEnd - iPtr, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); - } + if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PAGE(pPage); nFrag += iStart - iPtrEnd; iSize = iEnd - iPtr; iStart = iPtr; } } - if( nFrag>data[hdr+7] ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "fragment free bytes:%d increase unexpectly, should be %d", - (int)nFrag, (int)data[hdr+7]); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); - } + if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage); data[hdr+7] -= nFrag; } pTmp = &data[hdr+5]; @@ -71130,21 +70015,8 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ /* The new freeblock is at the beginning of the cell content area, ** so just extend the cell content area rather than create another ** freelist entry */ - if( iStart= the beginning of the CellContentArea:%d", (int)x, (int)iStart); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); - } - if( iPtr!=hdr+1 ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "1st freeblock's pos incorrect, hdr:%d, iPtr:%d", (int)hdr, (int)iPtr); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); - } + if( iStartintKeyLeaf = 0; pPage->xCellSize = cellSizePtr; pPage->xParseCell = btreeParseCellPtrIndex; -#ifdef LOG_DUMP - sqlite3_log(SQLITE_CORRUPT, - "database corruption at page[%u], flagByte[%x], isInit[%u], intKey[%u], intKeyLeaf[%u], leaf[%u], " - "childPtrSize[%u], cellOffset[%u], nCell[%u], hdrOffset[%u], minLocal[%u], maxLocal[%u], last ckpt time[%lld]", - pPage->pgno, flagByte, pPage->isInit, pPage->intKey, pPage->intKeyLeaf, pPage->leaf, - pPage->childPtrSize, pPage->cellOffset, pPage->nCell, pPage->hdrOffset, pPage->minLocal, pPage->maxLocal, g_lastCkptTime); -#endif /* LOG_DUMP */ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode(pPage->aData, 8, xBuffer, sizeof(xBuffer)); - sqlite3_snprintf(sizeof(zMsg), zMsg, "unrecognized flag:%d, base16:%s", flagByte, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } pPage->max1bytePayload = pBt->max1bytePayload; return SQLITE_OK; @@ -71286,20 +70145,12 @@ static int btreeComputeFreeSpace(MemPage *pPage){ /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will ** always be at least one cell before the first freeblock. */ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "the 1st freeblock:%d before all cells:%d", pc, top); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } while( 1 ){ if( pc>iCellLast ){ /* Freeblock off the end of the page */ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock end:%d out of page range:%d", pc, iCellLast); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } next = get2byte(&data[pc]); size = get2byte(&data[pc+2]); @@ -71309,19 +70160,11 @@ static int btreeComputeFreeSpace(MemPage *pPage){ } if( next>0 ){ /* Freeblock not in ascending order */ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "all freeblocks should order by asc, pre:%d, cur:%u", pc, next); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } if( pc+size>(unsigned int)usableSize ){ /* Last freeblock extends past page end */ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "last freeblock overflow, offset:%d, size:%u", pc, size); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } } @@ -71333,13 +70176,7 @@ static int btreeComputeFreeSpace(MemPage *pPage){ ** area, according to the page header, lies within the page. */ if( nFree>usableSize || nFreepBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } pPage->nFree = (u16)(nFree - iCellFirst); return SQLITE_OK; @@ -71370,20 +70207,12 @@ static SQLITE_NOINLINE int btreeCellSizeCheck(MemPage *pPage){ testcase( pc==iCellFirst ); testcase( pc==iCellLast ); if( pciCellLast ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "cell pointer:%d indicate out of range:[%d, %d]", pc, iCellFirst, iCellLast); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } sz = pPage->xCellSize(pPage, &data[pc]); testcase( pc+sz==usableSize ); if( pc+sz>usableSize ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpected cell size:%d,offset:%d, out of range:%d", sz, pc, usableSize); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } } return SQLITE_OK; @@ -71415,7 +70244,7 @@ static int btreeInitPage(MemPage *pPage){ /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating ** the b-tree page type. */ if( decodeFlags(pPage, data[0]) ){ - return SQLITE_CORRUPT_PAGE(NULL, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); pPage->maskPage = (u16)(pBt->pageSize - 1); @@ -71429,12 +70258,7 @@ static int btreeInitPage(MemPage *pPage){ pPage->nCell = get2byte(&data[3]); if( pPage->nCell>MX_CELL(pBt) ){ /* To many cells for a single page. The page must be corrupt */ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "too many cells(%d) for the page:%u, offset:%d, out of range:%u", - (int)pPage->nCell, pPage->pgno, (int)pPage->hdrOffset + 3, MX_CELL(pBt)); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } testcase( pPage->nCell==MX_CELL(pBt) ); /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only @@ -71589,11 +70413,7 @@ static int getAndInitPage( assert( pCur==0 || pCur->iPage>0 ); if( pgno>btreePagecount(pBt) ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "page number(%u) > db file size(%u)", pgno, btreePagecount(pBt)); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - -1, 0, zMsg, NULL); - rc = SQLITE_CORRUPT_REPORT(&context); + rc = SQLITE_CORRUPT_BKPT; goto getAndInitPage_error1; } rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly); @@ -71614,12 +70434,7 @@ static int getAndInitPage( /* 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) ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "check btree page, nCell:%u, intKey:%u, cursor->curIntKey:%u", - (*ppPage)->nCell, (*ppPage)->intKey, pCur->curIntKey); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - -1, 0, zMsg, NULL); - rc = SQLITE_CORRUPT_REPORT_PGNO(&context); + rc = SQLITE_CORRUPT_PGNO(pgno); goto getAndInitPage_error2; } return SQLITE_OK; @@ -71722,7 +70537,6 @@ static void pageReinit(DbPage *pData){ } } -static void DumpLocksByPager(Pager *pPager); /* ** Invoke the busy handler for a btree. */ @@ -71730,13 +70544,7 @@ static int btreeInvokeBusyHandler(void *pArg){ BtShared *pBt = (BtShared*)pArg; assert( pBt->db ); assert( sqlite3_mutex_held(pBt->db->mutex) ); - int rc = sqlite3InvokeBusyHandler(&pBt->db->busyHandler); -#if SQLITE_OS_UNIX - if (rc == 0) { - DumpLocksByPager(pBt->pPager); - } -#endif /* SQLITE_OS_UNIX */ - return rc; + return sqlite3InvokeBusyHandler(&pBt->db->busyHandler); } /* @@ -72018,8 +70826,8 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( } } #endif - *ppBtree = p; + btree_open_out: if( rc!=SQLITE_OK ){ if( pBt && pBt->pPager ){ @@ -72164,7 +70972,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){ } } #endif - ResetLockStatus(); + /* Rollback any active transaction and free the handle structure. ** The call to sqlite3BtreeRollback() drops any table-locks held by ** this handle. @@ -72984,12 +71792,7 @@ trans_begun: rc = sqlite3PagerOpenSavepoint(pPager, p->db->nSavepoint); } } -#ifdef SQLITE_META_DWR - if (rc == SQLITE_NOTADB || rc == SQLITE_CORRUPT) { - int rc1 = MetaDwrRecoverAndBeginTran(p, wrflag, pSchemaVersion); - rc = (rc1 == SQLITE_OK) ? SQLITE_OK : rc; - } -#endif + btreeIntegrity(p); sqlite3BtreeLeave(p); return rc; @@ -73053,12 +71856,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ if( eType==PTRMAP_OVERFLOW2 ){ /* The pointer is always the first 4 bytes of the page in this case. */ if( get4byte(pPage->aData)!=iFrom ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "1st 4 bytes of ovrflow page(%u) point to next(%u), should be %u", - pPage->pgno, get4byte(pPage->aData), iFrom); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_PTR_MAP, - 0, 4, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } put4byte(pPage->aData, iTo); }else{ @@ -73077,13 +71875,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ pPage->xParseCell(pPage, pCell, &info); if( info.nLocal pPage->aData+pPage->pBt->usableSize ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, - "btree cell contain ovrflow pointer overflow, offset:%d, size:%u, usableSize:%u", - (int)(pCell - pPage->aData), info.nSize, pPage->pBt->usableSize); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_PTR_MAP, pCell - pPage->aData, info.nSize, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } if( iFrom==get4byte(pCell+info.nSize-4) ){ put4byte(pCell+info.nSize-4, iTo); @@ -73092,13 +71884,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ } }else{ if( pCell+4 > pPage->aData+pPage->pBt->usableSize ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, - "btree cell contain child pointer overflow, offset:%d, size:4, usableSize:%u", - (int)(pCell - pPage->aData), pPage->pBt->usableSize); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_PTR_MAP, pCell - pPage->aData, 4, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } if( get4byte(pCell)==iFrom ){ put4byte(pCell, iTo); @@ -73110,11 +71896,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ if( i==nCell ){ if( eType!=PTRMAP_BTREE || get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "missing pointer point to overflow page on btree page(%u)", pPage->pgno); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } put4byte(&pPage->aData[pPage->hdrOffset+8], iTo); } @@ -73247,11 +72029,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){ return rc; } if( eType==PTRMAP_ROOTPAGE ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "try vacuum root page(%u), should not happened", nFin); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, PTRMAP_PAGENO(pBt, iLastPg), - CORRUPT_TYPE_PAGE_PTR_MAP, -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_REPORT(&context); + return SQLITE_CORRUPT_BKPT; } if( eType==PTRMAP_FREEPAGE ){ @@ -73381,9 +72159,6 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){ if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); put4byte(&pBt->pPage1->aData[28], pBt->nPage); -#ifdef SQLITE_META_DWR - MetaDwrCheckVacuum(pBt); -#endif } }else{ rc = SQLITE_DONE; @@ -73468,9 +72243,6 @@ static int autoVacuumCommit(Btree *p){ put4byte(&pBt->pPage1->aData[28], nFin); pBt->bDoTruncate = 1; pBt->nPage = nFin; -#ifdef SQLITE_META_DWR - MetaDwrCheckVacuum(pBt); -#endif } if( rc!=SQLITE_OK ){ sqlite3PagerRollback(pPager); @@ -73527,9 +72299,6 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){ if( pBt->bDoTruncate ){ sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage); } -#endif -#ifdef SQLITE_META_DWR - (void)MetaDwrUpdateMetaPages(p); #endif rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zSuperJrnl, 0); sqlite3BtreeLeave(p); @@ -74329,12 +73098,7 @@ static int accessPayload( assert( eOp==0 || eOp==1 ); assert( pCur->eState==CURSOR_VALID ); if( pCur->ix>=pPage->nCell ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "cell index:%u exceed limit:%u on the page:%u", - pCur->ix, pPage->nCell, pPage->pgno); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } assert( cursorHoldsMutex(pCur) ); @@ -74349,12 +73113,7 @@ static int accessPayload( ** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ** but is recast into its current form to avoid integer overflow problems */ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "base on payload size:%u, the max offset(%d) should > %d", - pCur->info.nLocal, (int)(aPayload - pPage->aData), (int)(pBt->usableSize - pCur->info.nLocal)); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - 0, 8, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } /* Check if data must be read/written to/from the btree page itself. */ @@ -74416,16 +73175,7 @@ static int accessPayload( assert( rc==SQLITE_OK && amt>0 ); while( nextPage ){ /* If required, populate the overflow page-list cache. */ - if( nextPage > pBt->nPage ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode(aPayload + pCur->info.nLocal, 4, xBuffer, sizeof(xBuffer)); - sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow page:%u should not exceed the size of database file, base16:%s", - nextPage, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - aPayload - pPage->aData + pCur->info.nLocal, 4, zMsg, NULL); - return SQLITE_CORRUPT_REPORT(&context); - } + if( nextPage > pBt->nPage ) return SQLITE_CORRUPT_BKPT; assert( pCur->aOverflow[iIdx]==0 || pCur->aOverflow[iIdx]==nextPage || CORRUPT_DB ); @@ -74510,11 +73260,7 @@ static int accessPayload( if( rc==SQLITE_OK && amt>0 ){ /* Overflow chain ends prematurely */ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow chain ends prematurely, rest:%d", amt); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } return rc; } @@ -74790,12 +73536,7 @@ static int moveToRoot(BtCursor *pCur){ ** (or the freelist). */ assert( pRoot->intKey==1 || pRoot->intKey==0 ); if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "the page(%u) state illegal, isInit:%u, pKeyInfo%s0, intKey:%u", - pRoot->pgno, pRoot->isInit, ((pCur->pKeyInfo==0)?"==":"!="), pRoot->intKey); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pCur->pBt->nPage, pRoot->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pCur->pPage); + return SQLITE_CORRUPT_PAGE(pCur->pPage); } skip_init: @@ -75049,11 +73790,7 @@ SQLITE_PRIVATE int sqlite3BtreeTableMoveto( if( pPage->intKeyLeaf ){ while( 0x80 <= *(pCell++) ){ if( pCell>=pPage->aDataEnd ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "cell idx(%d) point to a cell should not out of page", idx); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } } } @@ -75336,12 +74073,7 @@ bypass_moveto_root: testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */ testcase( nCell==2 ); /* Minimum legal index key size */ if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "nCell:%d illegal, usableSize:%u, nPage:%u", - nCell, pCur->pBt->usableSize, pCur->pBt->nPage); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); - rc = SQLITE_CORRUPT_PAGE(&context, pPage); + rc = SQLITE_CORRUPT_PAGE(pPage); goto moveto_index_finish; } pCellKey = sqlite3Malloc( nCell+nOverrun ); @@ -75669,13 +74401,7 @@ static int allocateBtreePage( n = get4byte(&pPage1->aData[36]); testcase( n==mxPage-1 ); if( n>=mxPage ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE*3] = {0}; - (void)sqlite3base16Encode(pPage1->aData, 100, xBuffer, sizeof(xBuffer)); - sqlite3_snprintf(sizeof(zMsg), zMsg, - "total pages(%u) in freelist should not over the total size of db file(%u), base16:%s", n, mxPage, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, 1, CORRUPT_TYPE_FILE_HEADER, 36, 4, zMsg, NULL); - return SQLITE_CORRUPT_REPORT(&context); + return SQLITE_CORRUPT_BKPT; } if( n>0 ){ /* There are pages on the freelist. Reuse one of those pages. */ @@ -75731,12 +74457,7 @@ static int allocateBtreePage( } testcase( iTrunk==mxPage ); if( iTrunk>mxPage || nSearch++ > n ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "freelist trunk page(%u) should <= the size of db(%u)", - iTrunk, mxPage); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, (pPrevTrunk ? pPrevTrunk->pgno : 1), - CORRUPT_TYPE_PAGE_FREE_LIST, -1, 0, zMsg, NULL); - rc = SQLITE_CORRUPT_REPORT_PGNO(&context); + rc = SQLITE_CORRUPT_PGNO(pPrevTrunk ? pPrevTrunk->pgno : 1); }else{ rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0); } @@ -75765,14 +74486,7 @@ static int allocateBtreePage( TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1)); }else if( k>(u32)(pBt->usableSize/4 - 2) ){ /* Value of k is out of range. Database corruption */ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode(pTrunk->aData, 8, xBuffer, sizeof(xBuffer)); - sqlite3_snprintf(sizeof(zMsg), zMsg, "total leaf pages(%u) on trunk page over limit(%u), base16:%s", - k, (u32)(pBt->usableSize/4 - 2), xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, - 0, 8, zMsg, NULL); - rc = SQLITE_CORRUPT_REPORT_PGNO(&context); + rc = SQLITE_CORRUPT_PGNO(iTrunk); goto end_allocate_page; #ifndef SQLITE_OMIT_AUTOVACUUM }else if( searchList @@ -75806,14 +74520,7 @@ static int allocateBtreePage( MemPage *pNewTrunk; Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); if( iNewTrunk>mxPage ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode(pTrunk->aData, 12, xBuffer, sizeof(xBuffer)); - sqlite3_snprintf(sizeof(zMsg), zMsg, - "leaf page's pgno(%u) on trunk page exceed db file size(%u), base16:%s", iNewTrunk, mxPage, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, - 8, 4, zMsg, NULL); - rc = SQLITE_CORRUPT_REPORT_PGNO(&context); + rc = SQLITE_CORRUPT_PGNO(iTrunk); goto end_allocate_page; } testcase( iNewTrunk==mxPage ); @@ -75878,14 +74585,7 @@ static int allocateBtreePage( iPage = get4byte(&aData[8+closest*4]); testcase( iPage==mxPage ); if( iPage>mxPage || iPage<2 ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode(aData+8+closest*4, 4, xBuffer, sizeof(xBuffer)); - sqlite3_snprintf(sizeof(zMsg), zMsg, "leaf page's pgno(%u) out of range:[3, %d], base16:%s", - iPage, mxPage, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, - 8+closest*4, 4, zMsg, NULL); - rc = SQLITE_CORRUPT_REPORT_PGNO(&context); + rc = SQLITE_CORRUPT_PGNO(iTrunk); goto end_allocate_page; } testcase( iPage==mxPage ); @@ -76070,14 +74770,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ nLeaf = get4byte(&pTrunk->aData[4]); assert( pBt->usableSize>32 ); if( nLeaf > (u32)pBt->usableSize/4 - 2 ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode(pTrunk->aData, 4, xBuffer, sizeof(xBuffer)); - sqlite3_snprintf(sizeof(zMsg), zMsg, "the number of leaf page(%u) on trunk page(%d) exceed limit, base16:%s", - nLeaf, iTrunk, xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, - 0, 4, zMsg, NULL); - rc = SQLITE_CORRUPT_REPORT(&context); + rc = SQLITE_CORRUPT_BKPT; goto freepage_out; } if( nLeaf < (u32)pBt->usableSize/4 - 8 ){ @@ -76166,12 +74859,7 @@ static SQLITE_NOINLINE int clearCellOverflow( testcase( pCell + (pInfo->nSize-1) == pPage->aDataEnd ); if( pCell + pInfo->nSize > pPage->aDataEnd ){ /* Cell extends past end of page */ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow end of page, pgno:%u, offset:%d, size:%u, usableSize:%u", - pPage->pgno, (int)(pCell - pPage->aData), pInfo->nSize, pPage->pBt->usableSize); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(btreePagecount(pPage->pBt), pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_PAGE(&context, pPage); + return SQLITE_CORRUPT_PAGE(pPage); } ovflPgno = get4byte(pCell + pInfo->nSize - 4); pBt = pPage->pBt; @@ -76188,14 +74876,7 @@ static SQLITE_NOINLINE int clearCellOverflow( /* 0 is not a legal page number and page 1 cannot be an ** overflow page. Therefore if ovflPgno<2 or past the end of the ** file the database must be corrupt. */ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; - (void)sqlite3base16Encode(pCell + pInfo->nSize - 4, 4, xBuffer, sizeof(xBuffer)); - sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow page's pgno(%u) illegal, out of range:[2, %u], base16:%s", - ovflPgno, btreePagecount(pBt), xBuffer); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(btreePagecount(pBt), pPage->pgno, - CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_REPORT(&context); + return SQLITE_CORRUPT_BKPT; } if( nOvfl ){ rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext); @@ -76468,12 +75149,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ testcase( pc==(u32)get2byte(&data[hdr+5]) ); testcase( pc+sz==pPage->pBt->usableSize ); if( pc+sz > pPage->pBt->usableSize ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, "cell offset:%u size:%d, idx:%d overflow, usableSize:%u", - pc, sz, idx, pPage->pBt->usableSize); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - -1, 0, zMsg, NULL); - *pRC = SQLITE_CORRUPT_REPORT(&context); + *pRC = SQLITE_CORRUPT_BKPT; return; } rc = freeSpace(pPage, pc, sz); @@ -78383,14 +77059,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 ){ - char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; - sqlite3_snprintf(sizeof(zMsg), zMsg, - "cell payload cursor point to(%d), size:%u overlaps with non-cell content area:[%u, %d]", - (int)(pCur->info.pPayload - pPage->aData), pCur->info.nLocal, pPage->cellOffset, - (int)(pPage->aDataEnd - pPage->aData)); - sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, - -1, 0, zMsg, NULL); - return SQLITE_CORRUPT_REPORT(&context); + return SQLITE_CORRUPT_BKPT; } /* Overwrite the local portion first */ rc = btreeOverwriteContent(pPage, pCur->info.pPayload, pX, @@ -79531,11 +78200,6 @@ SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ assert( iMeta==0 || iMeta==1 ); pBt->incrVacuum = (u8)iMeta; } -#endif -#ifdef SQLITE_META_DWR - if (idx == 1 && pBt->pPager->metaFd) { - pBt->pPager->metaChanged = META_SCHEMA_CHANGED; - } #endif } sqlite3BtreeLeave(p); @@ -79906,6 +78570,7 @@ static int checkTreePage( "unable to get the page. error code=%d", rc); goto end_of_check; } + /* Clear MemPage.isInit to make sure the corruption detection code in ** btreeInitPage() is executed. */ savedIsInit = pPage->isInit; @@ -80335,10 +79000,8 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int * if( p ){ BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); - ResetLockStatus(); if( pBt->inTransaction!=TRANS_NONE ){ rc = SQLITE_LOCKED; - MARK_LAST_BUSY_LINE(rc); }else{ rc = sqlite3PagerCheckpoint(pBt->pPager, p->db, eMode, pnLog, pnCkpt); } @@ -80818,13 +79481,6 @@ static int backupOnePage( int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); const int nCopy = MIN(nSrcPgsz, nDestPgsz); const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; -#ifdef SQLITE_HAS_CODEC - /* Use BtreeGetReserveNoMutex() for the source b-tree, as although it is - ** guaranteed that the shared-mutex is held by this thread, handle - ** p->pSrc may not actually be the owner. */ - int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc); - int nDestReserve = sqlite3BtreeGetRequestedReserve(p->pDest); -#endif /* SQLITE_HAS_CODEC */ int rc = SQLITE_OK; i64 iOff; @@ -80841,26 +79497,6 @@ static int backupOnePage( rc = SQLITE_READONLY; } -#ifdef SQLITE_HAS_CODEC - /* Backup is not possible if the page size of the destination is changing - ** and a codec is in use. - */ - if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){ - rc = SQLITE_READONLY; - } - - /* Backup is not possible if the number of bytes of reserve space differ - ** between source and destination. If there is a difference, try to - ** fix the destination to agree with the source. If that is not possible, - ** then the backup cannot proceed. - */ - if( nSrcReserve!=nDestReserve ){ - u32 newPgsz = nSrcPgsz; - rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve); - if( rc==SQLITE_OK && newPgsz!=(u32)nSrcPgsz ) rc = SQLITE_READONLY; - } -#endif /* SQLITE_HAS_CODEC */ - /* This loop runs once for each destination page spanned by the source ** page. For each iteration, variable iOff is set to the byte offset ** of the destination page. @@ -81112,7 +79748,6 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ } } } - if( rc==SQLITE_OK ){ rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1); } @@ -81145,12 +79780,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ sqlite3PagerTruncateImage(pDestPager, nDestTruncate); rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0); } - #ifdef SQLITE_META_DWR - if (rc == SQLITE_OK && p->pDest->pBt->pPager->metaFd) { - p->pDest->pBt->pPager->metaChanged = META_SCHEMA_CHANGED; - (void)MetaDwrUpdateMetaPages(p->pDest); - } - #endif + /* Finish committing the transaction to the destination database. */ if( SQLITE_OK==rc && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0)) @@ -81362,10 +79992,6 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ b.pDest = pTo; b.iNext = 1; -#ifdef SQLITE_HAS_CODEC - sqlite3PagerAlignReserve(sqlite3BtreePager(pTo), sqlite3BtreePager(pFrom)); -#endif /* SQLITE_HAS_CODEC */ - /* 0x7FFFFFFF is the hard limit for the number of pages in a database ** file. By passing this as the number of pages to copy to ** sqlite3_backup_step(), we can guarantee that the copy finishes @@ -83586,7 +82212,7 @@ static int growOpArray(Vdbe *v, int nOp){ ** ** Other useful labels for breakpoints include: ** test_trace_breakpoint(pc,pOp) -** sqlite3CorruptError(lineno,context) +** sqlite3CorruptError(lineno) ** sqlite3MisuseError(lineno) ** sqlite3CantopenError(lineno) */ @@ -86193,7 +84819,6 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ nTrans++; } rc = sqlite3PagerExclusiveLock(pPager); - MARK_LAST_BUSY_LINE(rc); sqlite3BtreeLeave(pBt); } } @@ -89489,15 +88114,6 @@ end_of_step: return (rc&db->errMask); } -#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK -SQLITE_API int sqlite3_set_droptable_handle(sqlite3 *db, void (*xFunc)(sqlite3*, const char*, const char*)){ - sqlite3_mutex_enter(db->mutex); - db->xDropTableHandle = xFunc; - sqlite3_mutex_leave(db->mutex); - return 0; -} -#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ - /* ** This is the top-level implementation of sqlite3_step(). Call ** sqlite3Step() to do most of the work. If a schema error occurs, @@ -89517,13 +88133,6 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ while( (rc = sqlite3Step(v))==SQLITE_SCHEMA && cnt++ < SQLITE_MAX_SCHEMA_RETRY ){ int savedPc = v->pc; -#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION - Sqlite3SharedBlockMethods *pSharedBlock = v->pSharedBlock; - int totalRows = v->totalRows; - int blockFull = v->blockFull; - int startPos = v->startPos; - int addedRows = v->addedRows; -#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ rc = sqlite3Reprepare(v); if( rc!=SQLITE_OK ){ /* This case occurs after failing to recompile an sql statement. @@ -89545,15 +88154,6 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ } break; } - -#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION - v->pSharedBlock = pSharedBlock; - v->totalRows = totalRows; - v->blockFull = blockFull; - v->startPos = startPos; - v->addedRows = addedRows; -#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ - sqlite3_reset(pStmt); if( savedPc>=0 ){ /* Setting minWriteFileFormat to 254 is a signal to the OP_Init and @@ -89564,20 +88164,6 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ } assert( v->expired==0 ); } -#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK - if( rc==SQLITE_DONE && db->xDropTableHandle!=NULL && db->isDropTable==1 ){ - db->isDropTable = 0; - db->xDropTableHandle(db, db->mDropTableName, db->mDropSchemaName); - } - if( db->mDropTableName!=NULL ){ - sqlite3_free(db->mDropTableName); - db->mDropTableName = NULL; - } - if( db->mDropSchemaName!=NULL ){ - sqlite3_free(db->mDropSchemaName); - db->mDropSchemaName = NULL; - } -#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ sqlite3_mutex_leave(db->mutex); return rc; } @@ -91244,7 +89830,7 @@ SQLITE_API int sqlite3_found_count = 0; ** ** Other useful labels for breakpoints include: ** test_addop_breakpoint(pc,pOp) -** sqlite3CorruptError(lineno,context) +** sqlite3CorruptError(lineno) ** sqlite3MisuseError(lineno) ** sqlite3CantopenError(lineno) */ @@ -91606,6 +90192,7 @@ static u16 numericType(Mem *pMem){ testcase( pMem->flags & MEM_Str ); testcase( pMem->flags & MEM_Blob ); return computeNumericType(pMem); + return 0; } #ifdef SQLITE_DEBUG @@ -91764,61 +90351,6 @@ static int checkSavepointCount(sqlite3 *db){ } #endif -#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION -static int copySharedBlockRow( - Vdbe *p, /* The VDBE */ - Op *pOp, /* Current operation */ - Mem *pMem, - void *pCtx -){ - int i = 0; - - int rc = p->pSharedBlock->xAddRow(pCtx, p->addedRows); - if( rc!=SQLITE_OK ){ - return rc; - } - - for(i=0; ip2; i++){ - switch (sqlite3_value_type(&pMem[i])) { - case SQLITE_INTEGER:{ - rc = p->pSharedBlock->xPutLong(pCtx, p->addedRows, i, (sqlite3_int64)pMem[i].u.i); - break; - } - case SQLITE_FLOAT: { - rc = p->pSharedBlock->xPutDouble(pCtx, p->addedRows, i, pMem[i].u.r); - break; - } - case SQLITE_TEXT: { - Deephemeralize(&pMem[i]); - sqlite3VdbeMemNulTerminate(&pMem[i]); - sqlite3VdbeChangeEncoding(&pMem[i],SQLITE_UTF8); - rc = p->pSharedBlock->xPutString(pCtx, p->addedRows, i, pMem[i].z, pMem[i].n+1); - break; - } - case SQLITE_BLOB: { - rc = p->pSharedBlock->xPutBlob(pCtx, p->addedRows, i, pMem[i].z, pMem[i].n); - break; - } - case SQLITE_NULL: { - rc = p->pSharedBlock->xPutNull(pCtx, p->addedRows, i); - break; - } - default: - rc = p->pSharedBlock->xPutOther(pCtx, p->addedRows, i); - break; - } - if( rc!=SQLITE_OK ){ - return rc; - } - } - - return rc; -no_mem: - rc = SQLITE_NOMEM; - return rc; -} -#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ - /* ** Return the register of pOp->p2 after first preparing it to be ** overwritten with an integer value. @@ -92320,12 +90852,6 @@ case OP_Halt: { VdbeFrame *pFrame; int pcx; -#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION - if( p->pSharedBlock!=NULL ){ - p->pSharedBlock->xFinish(p->pSharedBlock->pContext, p->addedRows, p->totalRows); - } -#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ - #ifdef SQLITE_DEBUG if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); } #endif @@ -92769,43 +91295,6 @@ case OP_ResultRow: { assert( pOp->p1>0 || CORRUPT_DB ); assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); -#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION - if( p->pSharedBlock!=NULL ){ - void *pCtx = p->pSharedBlock->pContext; - p->totalRows++; - if( p->totalRows<=p->startPos || p->blockFull ){ - break; - } - Mem *pMem = &aMem[pOp->p1]; - rc = copySharedBlockRow(p, pOp, pMem, pCtx); - if( rc==SQLITE_FULL && p->addedRows && (p->startPos + p->addedRows) <= p->pSharedBlock->requiredPos ){ - p->startPos += p->addedRows; - p->addedRows = 0; - p->pSharedBlock->xReset(pCtx,p->startPos); - p->blockFull = 0; - rc = copySharedBlockRow(p, pOp, pMem, pCtx); - } - - if( rc==SQLITE_OK ){ - p->addedRows++; - }else if( rc==SQLITE_FULL ){ - p->blockFull = 1; - }else{ - //SQLITE_NOMEM - goto no_mem; - } - - if( p->blockFull && p->pSharedBlock->countAllRows==0 ){ - p->pSharedBlock->xFinish(pCtx, p->addedRows, p->totalRows); - rc = SQLITE_DONE; - goto vdbe_return; - }else if( p->blockFull && p->pSharedBlock->countAllRows==1 ){ - rc = SQLITE_OK; - } - break; - } -#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ - p->cacheCtr = (p->cacheCtr + 2)|1; p->pResultSet = &aMem[pOp->p1]; #ifdef SQLITE_DEBUG @@ -93602,17 +92091,6 @@ case OP_Compare: { ** This opcode must immediately follow an OP_Compare opcode. */ case OP_Jump: { /* jump */ -#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION - if( pOp->p5&0x80 ){ - if( p->pSharedBlock!=NULL ){ - if( p->totalRows < p->startPos || p->blockFull ){ - p->totalRows++; - pOp = &aOp[pOp->p2 - 1]; - } - } - break; - } -#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ assert( pOp>aOp && pOp[-1].opcode==OP_Compare ); if( iCompare<0 ){ VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1]; @@ -98628,20 +97106,6 @@ case OP_IfNotZero: { /* jump, in1 */ ** and jump to P2 if the new value is exactly zero. */ case OP_DecrJumpZero: { /* jump, in1 */ -#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION - if( pOp->p5&0x80 ){ - if( p->pSharedBlock!=NULL ){ - if( p->totalRows < p->startPos || p->blockFull ){ - pIn1 = &aMem[pOp->p1]; - assert( pIn1->flags&MEM_Int ); - if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--; - VdbeBranchTaken(pIn1->u.i==-1, 2); - if( pIn1->u.i==-1 ) goto jump_to_p2; - } - } - break; - } -#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--; @@ -117589,40 +116053,6 @@ static void attachFunc( if( rc==SQLITE_OK && pNew->zDbSName==0 ){ rc = SQLITE_NOMEM_BKPT; } -#ifdef SQLITE_HAS_CODEC - if( rc==SQLITE_OK ){ - extern int sqlite3CodecAttach(sqlite3*, int, const void*, int); - extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); - int nKey; - char *zKey; - int t = sqlite3_value_type(argv[2]); - switch( t ){ - case SQLITE_INTEGER: - case SQLITE_FLOAT: - zErrDyn = sqlite3DbStrDup(db, "Invalid key value"); - rc = SQLITE_ERROR; - break; - - case SQLITE_TEXT: - case SQLITE_BLOB: - nKey = sqlite3_value_bytes(argv[2]); - zKey = (char *)sqlite3_value_blob(argv[2]); - rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); - break; - - case SQLITE_NULL: - /* No key specified. Use the key from URI filename, or if none, - ** use the key from the main database. */ - if( sqlite3CodecQueryParameters(db, zName, zPath)==0 ){ - sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); - if( nKey || sqlite3BtreeGetRequestedReserve(db->aDb[0].pBt)>0 ){ - rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); - } - } - break; - } - } -#endif /* SQLITE_HAS_CODEC */ sqlite3_free_filename( zPath ); /* If the file was opened successfully, read the schema for the new database. @@ -119194,24 +117624,8 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char testcase( zTabName[0]==0 ); /* Zero-length table names are allowed */ pDb = &db->aDb[iDb]; p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0); -#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK - u8 tableType = p->eTabType; -#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ sqlite3DeleteTable(db, p); db->mDbFlags |= DBFLAG_SchemaChange; -#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK - if( tableType!=TABTYP_VIEW ){ - db->isDropTable = 1; - db->mDropTableName = sqlite3_malloc(strlen(zTabName) + 1); - if( db->mDropTableName!=NULL ){ - memcpy(db->mDropTableName, zTabName, strlen(zTabName) + 1); - } - db->mDropSchemaName = sqlite3_malloc(strlen(db->aDb[iDb].zDbSName) + 1); - if( db->mDropSchemaName!=NULL ){ - memcpy(db->mDropSchemaName, db->aDb[iDb].zDbSName, strlen(db->aDb[iDb].zDbSName) + 1); - } - } -#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ } /* @@ -127484,16 +125898,10 @@ static void groupConcatValue(sqlite3_context *context){ */ SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){ int rc = sqlite3_overload_function(db, "MATCH", 2); -#ifdef SQLITE_HAS_CODEC - extern void sqlite3CodecExportData(sqlite3_context *, int, sqlite3_value **); -#endif /* SQLITE_HAS_CODEC */ assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); } -#ifdef SQLITE_HAS_CODEC - sqlite3CreateFunc(db, "export_database", 1, SQLITE_TEXT, 0, sqlite3CodecExportData, 0, 0, 0, 0, 0); -#endif /* SQLITE_HAS_CODEC */ } /* @@ -133127,10 +131535,6 @@ struct sqlite3_api_routines { const char *(*db_name)(sqlite3*,int); /* Version 3.40.0 and later */ int (*value_encoding)(sqlite3_value*); -#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK - /* handle after drop table done */ - int (*set_droptable_handle)(sqlite3*,void(*)(sqlite3*,const char*,const char*)); -#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ }; /* @@ -133457,10 +131861,6 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_db_name sqlite3_api->db_name /* Version 3.40.0 and later */ #define sqlite3_value_encoding sqlite3_api->value_encoding -#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK -/* handle after drop table done */ -#define sqlite3_set_droptable_handle sqlite3_api->set_droptable_handle -#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) @@ -133484,7 +131884,7 @@ typedef int (*sqlite3_loadext_entry)( /************** Continuing where we left off in loadext.c ********************/ /* #include "sqliteInt.h" */ -#if !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS) +#ifndef SQLITE_OMIT_LOAD_EXTENSION /* ** Some API routines are omitted when various features are ** excluded from a build of SQLite. Substitute a NULL pointer @@ -133498,9 +131898,7 @@ typedef int (*sqlite3_loadext_entry)( # define sqlite3_column_origin_name 0 # define sqlite3_column_origin_name16 0 #endif -#endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS) */ -#ifndef SQLITE_OMIT_LOAD_EXTENSION #ifdef SQLITE_OMIT_AUTHORIZATION # define sqlite3_set_authorizer 0 #endif @@ -133581,7 +131979,6 @@ typedef int (*sqlite3_loadext_entry)( #if defined(SQLITE_OMIT_TRACE) # define sqlite3_trace_v2 0 #endif -#endif /* !SQLITE_OMIT_LOAD_EXTENSION */ /* ** The following structure contains pointers to all SQLite API routines. @@ -133598,7 +131995,6 @@ typedef int (*sqlite3_loadext_entry)( ** also check to make sure that the pointer to the function is ** not NULL before calling it. */ -#if !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS) static const sqlite3_api_routines sqlite3Apis = { sqlite3_aggregate_context, #ifndef SQLITE_OMIT_DEPRECATED @@ -133868,11 +132264,7 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_bind_blob64, sqlite3_bind_text64, sqlite3_cancel_auto_extension, -#ifndef SQLITE_OMIT_LOAD_EXTENSION sqlite3_load_extension, -#else - 0, -#endif /* !SQLITE_OMIT_LOAD_EXTENSION */ sqlite3_malloc64, sqlite3_msize, sqlite3_realloc64, @@ -133983,10 +132375,7 @@ static const sqlite3_api_routines sqlite3Apis = { #endif sqlite3_db_name, /* Version 3.40.0 and later */ - sqlite3_value_encoding, -#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK - sqlite3_set_droptable_handle -#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ + sqlite3_value_encoding }; /* True if x is the directory separator character @@ -133997,9 +132386,6 @@ static const sqlite3_api_routines sqlite3Apis = { # define DirSep(X) ((X)=='/') #endif -#endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) || defined(SQLITE_EXPORT_SYMBOLS) */ - -#ifndef SQLITE_OMIT_LOAD_EXTENSION /* ** Attempt to load an SQLite extension library contained in the file ** zFile. The entry point is zProc. zProc may be 0 in which case a @@ -134460,9 +132846,6 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ #define PragTyp_WAL_CHECKPOINT 43 #define PragTyp_LOCK_STATUS 44 #define PragTyp_STATS 45 -#ifdef SQLITE_HAS_CODEC -#define PragTyp_KEY 255 -#endif /* SQLITE_HAS_CODEC */ /* Property flags associated with various pragma. */ #define PragFlg_NeedSchema 0x01 /* Force schema load before running */ @@ -134753,18 +133136,6 @@ static const PragmaName aPragmaName[] = { /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, -#if defined(SQLITE_HAS_CODEC) - {/* zName: */ "hexkey", - /* ePragTyp: */ PragTyp_KEY, - /* ePragFlg: */ 0, - /* ColNames: */ 0, 0, - /* iArg: */ 2 }, - {/* zName: */ "hexrekey", - /* ePragTyp: */ PragTyp_KEY, - /* ePragFlg: */ 0, - /* ColNames: */ 0, 0, - /* iArg: */ 3 }, -#endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_CHECK) {/* zName: */ "ignore_check_constraints", @@ -134817,13 +133188,6 @@ static const PragmaName aPragmaName[] = { /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif -#if defined(SQLITE_HAS_CODEC) - {/* zName: */ "key", - /* ePragTyp: */ PragTyp_KEY, - /* ePragFlg: */ 0, - /* ColNames: */ 0, 0, - /* iArg: */ 0 }, -#endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "legacy_alter_table", /* ePragTyp: */ PragTyp_FLAG, @@ -134931,15 +133295,6 @@ static const PragmaName aPragmaName[] = { /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_RecTriggers }, -#endif -#if defined(SQLITE_HAS_CODEC) - {/* zName: */ "rekey", - /* ePragTyp: */ PragTyp_KEY, - /* ePragFlg: */ 0, - /* ColNames: */ 0, 0, - /* iArg: */ 1 }, -#endif -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "reverse_unordered_selects", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, @@ -135028,18 +133383,6 @@ static const PragmaName aPragmaName[] = { /* ePragFlg: */ PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, -#endif -#if defined(SQLITE_HAS_CODEC) - {/* zName: */ "textkey", - /* ePragTyp: */ PragTyp_KEY, - /* ePragFlg: */ 0, - /* ColNames: */ 0, 0, - /* iArg: */ 4 }, - {/* zName: */ "textrekey", - /* ePragTyp: */ PragTyp_KEY, - /* ePragFlg: */ 0, - /* ColNames: */ 0, 0, - /* iArg: */ 5 }, #endif {/* zName: */ "threads", /* ePragTyp: */ PragTyp_THREADS, @@ -135481,10 +133824,6 @@ SQLITE_PRIVATE void sqlite3Pragma( Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */ const PragmaName *pPragma; /* The pragma */ -#ifdef SQLITE_HAS_CODEC - extern int sqlite3CodecPragma(sqlite3*, int, Parse *, const char *, const char *); -#endif /* SQLITE_HAS_CODEC */ - if( v==0 ) return; sqlite3VdbeRunOnlyOnce(v); pParse->nMem = 2; @@ -135554,19 +133893,6 @@ SQLITE_PRIVATE void sqlite3Pragma( goto pragma_out; } -#ifdef SQLITE_HAS_CODEC - if(sqlite3CodecPragma(db, iDb, pParse, zLeft, zRight)) { - /* sqlite3CodecPragma executes internal */ - goto pragma_out; - } -#endif -/* END CODEC */ -#ifdef SQLITE_META_DWR - if(PragmaMetaDoubleWrie(db, iDb, pParse, zLeft, zRight)) { - /* PragmaMetaDoubleWrie executes internal */ - goto pragma_out; - } -#endif /* Locate the pragma in the lookup table */ pPragma = pragmaLocate(zLeft); if( pPragma==0 ){ @@ -137609,48 +135935,6 @@ SQLITE_PRIVATE void sqlite3Pragma( } #endif -#ifdef SQLITE_HAS_CODEC - /* Pragma iArg - ** ---------- ------ - ** key 0 - ** rekey 1 - ** hexkey 2 - ** hexrekey 3 - ** textkey 4 - ** textrekey 5 - */ - case PragTyp_KEY: { - if( zRight ){ - char zBuf[40]; - const char *zKey = zRight; - int n; - if( pPragma->iArg==2 || pPragma->iArg==3 ){ - u8 iByte; - int i; - for(i=0, iByte=0; i<(int)(sizeof(zBuf)*2) && sqlite3Isxdigit(zRight[i]); i++){ - iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]); - if( (i&1)!=0 ) zBuf[i/2] = iByte; - } - zKey = zBuf; - n = i/2; - }else{ - n = pPragma->iArg<4 ? sqlite3Strlen30(zRight) : -1; - } - if( (pPragma->iArg & 1)==0 ){ - rc = sqlite3_key_v2(db, zDb, zKey, n); - }else{ - rc = sqlite3_rekey_v2(db, zDb, zKey, n); - } - if( rc==SQLITE_OK && n!=0 ){ - sqlite3VdbeSetNumCols(v, 1); - sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "ok", SQLITE_STATIC); - returnSingleText(v, "ok"); - } - } - break; - } -#endif /* SQLITE_HAS_CODEC */ - #if defined(SQLITE_ENABLE_CEROD) case PragTyp_ACTIVATE_EXTENSIONS: if( zRight ){ if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){ @@ -140176,25 +138460,9 @@ static void selectInnerLoop( assert( p->pEList!=0 ); hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP; if( pSort && pSort->pOrderBy==0 ) pSort = 0; -#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION - if( hasDistinct && (pDistinct->eTnctType==WHERE_DISTINCT_UNIQUE) ){ - hasDistinct = WHERE_DISTINCT_NOOP; - sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct); - } -#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ if( pSort==0 && !hasDistinct ){ assert( iContinue!=0 ); codeOffset(v, p->iOffset, iContinue); -#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION - if( eDest==SRT_Output ){ - if( p->iLimit ){ - sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); - sqlite3VdbeChangeP5(v, 128); - } - sqlite3VdbeAddOp2(v, OP_Jump, 0, iContinue); - sqlite3VdbeChangeP5(v, 128); - } -#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ } /* Pull the requested columns. @@ -140323,16 +138591,6 @@ static void selectInnerLoop( fixDistinctOpenEph(pParse, eType, iTab, pDistinct->addrTnct); if( pSort==0 ){ codeOffset(v, p->iOffset, iContinue); -#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION - if( eDest==SRT_Output ){ - if( p->iLimit ){ - sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); - sqlite3VdbeChangeP5(v, 128); - } - sqlite3VdbeAddOp2(v, OP_Jump, 0, iContinue); - sqlite3VdbeChangeP5(v, 128); - } -#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ } } @@ -140779,23 +139037,11 @@ static void generateSortTail( addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); VdbeCoverage(v); assert( p->iLimit==0 && p->iOffset==0 ); -#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION - if( eDest==SRT_Output ){ - sqlite3VdbeAddOp2(v, OP_Jump, 0, addrContinue); - sqlite3VdbeChangeP5(v, 128); - } -#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ sqlite3VdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab); bSeq = 0; }else{ addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); -#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION - if( eDest==SRT_Output ){ - sqlite3VdbeAddOp2(v, OP_Jump, 0, addrContinue); - sqlite3VdbeChangeP5(v, 128); - } -#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ iSortTab = iTab; bSeq = 1; if( p->iOffset>0 ){ @@ -150001,6 +148247,7 @@ static void updateVirtualTable( } } + if( eOnePass==ONEPASS_OFF ){ /* End the virtual table scan */ if( pSrc->nSrc==1 ){ @@ -150597,17 +148844,6 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( } nRes = sqlite3BtreeGetRequestedReserve(pMain); -#ifdef SQLITE_HAS_CODEC - /* A VACUUM cannot change the pagesize of an encrypted database. */ - if( db->nextPagesize ){ - extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); - int nKey; - char *zKey; - sqlite3CodecGetKey(db, iDb, (void**)&zKey, &nKey); - if( nKey ) db->nextPagesize = 0; - } -#endif /* SQLITE_HAS_CODEC */ - sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); sqlite3BtreeSetPagerFlags(pTemp, pgflags|PAGER_CACHESPILL); @@ -174246,7 +172482,6 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db); /************** End of rtree.h ***********************************************/ /************** Continuing where we left off in main.c ***********************/ #endif -#include "sqlite3tokenizer.h" #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) /************** Include sqliteicu.h in the middle of main.c ******************/ /************** Begin file sqliteicu.h ***************************************/ @@ -174271,54 +172506,13 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db); extern "C" { #endif /* __cplusplus */ -SQLITE_PRIVATE int sqlite3IcuInitInner(sqlite3 *db); +SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db); #if 0 } /* extern "C" */ #endif /* __cplusplus */ /************** End of sqliteicu.h *******************************************/ -#ifndef _WIN32 -#include -#endif - -typedef void (*sqlite3Fts3IcuTokenizerModule_ptr)(sqlite3_tokenizer_module const** ppModule); -typedef int (*sqlite3IcuInit_ptr)(sqlite3 *db); -static sqlite3Fts3IcuTokenizerModule_ptr tokenModulePtr = NULL; -static sqlite3IcuInit_ptr icuInitPtr = NULL; -static u32 icuEnable = 0u; -static u32 icuInit = 0u; -static void *g_library = NULL; - -int sqlite3IcuModuleInit(){ - int rc = SQLITE_OK; - if( icuInit ){ - return rc; - } -#ifndef _WIN32 - g_library = dlopen("libsqliteicu.z.so", RTLD_LAZY); - if( g_library==NULL ){ - sqlite3_log(SQLITE_ERROR, "load icu so failed"); - return SQLITE_ERROR; - } - tokenModulePtr = (sqlite3Fts3IcuTokenizerModule_ptr)dlsym(g_library, "sqlite3Fts3IcuTokenizerModule"); - icuInitPtr = (sqlite3IcuInit_ptr)dlsym(g_library, "sqlite3IcuInit"); - if( tokenModulePtr==NULL || icuInitPtr==NULL ){ - sqlite3_log(SQLITE_ERROR, "load icu init function failed"); - return SQLITE_ERROR; - } - icuInit = 1u; -#endif - return rc; -} - -SQLITE_PRIVATE int sqlite3IcuInitInner(sqlite3 *db) -{ - if( !icuEnable ){ - return SQLITE_OK; - } - return icuInitPtr(db); -} /************** Continuing where we left off in main.c ***********************/ #endif @@ -174368,7 +172562,7 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = { sqlite3Fts5Init, #endif #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) - sqlite3IcuInitInner, + sqlite3IcuInit, #endif #ifdef SQLITE_ENABLE_RTREE sqlite3RtreeInit, @@ -174725,24 +172919,12 @@ SQLITE_API int sqlite3_shutdown(void){ SQLITE_API int sqlite3_config(int op, ...){ va_list ap; int rc = SQLITE_OK; - va_start(ap, op); - -#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) - if( op==SQLITE_CONFIG_ENABLE_ICU ){ - int iVal = va_arg(ap, int); - if( iVal==0 ){ - icuEnable = 0u; - }else{ - icuEnable = 1u; - } - return rc; - } -#endif /* SQLITE_ENABLE_ICU */ /* sqlite3_config() shall return SQLITE_MISUSE if it is invoked while ** the SQLite library is in use. */ if( sqlite3GlobalConfig.isInit ) return SQLITE_MISUSE_BKPT; + va_start(ap, op); switch( op ){ /* Mutex configuration options are only available in a threadsafe @@ -175031,12 +173213,6 @@ SQLITE_API int sqlite3_config(int op, ...){ break; } #endif /* SQLITE_OMIT_DESERIALIZE */ - case SQLITE_CONFIG_CORRUPTION: { - typedef void(*CORRUPTION_FUNC_t)(void*, const void*); - sqlite3GlobalConfig.xCorruption = va_arg(ap, CORRUPTION_FUNC_t); - sqlite3GlobalConfig.pCorruptionArg = va_arg(ap, void*); - break; - } default: { rc = SQLITE_ERROR; @@ -175246,29 +173422,6 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ rc = setupLookaside(db, pBuf, sz, cnt); break; } -#ifdef SQLITE_SHARED_BLOCK_OPTIMIZATION - case SQLITE_DBCONFIG_SET_SHAREDBLOCK: { - Vdbe *pVdbe = (Vdbe *)va_arg(ap, sqlite3_stmt*); - Sqlite3SharedBlockMethods *pSharedBlock = va_arg(ap, Sqlite3SharedBlockMethods*); - if( pVdbe==NULL ){ - rc = SQLITE_MISUSE; - break; - } - pVdbe->pSharedBlock = pSharedBlock; - if( pSharedBlock!=NULL ){ - pVdbe->startPos = pSharedBlock->startPos; - } - pVdbe->totalRows = 0; - pVdbe->blockFull = 0; - pVdbe->addedRows = 0; - rc = SQLITE_OK; - break; - } - case SQLITE_DBCONFIG_USE_SHAREDBLOCK: { - rc = SQLITE_OK; - break; - } -#endif /* SQLITE_SHARED_BLOCK_OPTIMIZATION */ default: { static const struct { int op; /* The opcode */ @@ -175971,10 +174124,6 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){ zErr = "no more rows available"; break; } - case SQLITE_META_RECOVERED: { - zErr = "warning meta recover message"; - break; - } default: { rc &= 0xff; if( ALWAYS(rc>=0) && rceOpenState = SQLITE_STATE_SICK; } -#ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK - db->isDropTable = 0; - db->mDropTableName = NULL; - db->mDropSchemaName = NULL; - db->xDropTableHandle = NULL; -#endif /* SQLITE_ENABLE_DROPTABLE_CALLBACK */ *ppDb = db; #ifdef SQLITE_ENABLE_SQLLOG if( sqlite3GlobalConfig.xSqllog ){ @@ -177892,14 +175995,6 @@ opendb_out: sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0); } #endif -#ifdef SQLITE_HAS_CODEC - if( rc==SQLITE_OK ) { -#ifdef SQLITE_CODEC_ATTACH_CHANGED - sqlite3CodecResetParameters(&db->codecParm); -#endif /* SQLITE_CODEC_ATTACH_CHANGED */ - sqlite3CodecQueryParameters(db, 0, zOpen); - } -#endif /* SQLITE_HAS_CODEC */ sqlite3_free_filename(zOpen); return rc; } @@ -178115,21 +176210,9 @@ SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType){ zType, lineno, 20+sqlite3_sourceid()); return iErr; } -SQLITE_PRIVATE int sqlite3CorruptError(int lineno, sqlite3CorruptContext *context){ +SQLITE_PRIVATE int sqlite3CorruptError(int lineno){ testcase( sqlite3GlobalConfig.xLog!=0 ); - if (context!=NULL && sqlite3GlobalConfig.xCorruption != 0) { - char zMsg[SQLITE_PRINT_BUF_SIZE] = {0}; /* Complete corruption log message */ - sqlite3_snprintf(sizeof(zMsg), zMsg, "pgno:%u,type:%d,range:{%d,%d},line:%d", - context->pgno, (int)context->type, (int)context->zoneRange.offset, (int)context->zoneRange.size, lineno); - sqlite3GlobalConfig.xCorruption(sqlite3GlobalConfig.pCorruptionArg, zMsg); - } - char zCorruptMsg[SQLITE_PRINT_BUF_SIZE * 10] = {0}; - if (context!=NULL && context->zMsg != NULL){ - sqlite3_snprintf(sizeof(zCorruptMsg), zCorruptMsg, "database corruption, %s", context->zMsg); - } else { - sqlite3_snprintf(sizeof(zCorruptMsg), zCorruptMsg, "database corruption"); - } - return sqlite3ReportError(SQLITE_CORRUPT, lineno, zCorruptMsg); + return sqlite3ReportError(SQLITE_CORRUPT, lineno, "database corruption"); } SQLITE_PRIVATE int sqlite3MisuseError(int lineno){ testcase( sqlite3GlobalConfig.xLog!=0 ); @@ -178351,16 +176434,12 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager); rc = SQLITE_OK; }else if( op==SQLITE_FCNTL_RESERVE_BYTES ){ -#ifndef SQLITE_CKSUMVFS_STATIC - rc = SQLITE_OK; -#else int iNew = *(int*)pArg; *(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree); if( iNew>=0 && iNew<=255 ){ sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0); } rc = SQLITE_OK; -#endif }else if( op==SQLITE_FCNTL_RESET_CACHE ){ sqlite3BtreeClearCache(pBtree); rc = SQLITE_OK; @@ -180022,6 +178101,114 @@ SQLITE_EXTENSION_INIT3 ** the tokenization rules supplied by a specific sqlite3_tokenizer ** object. */ +typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module; +typedef struct sqlite3_tokenizer sqlite3_tokenizer; +typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor; + +struct sqlite3_tokenizer_module { + + /* + ** Structure version. Should always be set to 0 or 1. + */ + int iVersion; + + /* + ** Create a new tokenizer. The values in the argv[] array are the + ** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL + ** TABLE statement that created the fts3 table. For example, if + ** the following SQL is executed: + ** + ** CREATE .. USING fts3( ... , tokenizer arg1 arg2) + ** + ** then argc is set to 2, and the argv[] array contains pointers + ** to the strings "arg1" and "arg2". + ** + ** This method should return either SQLITE_OK (0), or an SQLite error + ** code. If SQLITE_OK is returned, then *ppTokenizer should be set + ** to point at the newly created tokenizer structure. The generic + ** sqlite3_tokenizer.pModule variable should not be initialized by + ** this callback. The caller will do so. + */ + int (*xCreate)( + int argc, /* Size of argv array */ + const char *const*argv, /* Tokenizer argument strings */ + sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ + ); + + /* + ** Destroy an existing tokenizer. The fts3 module calls this method + ** exactly once for each successful call to xCreate(). + */ + int (*xDestroy)(sqlite3_tokenizer *pTokenizer); + + /* + ** Create a tokenizer cursor to tokenize an input buffer. The caller + ** is responsible for ensuring that the input buffer remains valid + ** until the cursor is closed (using the xClose() method). + */ + int (*xOpen)( + sqlite3_tokenizer *pTokenizer, /* Tokenizer object */ + const char *pInput, int nBytes, /* Input buffer */ + sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */ + ); + + /* + ** Destroy an existing tokenizer cursor. The fts3 module calls this + ** method exactly once for each successful call to xOpen(). + */ + int (*xClose)(sqlite3_tokenizer_cursor *pCursor); + + /* + ** Retrieve the next token from the tokenizer cursor pCursor. This + ** method should either return SQLITE_OK and set the values of the + ** "OUT" variables identified below, or SQLITE_DONE to indicate that + ** the end of the buffer has been reached, or an SQLite error code. + ** + ** *ppToken should be set to point at a buffer containing the + ** normalized version of the token (i.e. after any case-folding and/or + ** stemming has been performed). *pnBytes should be set to the length + ** of this buffer in bytes. The input text that generated the token is + ** identified by the byte offsets returned in *piStartOffset and + ** *piEndOffset. *piStartOffset should be set to the index of the first + ** byte of the token in the input buffer. *piEndOffset should be set + ** to the index of the first byte just past the end of the token in + ** the input buffer. + ** + ** The buffer *ppToken is set to point at is managed by the tokenizer + ** implementation. It is only required to be valid until the next call + ** to xNext() or xClose(). + */ + /* TODO(shess) current implementation requires pInput to be + ** nul-terminated. This should either be fixed, or pInput/nBytes + ** should be converted to zInput. + */ + int (*xNext)( + sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */ + const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */ + int *piStartOffset, /* OUT: Byte offset of token in input buffer */ + int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */ + int *piPosition /* OUT: Number of tokens returned before this one */ + ); + + /*********************************************************************** + ** Methods below this point are only available if iVersion>=1. + */ + + /* + ** Configure the language id of a tokenizer cursor. + */ + int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid); +}; + +struct sqlite3_tokenizer { + const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */ + /* Tokenizer implementations will typically add additional fields */ +}; + +struct sqlite3_tokenizer_cursor { + sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */ + /* Tokenizer implementations will typically add additional fields */ +}; int fts3_global_term_cnt(int iTerm, int iCol); int fts3_term_cnt(int iTerm, int iCol); @@ -184506,6 +182693,9 @@ SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(sqlite3_tokenizer_module co #ifndef SQLITE_DISABLE_FTS3_UNICODE SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const**ppModule); #endif +#ifdef SQLITE_ENABLE_ICU +SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); +#endif /* ** Initialize the fts3 extension. If this extension is built as part @@ -184524,14 +182714,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){ #ifdef SQLITE_ENABLE_ICU const sqlite3_tokenizer_module *pIcu = 0; - if( icuEnable ){ - if( tokenModulePtr!=NULL ){ - tokenModulePtr(&pIcu); - }else{ - sqlite3_log(SQLITE_ERROR, "icu module ptr is null"); - return SQLITE_ERROR; - } - } + sqlite3Fts3IcuTokenizerModule(&pIcu); #endif #ifndef SQLITE_DISABLE_FTS3_UNICODE @@ -184567,7 +182750,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){ || sqlite3Fts3HashInsert(&pHash->hash, "unicode61", 10, (void *)pUnicode) #endif #ifdef SQLITE_ENABLE_ICU - || (icuEnable && pIcu && sqlite3Fts3HashInsert(&pHash->hash, "icu", 4, (void *)pIcu)) + || (pIcu && sqlite3Fts3HashInsert(&pHash->hash, "icu", 4, (void *)pIcu)) #endif ){ rc = SQLITE_NOMEM; @@ -208179,6 +206362,829 @@ SQLITE_API int sqlite3_rtree_init( #endif /************** End of rtree.c ***********************************************/ +/************** Begin file icu.c *********************************************/ +/* +** 2007 May 6 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $ +** +** This file implements an integration between the ICU library +** ("International Components for Unicode", an open-source library +** for handling unicode data) and SQLite. The integration uses +** ICU to provide the following to SQLite: +** +** * An implementation of the SQL regexp() function (and hence REGEXP +** operator) using the ICU uregex_XX() APIs. +** +** * Implementations of the SQL scalar upper() and lower() functions +** for case mapping. +** +** * Integration of ICU and SQLite collation sequences. +** +** * An implementation of the LIKE operator that uses ICU to +** provide case-independent matching. +*/ + +#if !defined(SQLITE_CORE) \ + || defined(SQLITE_ENABLE_ICU) \ + || defined(SQLITE_ENABLE_ICU_COLLATIONS) + +/* Include ICU headers */ +#include +#include +#include +#include + +/* #include */ + +#ifndef SQLITE_CORE +/* #include "sqlite3ext.h" */ + SQLITE_EXTENSION_INIT1 +#else +/* #include "sqlite3.h" */ +#endif + +/* +** This function is called when an ICU function called from within +** the implementation of an SQL scalar function returns an error. +** +** The scalar function context passed as the first argument is +** loaded with an error message based on the following two args. +*/ +static void icuFunctionError( + sqlite3_context *pCtx, /* SQLite scalar function context */ + const char *zName, /* Name of ICU function that failed */ + UErrorCode e /* Error code returned by ICU function */ +){ + char zBuf[128]; + sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e)); + zBuf[127] = '\0'; + sqlite3_result_error(pCtx, zBuf, -1); +} + +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) + +/* +** Maximum length (in bytes) of the pattern in a LIKE or GLOB +** operator. +*/ +#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH +# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000 +#endif + +/* +** Version of sqlite3_free() that is always a function, never a macro. +*/ +static void xFree(void *p){ + sqlite3_free(p); +} + +/* +** This lookup table is used to help decode the first byte of +** a multi-byte UTF8 character. It is copied here from SQLite source +** code file utf8.c. +*/ +static const unsigned char icuUtf8Trans1[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, +}; + +#define SQLITE_ICU_READ_UTF8(zIn, c) \ + c = *(zIn++); \ + if( c>=0xc0 ){ \ + c = icuUtf8Trans1[c-0xc0]; \ + while( (*zIn & 0xc0)==0x80 ){ \ + c = (c<<6) + (0x3f & *(zIn++)); \ + } \ + } + +#define SQLITE_ICU_SKIP_UTF8(zIn) \ + assert( *zIn ); \ + if( *(zIn++)>=0xc0 ){ \ + while( (*zIn & 0xc0)==0x80 ){zIn++;} \ + } + + +/* +** Compare two UTF-8 strings for equality where the first string is +** a "LIKE" expression. Return true (1) if they are the same and +** false (0) if they are different. +*/ +static int icuLikeCompare( + const uint8_t *zPattern, /* LIKE pattern */ + const uint8_t *zString, /* The UTF-8 string to compare against */ + const UChar32 uEsc /* The escape character */ +){ + static const uint32_t MATCH_ONE = (uint32_t)'_'; + static const uint32_t MATCH_ALL = (uint32_t)'%'; + + int prevEscape = 0; /* True if the previous character was uEsc */ + + while( 1 ){ + + /* Read (and consume) the next character from the input pattern. */ + uint32_t uPattern; + SQLITE_ICU_READ_UTF8(zPattern, uPattern); + if( uPattern==0 ) break; + + /* There are now 4 possibilities: + ** + ** 1. uPattern is an unescaped match-all character "%", + ** 2. uPattern is an unescaped match-one character "_", + ** 3. uPattern is an unescaped escape character, or + ** 4. uPattern is to be handled as an ordinary character + */ + if( uPattern==MATCH_ALL && !prevEscape && uPattern!=(uint32_t)uEsc ){ + /* Case 1. */ + uint8_t c; + + /* Skip any MATCH_ALL or MATCH_ONE characters that follow a + ** MATCH_ALL. For each MATCH_ONE, skip one character in the + ** test string. + */ + while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){ + if( c==MATCH_ONE ){ + if( *zString==0 ) return 0; + SQLITE_ICU_SKIP_UTF8(zString); + } + zPattern++; + } + + if( *zPattern==0 ) return 1; + + while( *zString ){ + if( icuLikeCompare(zPattern, zString, uEsc) ){ + return 1; + } + SQLITE_ICU_SKIP_UTF8(zString); + } + return 0; + + }else if( uPattern==MATCH_ONE && !prevEscape && uPattern!=(uint32_t)uEsc ){ + /* Case 2. */ + if( *zString==0 ) return 0; + SQLITE_ICU_SKIP_UTF8(zString); + + }else if( uPattern==(uint32_t)uEsc && !prevEscape ){ + /* Case 3. */ + prevEscape = 1; + + }else{ + /* Case 4. */ + uint32_t uString; + SQLITE_ICU_READ_UTF8(zString, uString); + uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT); + uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT); + if( uString!=uPattern ){ + return 0; + } + prevEscape = 0; + } + } + + return *zString==0; +} + +/* +** Implementation of the like() SQL function. This function implements +** the build-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 +** +** is implemented as like(B, A). If there is an escape character E, +** +** A LIKE B ESCAPE E +** +** is mapped to like(B, A, E). +*/ +static void icuLikeFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const unsigned char *zA = sqlite3_value_text(argv[0]); + const unsigned char *zB = sqlite3_value_text(argv[1]); + UChar32 uEsc = 0; + + /* Limit the length of the LIKE or GLOB pattern to avoid problems + ** of deep recursion and N*N behavior in patternCompare(). + */ + if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){ + sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); + return; + } + + + if( argc==3 ){ + /* The escape character string must consist of a single UTF-8 character. + ** Otherwise, return an error. + */ + int nE= sqlite3_value_bytes(argv[2]); + const unsigned char *zE = sqlite3_value_text(argv[2]); + int i = 0; + if( zE==0 ) return; + U8_NEXT(zE, i, nE, uEsc); + if( i!=nE){ + sqlite3_result_error(context, + "ESCAPE expression must be a single character", -1); + return; + } + } + + if( zA && zB ){ + sqlite3_result_int(context, icuLikeCompare(zA, zB, uEsc)); + } +} + +/* +** Function to delete compiled regexp objects. Registered as +** a destructor function with sqlite3_set_auxdata(). +*/ +static void icuRegexpDelete(void *p){ + URegularExpression *pExpr = (URegularExpression *)p; + uregex_close(pExpr); +} + +/* +** Implementation of SQLite REGEXP operator. This scalar function takes +** two arguments. The first is a regular expression pattern to compile +** the second is a string to match against that pattern. If either +** argument is an SQL NULL, then NULL Is returned. Otherwise, the result +** is 1 if the string matches the pattern, or 0 otherwise. +** +** SQLite maps the regexp() function to the regexp() operator such +** that the following two are equivalent: +** +** zString REGEXP zPattern +** regexp(zPattern, zString) +** +** Uses the following ICU regexp APIs: +** +** uregex_open() +** uregex_matches() +** uregex_close() +*/ +static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ + UErrorCode status = U_ZERO_ERROR; + URegularExpression *pExpr; + UBool res; + const UChar *zString = sqlite3_value_text16(apArg[1]); + + (void)nArg; /* Unused parameter */ + + /* If the left hand side of the regexp operator is NULL, + ** then the result is also NULL. + */ + if( !zString ){ + return; + } + + pExpr = sqlite3_get_auxdata(p, 0); + if( !pExpr ){ + const UChar *zPattern = sqlite3_value_text16(apArg[0]); + if( !zPattern ){ + return; + } + pExpr = uregex_open(zPattern, -1, 0, 0, &status); + + if( U_SUCCESS(status) ){ + sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete); + pExpr = sqlite3_get_auxdata(p, 0); + } + if( !pExpr ){ + icuFunctionError(p, "uregex_open", status); + return; + } + } + + /* Configure the text that the regular expression operates on. */ + uregex_setText(pExpr, zString, -1, &status); + if( !U_SUCCESS(status) ){ + icuFunctionError(p, "uregex_setText", status); + return; + } + + /* Attempt the match */ + res = uregex_matches(pExpr, 0, &status); + if( !U_SUCCESS(status) ){ + icuFunctionError(p, "uregex_matches", status); + return; + } + + /* Set the text that the regular expression operates on to a NULL + ** pointer. This is not really necessary, but it is tidier than + ** leaving the regular expression object configured with an invalid + ** pointer after this function returns. + */ + uregex_setText(pExpr, 0, 0, &status); + + /* Return 1 or 0. */ + sqlite3_result_int(p, res ? 1 : 0); +} + +/* +** Implementations of scalar functions for case mapping - upper() and +** lower(). Function upper() converts its input to upper-case (ABC). +** Function lower() converts to lower-case (abc). +** +** ICU provides two types of case mapping, "general" case mapping and +** "language specific". Refer to ICU documentation for the differences +** between the two. +** +** To utilise "general" case mapping, the upper() or lower() scalar +** functions are invoked with one argument: +** +** upper('ABC') -> 'abc' +** lower('abc') -> 'ABC' +** +** To access ICU "language specific" case mapping, upper() or lower() +** should be invoked with two arguments. The second argument is the name +** of the locale to use. Passing an empty string ("") or SQL NULL value +** as the second argument is the same as invoking the 1 argument version +** of upper() or lower(). +** +** lower('I', 'en_us') -> 'i' +** lower('I', 'tr_tr') -> '\u131' (small dotless i) +** +** http://www.icu-project.org/userguide/posix.html#case_mappings +*/ +static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ + const UChar *zInput; /* Pointer to input string */ + UChar *zOutput = 0; /* Pointer to output buffer */ + int nInput; /* Size of utf-16 input string in bytes */ + int nOut; /* Size of output buffer in bytes */ + int cnt; + int bToUpper; /* True for toupper(), false for tolower() */ + UErrorCode status; + const char *zLocale = 0; + + assert(nArg==1 || nArg==2); + bToUpper = (sqlite3_user_data(p)!=0); + if( nArg==2 ){ + zLocale = (const char *)sqlite3_value_text(apArg[1]); + } + + zInput = sqlite3_value_text16(apArg[0]); + if( !zInput ){ + return; + } + nOut = nInput = sqlite3_value_bytes16(apArg[0]); + if( nOut==0 ){ + sqlite3_result_text16(p, "", 0, SQLITE_STATIC); + return; + } + + for(cnt=0; cnt<2; cnt++){ + UChar *zNew = sqlite3_realloc(zOutput, nOut); + if( zNew==0 ){ + sqlite3_free(zOutput); + sqlite3_result_error_nomem(p); + return; + } + zOutput = zNew; + status = U_ZERO_ERROR; + if( bToUpper ){ + nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); + }else{ + nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); + } + + if( U_SUCCESS(status) ){ + sqlite3_result_text16(p, zOutput, nOut, xFree); + }else if( status==U_BUFFER_OVERFLOW_ERROR ){ + assert( cnt==0 ); + continue; + }else{ + icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status); + } + return; + } + assert( 0 ); /* Unreachable */ +} + +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ + +/* +** Collation sequence destructor function. The pCtx argument points to +** a UCollator structure previously allocated using ucol_open(). +*/ +static void icuCollationDel(void *pCtx){ + UCollator *p = (UCollator *)pCtx; + ucol_close(p); +} + +/* +** Collation sequence comparison function. The pCtx argument points to +** a UCollator structure previously allocated using ucol_open(). +*/ +static int icuCollationColl( + void *pCtx, + int nLeft, + const void *zLeft, + int nRight, + const void *zRight +){ + UCollationResult res; + UCollator *p = (UCollator *)pCtx; + res = ucol_strcoll(p, (UChar *)zLeft, nLeft/2, (UChar *)zRight, nRight/2); + switch( res ){ + case UCOL_LESS: return -1; + case UCOL_GREATER: return +1; + case UCOL_EQUAL: return 0; + } + assert(!"Unexpected return value from ucol_strcoll()"); + return 0; +} + +/* +** Implementation of the scalar function icu_load_collation(). +** +** This scalar function is used to add ICU collation based collation +** types to an SQLite database connection. It is intended to be called +** as follows: +** +** SELECT icu_load_collation(, ); +** +** Where is a string containing an ICU locale identifier (i.e. +** "en_AU", "tr_TR" etc.) and is the name of the +** collation sequence to create. +*/ +static void icuLoadCollation( + sqlite3_context *p, + int nArg, + sqlite3_value **apArg +){ + sqlite3 *db = (sqlite3 *)sqlite3_user_data(p); + UErrorCode status = U_ZERO_ERROR; + const char *zLocale; /* Locale identifier - (eg. "jp_JP") */ + const char *zName; /* SQL Collation sequence name (eg. "japanese") */ + UCollator *pUCollator; /* ICU library collation object */ + int rc; /* Return code from sqlite3_create_collation_x() */ + + assert(nArg==2); + (void)nArg; /* Unused parameter */ + zLocale = (const char *)sqlite3_value_text(apArg[0]); + zName = (const char *)sqlite3_value_text(apArg[1]); + + if( !zLocale || !zName ){ + return; + } + + pUCollator = ucol_open(zLocale, &status); + if( !U_SUCCESS(status) ){ + icuFunctionError(p, "ucol_open", status); + return; + } + assert(p); + + rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator, + icuCollationColl, icuCollationDel + ); + if( rc!=SQLITE_OK ){ + ucol_close(pUCollator); + sqlite3_result_error(p, "Error registering collation function", -1); + } +} + +/* +** Register the ICU extension functions with database db. +*/ +SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){ +# define SQLITEICU_EXTRAFLAGS (SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS) + static const struct IcuScalar { + const char *zName; /* Function name */ + unsigned char nArg; /* Number of arguments */ + unsigned int enc; /* Optimal text encoding */ + unsigned char iContext; /* sqlite3_user_data() context */ + void (*xFunc)(sqlite3_context*,int,sqlite3_value**); + } scalars[] = { + {"icu_load_collation",2,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}, + {"lower", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, + {"upper", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, + {"upper", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, + {"lower", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, + {"lower", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, + {"upper", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, + {"upper", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, + {"like", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc}, + {"like", 3, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc}, +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ + }; + int rc = SQLITE_OK; + int i; + + for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){ + const struct IcuScalar *p = &scalars[i]; + rc = sqlite3_create_function( + db, p->zName, p->nArg, p->enc, + p->iContext ? (void*)db : (void*)0, + p->xFunc, 0, 0 + ); + } + + return rc; +} + +#if !SQLITE_CORE +#ifdef _WIN32 +__declspec(dllexport) +#endif +SQLITE_API int sqlite3_icu_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + SQLITE_EXTENSION_INIT2(pApi) + return sqlite3IcuInit(db); +} +#endif + +#endif + +/************** End of icu.c *************************************************/ +/************** Begin file fts3_icu.c ****************************************/ +/* +** 2007 June 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file implements a tokenizer for fts3 based on the ICU library. +*/ +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) +#ifdef SQLITE_ENABLE_ICU + +/* #include */ +/* #include */ +/* #include "fts3_tokenizer.h" */ + +#include +/* #include */ +/* #include */ +#include + +typedef struct IcuTokenizer IcuTokenizer; +typedef struct IcuCursor IcuCursor; + +struct IcuTokenizer { + sqlite3_tokenizer base; + char *zLocale; +}; + +struct IcuCursor { + sqlite3_tokenizer_cursor base; + + UBreakIterator *pIter; /* ICU break-iterator object */ + int nChar; /* Number of UChar elements in pInput */ + UChar *aChar; /* Copy of input using utf-16 encoding */ + int *aOffset; /* Offsets of each character in utf-8 input */ + + int nBuffer; + char *zBuffer; + + int iToken; +}; + +/* +** Create a new tokenizer instance. +*/ +static int icuCreate( + int argc, /* Number of entries in argv[] */ + const char * const *argv, /* Tokenizer creation arguments */ + sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ +){ + IcuTokenizer *p; + int n = 0; + + if( argc>0 ){ + n = strlen(argv[0])+1; + } + p = (IcuTokenizer *)sqlite3_malloc64(sizeof(IcuTokenizer)+n); + if( !p ){ + return SQLITE_NOMEM; + } + memset(p, 0, sizeof(IcuTokenizer)); + + if( n ){ + p->zLocale = (char *)&p[1]; + memcpy(p->zLocale, argv[0], n); + } + + *ppTokenizer = (sqlite3_tokenizer *)p; + + return SQLITE_OK; +} + +/* +** Destroy a tokenizer +*/ +static int icuDestroy(sqlite3_tokenizer *pTokenizer){ + IcuTokenizer *p = (IcuTokenizer *)pTokenizer; + sqlite3_free(p); + return SQLITE_OK; +} + +/* +** Prepare to begin tokenizing a particular string. The input +** string to be tokenized is pInput[0..nBytes-1]. A cursor +** used to incrementally tokenize this string is returned in +** *ppCursor. +*/ +static int icuOpen( + sqlite3_tokenizer *pTokenizer, /* The tokenizer */ + const char *zInput, /* Input string */ + int nInput, /* Length of zInput in bytes */ + sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ +){ + IcuTokenizer *p = (IcuTokenizer *)pTokenizer; + IcuCursor *pCsr; + + const int32_t opt = U_FOLD_CASE_DEFAULT; + UErrorCode status = U_ZERO_ERROR; + int nChar; + + UChar32 c; + int iInput = 0; + int iOut = 0; + + *ppCursor = 0; + + if( zInput==0 ){ + nInput = 0; + zInput = ""; + }else if( nInput<0 ){ + nInput = strlen(zInput); + } + nChar = nInput+1; + pCsr = (IcuCursor *)sqlite3_malloc64( + sizeof(IcuCursor) + /* IcuCursor */ + ((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */ + (nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */ + ); + if( !pCsr ){ + return SQLITE_NOMEM; + } + memset(pCsr, 0, sizeof(IcuCursor)); + pCsr->aChar = (UChar *)&pCsr[1]; + pCsr->aOffset = (int *)&pCsr->aChar[(nChar+3)&~3]; + + pCsr->aOffset[iOut] = iInput; + U8_NEXT(zInput, iInput, nInput, c); + while( c>0 ){ + int isError = 0; + c = u_foldCase(c, opt); + U16_APPEND(pCsr->aChar, iOut, nChar, c, isError); + if( isError ){ + sqlite3_free(pCsr); + return SQLITE_ERROR; + } + pCsr->aOffset[iOut] = iInput; + + if( iInputpIter = ubrk_open(UBRK_WORD, p->zLocale, pCsr->aChar, iOut, &status); + if( !U_SUCCESS(status) ){ + sqlite3_free(pCsr); + return SQLITE_ERROR; + } + pCsr->nChar = iOut; + + ubrk_first(pCsr->pIter); + *ppCursor = (sqlite3_tokenizer_cursor *)pCsr; + return SQLITE_OK; +} + +/* +** Close a tokenization cursor previously opened by a call to icuOpen(). +*/ +static int icuClose(sqlite3_tokenizer_cursor *pCursor){ + IcuCursor *pCsr = (IcuCursor *)pCursor; + ubrk_close(pCsr->pIter); + sqlite3_free(pCsr->zBuffer); + sqlite3_free(pCsr); + return SQLITE_OK; +} + +/* +** Extract the next token from a tokenization cursor. +*/ +static int icuNext( + sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by simpleOpen */ + const char **ppToken, /* OUT: *ppToken is the token text */ + int *pnBytes, /* OUT: Number of bytes in token */ + int *piStartOffset, /* OUT: Starting offset of token */ + int *piEndOffset, /* OUT: Ending offset of token */ + int *piPosition /* OUT: Position integer of token */ +){ + IcuCursor *pCsr = (IcuCursor *)pCursor; + + int iStart = 0; + int iEnd = 0; + int nByte = 0; + + while( iStart==iEnd ){ + UChar32 c; + + iStart = ubrk_current(pCsr->pIter); + iEnd = ubrk_next(pCsr->pIter); + if( iEnd==UBRK_DONE ){ + return SQLITE_DONE; + } + + while( iStartaChar, iWhite, pCsr->nChar, c); + if( u_isspace(c) ){ + iStart = iWhite; + }else{ + break; + } + } + assert(iStart<=iEnd); + } + + do { + UErrorCode status = U_ZERO_ERROR; + if( nByte ){ + char *zNew = sqlite3_realloc(pCsr->zBuffer, nByte); + if( !zNew ){ + return SQLITE_NOMEM; + } + pCsr->zBuffer = zNew; + pCsr->nBuffer = nByte; + } + + u_strToUTF8( + pCsr->zBuffer, pCsr->nBuffer, &nByte, /* Output vars */ + &pCsr->aChar[iStart], iEnd-iStart, /* Input vars */ + &status /* Output success/failure */ + ); + } while( nByte>pCsr->nBuffer ); + + *ppToken = pCsr->zBuffer; + *pnBytes = nByte; + *piStartOffset = pCsr->aOffset[iStart]; + *piEndOffset = pCsr->aOffset[iEnd]; + *piPosition = pCsr->iToken++; + + return SQLITE_OK; +} + +/* +** The set of routines that implement the simple tokenizer +*/ +static const sqlite3_tokenizer_module icuTokenizerModule = { + 0, /* iVersion */ + icuCreate, /* xCreate */ + icuDestroy, /* xCreate */ + icuOpen, /* xOpen */ + icuClose, /* xClose */ + icuNext, /* xNext */ + 0, /* xLanguageid */ +}; + +/* +** Set *ppModule to point at the implementation of the ICU tokenizer. +*/ +SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( + sqlite3_tokenizer_module const**ppModule +){ + *ppModule = &icuTokenizerModule; +} + +#endif /* defined(SQLITE_ENABLE_ICU) */ +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + +/************** End of fts3_icu.c ********************************************/ /************** Begin file sqlite3rbu.c **************************************/ /* ** 2014 August 30 @@ -218575,19 +217581,15 @@ static int sessionReadRecord( } } if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ - if( (pIn->nData-pIn->iNext)<8 ){ - rc = SQLITE_CORRUPT_BKPT; + sqlite3_int64 v = sessionGetI64(aVal); + if( eType==SQLITE_INTEGER ){ + sqlite3VdbeMemSetInt64(apOut[i], v); }else{ - sqlite3_int64 v = sessionGetI64(aVal); - if( eType==SQLITE_INTEGER ){ - sqlite3VdbeMemSetInt64(apOut[i], v); - }else{ - double d; - memcpy(&d, &v, 8); - sqlite3VdbeMemSetDouble(apOut[i], d); - } - pIn->iNext += 8; + double d; + memcpy(&d, &v, 8); + sqlite3VdbeMemSetDouble(apOut[i], d); } + pIn->iNext += 8; } } } @@ -244612,2985 +243614,3 @@ SQLITE_API int sqlite3_stmt_init( /* Return the source-id for this library */ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } /************************** End of sqlite3.c ******************************/ - -#ifdef SQLITE_HAS_CODEC -/************** Begin file hw_codec_openssl.h *******************************/ -#ifndef EXPOSE_INTERNAL_FUNC -#define CODEC_STATIC static -#else -#define CODEC_STATIC -#endif - -#define DEFAULT_CIPHER "aes-256-gcm" - -typedef struct{ - unsigned char *buffer; - int bufferSize; -}Buffer; -/************** End file hw_codec_openssl.h *********************************/ -/************** Begin file hw_codec.h ***************************************/ -#define DEFAULT_PAGE_SIZE 1024 -#define DEFAULT_ITER 10000 -#define FILE_HEADER_SIZE 16 -#define SALT_SIZE FILE_HEADER_SIZE -#define HMAC_SALT_MASK 0x3a -#define HMAC_ITER 2 -#define MAX_HMAC_SIZE 64 -#define MAX_INIT_VECTOR_SIZE 16 -#define MIN_BLOCK_SIZE 16 - -#define CODEC_OPERATION_ENCRYPT 1 -#define CODEC_OPERATION_DECRYPT 0 - -#define KEY_CONTEXT_HEAD_SIZE (sizeof(CodecConstant) + 3 * sizeof(int)) - -typedef struct{ - void *cipher; - int keySize; - int keyInfoSize; - int cipherPageSize; - int initVectorSize; - int hmacSize; - int reserveSize; - int hmacAlgo; - int kdfAlgo; - int rekeyHmacAlgo; -}CodecConstant; - -typedef struct{ - CodecConstant codecConst; - int deriveFlag; - int iter; - int passwordSize; - unsigned char *password; - unsigned char *key; - unsigned char *hmacKey; - unsigned char *keyInfo; -}KeyContext; - -typedef struct{ - Btree *pBt; - int savePassword; - unsigned char salt[SALT_SIZE]; - unsigned char hmacSalt[SALT_SIZE]; - unsigned char *buffer; - KeyContext *readCtx; - KeyContext *writeCtx; -}CodecContext; - -/************** End file hw_codec.h *****************************************/ -/************** Begin file hw_codec_openssl.c *******************************/ -#include -#include -#include -#include - -unsigned int openssl_init_count = 0; -unsigned int openssl_external_init_flag = 0; -sqlite3_mutex *openssl_random_mutex = NULL; - -CODEC_STATIC void opensslActive(){ - sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - - if(openssl_init_count == 0){ - if(EVP_get_cipherbyname(DEFAULT_CIPHER) == NULL){ - OpenSSL_add_all_algorithms(); - }else{ - openssl_external_init_flag = 1; - } - } - - if(openssl_random_mutex == NULL){ - openssl_random_mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); - } - openssl_init_count++; - - sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - return; -} - -CODEC_STATIC void opensslDeactive(){ - sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - - openssl_init_count--; - if(openssl_init_count == 0){ - if(openssl_external_init_flag){ - openssl_external_init_flag = 0; - }else{ - EVP_cleanup(); - } - } - - sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - return; -} - -CODEC_STATIC int opensslGetRandom(Buffer *buffer){ - sqlite3_mutex_enter(openssl_random_mutex); - int rc = RAND_bytes(buffer->buffer, buffer->bufferSize); - sqlite3_mutex_leave(openssl_random_mutex); - if(rc != 1){ - return SQLITE_ERROR; - } - return SQLITE_OK; -} - -CODEC_STATIC void *opensslGetCipher(const char *cipherName){ - return (void *)EVP_get_cipherbyname(cipherName); -} - -CODEC_STATIC int opensslFreeCipher(void *cipher){ - return SQLITE_OK; -} - -CODEC_STATIC const char *opensslGetCipherName(void *cipher){ - return EVP_CIPHER_name((EVP_CIPHER *)cipher); -} - -CODEC_STATIC int opensslGetKeySize(void *cipher){ - return EVP_CIPHER_key_length((EVP_CIPHER *)cipher); -} - -CODEC_STATIC int opensslGetInitVectorSize(void *cipher){ - return EVP_CIPHER_iv_length((EVP_CIPHER *)cipher); -} - -#define CIPHER_HMAC_ALGORITHM_SHA1 1 -#define CIPHER_HMAC_ALGORITHM_SHA256 2 -#define CIPHER_HMAC_ALGORITHM_SHA512 3 - -#define DEFAULT_HMAC_ALGORITHM CIPHER_HMAC_ALGORITHM_SHA1 - -#define CIPHER_HMAC_ALGORITHM_NAME_SHA1 "SHA1" -#define CIPHER_HMAC_ALGORITHM_NAME_SHA256 "SHA256" -#define CIPHER_HMAC_ALGORITHM_NAME_SHA512 "SHA512" - -#define CIPHER_KDF_ALGORITHM_SHA1 1 -#define CIPHER_KDF_ALGORITHM_SHA256 2 -#define CIPHER_KDF_ALGORITHM_SHA512 3 - -#define DEFAULT_KDF_ALGORITHM CIPHER_KDF_ALGORITHM_SHA1 - -#define CIPHER_KDF_ALGORITHM_NAME_SHA1 "KDF_SHA1" -#define CIPHER_KDF_ALGORITHM_NAME_SHA256 "KDF_SHA256" -#define CIPHER_KDF_ALGORITHM_NAME_SHA512 "KDF_SHA512" - - -CODEC_STATIC int opensslGetHmacSize(KeyContext *keyCtx){ - if( keyCtx==NULL ){ - return 0; - } - if( keyCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){ - return EVP_MD_size(EVP_sha1()); - }else if( keyCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){ - return EVP_MD_size(EVP_sha256()); - }else if( keyCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){ - return EVP_MD_size(EVP_sha512()); - } - return 0; -} - -CODEC_STATIC int opensslGetBlockSize(void *cipher){ - return EVP_CIPHER_block_size((EVP_CIPHER *)cipher); -} - -CODEC_STATIC void *opensslGetCtx(void *cipher, int mode, unsigned char *key, unsigned char *initVector){ - EVP_CIPHER_CTX *tmpCtx = EVP_CIPHER_CTX_new(); - if(tmpCtx == NULL){ - return (void *)tmpCtx; - } - EVP_CipherInit_ex(tmpCtx, (EVP_CIPHER *)cipher, NULL, NULL, NULL, mode); - EVP_CIPHER_CTX_set_padding(tmpCtx, 0); - EVP_CipherInit_ex(tmpCtx, NULL, NULL, key, initVector, mode); - return (void *)tmpCtx; -} - -CODEC_STATIC int opensslCipher(void *iCtx, Buffer *input, unsigned char *output){ - int outputLength = 0; - int cipherLength; - EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)iCtx; - EVP_CipherUpdate(ctx, output, &cipherLength, input->buffer, input->bufferSize); - outputLength += cipherLength; - output += cipherLength; - EVP_CipherFinal_ex(ctx, output, &cipherLength); - outputLength += cipherLength; - if(outputLength != input->bufferSize){ - return SQLITE_ERROR; - } - return SQLITE_OK; -} - -CODEC_STATIC void opensslFreeCtx(void *ctx){ - EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)ctx); -} - -CODEC_STATIC int opensslHmac(Buffer *key, Buffer *input1, Buffer *input2, Buffer *output, int hmacAlgo){ - HMAC_CTX *ctx = HMAC_CTX_new(); - if(ctx == NULL){ - return SQLITE_ERROR; - } - if( hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){ - HMAC_Init_ex(ctx, key->buffer, key->bufferSize, EVP_sha1(), NULL); - }else if( hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){ - HMAC_Init_ex(ctx, key->buffer, key->bufferSize, EVP_sha256(), NULL); - }else if( hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){ - HMAC_Init_ex(ctx, key->buffer, key->bufferSize, EVP_sha512(), NULL); - } - HMAC_Update(ctx, input1->buffer, input1->bufferSize); - HMAC_Update(ctx, input2->buffer, input2->bufferSize); - HMAC_Final(ctx, output->buffer, (unsigned int *)(&output->bufferSize)); - - HMAC_CTX_free(ctx); - return SQLITE_OK; -} - -CODEC_STATIC void opensslKdf(Buffer *password, Buffer *salt, int workfactor, Buffer *key, int kdfAlgo){ - if( kdfAlgo==CIPHER_KDF_ALGORITHM_SHA1 ){ - PKCS5_PBKDF2_HMAC((const char *)(password->buffer), password->bufferSize, salt->buffer, salt->bufferSize, - workfactor, EVP_sha1(), key->bufferSize, key->buffer); - }else if( kdfAlgo==CIPHER_KDF_ALGORITHM_SHA256 ){ - PKCS5_PBKDF2_HMAC((const char *)(password->buffer), password->bufferSize, salt->buffer, salt->bufferSize, - workfactor, EVP_sha256(), key->bufferSize, key->buffer); - }else if( kdfAlgo==CIPHER_KDF_ALGORITHM_SHA512 ){ - PKCS5_PBKDF2_HMAC((const char *)(password->buffer), password->bufferSize, salt->buffer, salt->bufferSize, - workfactor, EVP_sha512(), key->bufferSize, key->buffer); - } -} - -/************** End file hw_codec_openssl.c *********************************/ -/************** Begin file hw_codec.c ***************************************/ - -#include "securec.h" - -typedef enum{ - OPERATE_CONTEXT_READ = 0, - OPERATE_CONTEXT_WRITE, - OPERATE_CONTEXT_BOTH -}OperateContext; - -CODEC_STATIC int sqlite3CodecIsHex(const unsigned char *buffer, int bufferSize){ - int i; - for(i = 0; i < bufferSize; i++){ - if((buffer[i] < '0' || buffer[i] > '9') && - (buffer[i] < 'a' || buffer[i] > 'f') && - (buffer[i] < 'A' || buffer[i] > 'F')){ - return 0; - } - } - return 1; -} - -CODEC_STATIC int sqlite3CodecHex2int(char input){ - if(input >= '0' && input <= '9'){ - return (int)(input - '0'); - }else if(input >= 'a' && input <= 'f'){ - return (int)(input - 'a') + 10; - }else if(input >= 'A' && input <= 'F'){ - return (int)(input - 'A') + 10; - }else{ - return 0; - } -} - -CODEC_STATIC void sqlite3CodecHex2Bin(unsigned char *inputBuffer, int inputBuffersize, unsigned char *outputBuffer){ - int i; - for(i = 0; i < inputBuffersize - 1; i += 2){ - outputBuffer[i / 2] = sqlite3CodecHex2int(inputBuffer[i]) << 4 | sqlite3CodecHex2int(inputBuffer[i + 1]); - } - return; -} - -CODEC_STATIC void sqlite3CodecBin2Hex(unsigned char *inputBuffer, int inputBuffersize, unsigned char *outputBuffer){ - char *buffer = NULL; - int i; - for(i = 0; i < inputBuffersize; i++){ - buffer = (char *)(outputBuffer + i * 2); - sqlite3_snprintf(3, buffer, "%02x ", inputBuffer[i]); - } - return; -} - -CODEC_STATIC int sqlite3CodecIfMemset(unsigned char *input, unsigned char val, int len){ - int i; - for(i = 0; i < len; i++){ - if(input[i] != val){ - return 0; - } - } - return 1; -} - -CODEC_STATIC int sqlite3CodecIsKeyInfoFormat(const unsigned char *input, int inputSize){ - return (input[0] == 'x') && (input[1] == '\'') && (input[inputSize - 1] == '\'') && (sqlite3CodecIsHex(input + 2, inputSize - 3)) ? 1 : 0; -} - -CODEC_STATIC void sqlite3CodecSetError(CodecContext *ctx, int error){ - if(ctx->pBt){ - ctx->pBt->pBt->pPager->errCode = error; - ctx->pBt->pBt->db->errCode = error; - } - return; -} - -CODEC_STATIC void sqlite3CodecClearDeriveKey(KeyContext *keyCtx){ - if(keyCtx->key != NULL){ - (void)memset_s(keyCtx->key, keyCtx->codecConst.keySize, 0, keyCtx->codecConst.keySize); - sqlite3_free(keyCtx->key); - keyCtx->key = NULL; - } - if(keyCtx->hmacKey != NULL){ - (void)memset_s(keyCtx->hmacKey, keyCtx->codecConst.keySize, 0, keyCtx->codecConst.keySize); - sqlite3_free(keyCtx->hmacKey); - keyCtx->hmacKey = NULL; - } - if(keyCtx->keyInfo != NULL){ - (void)memset_s(keyCtx->keyInfo, keyCtx->codecConst.keyInfoSize, 0, keyCtx->codecConst.keyInfoSize); - sqlite3_free(keyCtx->keyInfo); - keyCtx->keyInfo = NULL; - } - keyCtx->deriveFlag = 0; -} - -CODEC_STATIC void sqlite3CodecClearPassword(KeyContext *keyCtx){ - if(keyCtx->password != NULL){ - (void)memset_s(keyCtx->password, keyCtx->passwordSize, 0, keyCtx->passwordSize); - sqlite3_free(keyCtx->password); - keyCtx->password = NULL; - } - keyCtx->passwordSize = 0; -} - -CODEC_STATIC void sqlite3CodecInitDeriveKeyMemory(KeyContext *keyCtx){ - keyCtx->key = (unsigned char *)sqlite3Malloc(keyCtx->codecConst.keySize); - keyCtx->hmacKey = (unsigned char *)sqlite3Malloc(keyCtx->codecConst.keySize); - keyCtx->keyInfo = (unsigned char *)sqlite3Malloc(keyCtx->codecConst.keyInfoSize); - return; -} - -CODEC_STATIC int sqlite3CodecKeyCtxCmp(KeyContext *first, KeyContext *second){ - if(memcmp((unsigned char *)first, (unsigned char *)second, sizeof(CodecConstant))){ - return 0; - } - if(first->iter != second->iter){ - return 0; - } - if(first->passwordSize != second->passwordSize){ - return 0; - } - if((first->password != second->password) && memcmp(first->password, second->password, first->passwordSize)){ - return 0; - } - return 1; -} - -// This function will free all resources of key context, except it self. -CODEC_STATIC void sqlite3CodecFreeKeyContext(KeyContext *keyCtx){ - sqlite3CodecClearDeriveKey(keyCtx); - sqlite3CodecClearPassword(keyCtx); - (void)opensslFreeCipher(keyCtx->codecConst.cipher); - (void)memset_s(keyCtx, sizeof(KeyContext), 0, KEY_CONTEXT_HEAD_SIZE); -} - -// You should clear key derive result of output before you call this function -CODEC_STATIC int sqlite3CodecCopyDeriveKey(KeyContext *input, KeyContext *output){ - errno_t rc = EOK; - if(input->key != NULL && input->codecConst.keySize > 0){ - output->key = (unsigned char *)sqlite3Malloc(output->codecConst.keySize); - if(output->key == NULL){ - sqlite3CodecFreeKeyContext(output); - return SQLITE_NOMEM; - } - rc = memcpy_s(output->key, output->codecConst.keySize, input->key, input->codecConst.keySize); - if(rc != EOK){ - sqlite3CodecFreeKeyContext(output); - return SQLITE_ERROR; - } - } - if(input->hmacKey != NULL && input->codecConst.keySize > 0){ - output->hmacKey = (unsigned char *)sqlite3Malloc(output->codecConst.keySize); - if(output->hmacKey == NULL){ - sqlite3CodecFreeKeyContext(output); - return SQLITE_NOMEM; - } - rc = memcpy_s(output->hmacKey, output->codecConst.keySize, input->hmacKey, input->codecConst.keySize); - if(rc != EOK){ - sqlite3CodecFreeKeyContext(output); - return SQLITE_ERROR; - } - } - if(input->keyInfo != NULL && input->codecConst.keyInfoSize > 0){ - output->keyInfo = (unsigned char *)sqlite3Malloc(output->codecConst.keyInfoSize); - if(output->keyInfo == NULL){ - sqlite3CodecFreeKeyContext(output); - return SQLITE_NOMEM; - } - rc = memcpy_s(output->keyInfo, output->codecConst.keyInfoSize, input->keyInfo, input->codecConst.keyInfoSize); - if(rc != EOK){ - sqlite3CodecFreeKeyContext(output); - return SQLITE_ERROR; - } - } - return SQLITE_OK; -} - -// You should set all key infos including salt before you call this function -CODEC_STATIC int sqlite3CodecDeriveKey(CodecContext *ctx, OperateContext whichKey){ - KeyContext *keyCtx = NULL; - KeyContext *secondKeyCtx = NULL; - switch(whichKey){ - case OPERATE_CONTEXT_READ: - keyCtx = ctx->readCtx; - secondKeyCtx = ctx->writeCtx; - break; - case OPERATE_CONTEXT_WRITE: - keyCtx = ctx->writeCtx; - secondKeyCtx = ctx->readCtx; - break; - default: - return SQLITE_ERROR; - } - if(keyCtx->password == NULL || keyCtx->passwordSize <= 0){ - return SQLITE_ERROR; - } - if(keyCtx->deriveFlag){ - return SQLITE_OK; - } - errno_t memcpyRc = EOK; - unsigned char salt[SALT_SIZE]; - if (ctx->pBt != NULL && sqlite3OsRead(ctx->pBt->pBt->pPager->fd, salt, SALT_SIZE, 0) == SQLITE_OK) { - assert(SALT_SIZE == FILE_HEADER_SIZE); - if (memcmp(SQLITE_FILE_HEADER, salt, SALT_SIZE) != 0 && memcmp(ctx->salt, salt, SALT_SIZE) != 0) { - memcpyRc = memcpy_s(ctx->salt, FILE_HEADER_SIZE, salt, SALT_SIZE); - if(memcpyRc != EOK){ - return SQLITE_ERROR; - } - } - } - sqlite3CodecInitDeriveKeyMemory(keyCtx); - if(keyCtx->key == NULL || keyCtx->hmacKey == NULL || keyCtx->keyInfo == NULL){ - sqlite3CodecClearDeriveKey(keyCtx); - return SQLITE_NOMEM; - } - if((keyCtx->passwordSize == keyCtx->codecConst.keyInfoSize) && - (sqlite3CodecIsKeyInfoFormat(keyCtx->password, keyCtx->passwordSize))){ - sqlite3CodecHex2Bin(keyCtx->password + 2, keyCtx->codecConst.keySize * 2, keyCtx->key); - sqlite3CodecHex2Bin(keyCtx->password + 2 + keyCtx->codecConst.keySize * 2, SALT_SIZE * 2, ctx->salt); - memcpyRc = memcpy_s(keyCtx->keyInfo, keyCtx->codecConst.keyInfoSize, keyCtx->password, keyCtx->passwordSize); - if(memcpyRc != EOK){ - return SQLITE_ERROR; - } - }else if((keyCtx->passwordSize == keyCtx->codecConst.keyInfoSize - SALT_SIZE * 2) && - (sqlite3CodecIsKeyInfoFormat(keyCtx->password, keyCtx->passwordSize))){ - sqlite3CodecHex2Bin(keyCtx->password + 2, keyCtx->codecConst.keySize * 2, keyCtx->key); - memcpyRc = memcpy_s(keyCtx->keyInfo, keyCtx->codecConst.keyInfoSize, keyCtx->password, keyCtx->passwordSize); - if(memcpyRc != EOK){ - return SQLITE_ERROR; - } - sqlite3CodecBin2Hex(ctx->salt, SALT_SIZE, keyCtx->keyInfo + 2 + keyCtx->codecConst.keySize * 2); - keyCtx->keyInfo[keyCtx->codecConst.keyInfoSize - 1] = '\''; - }else{ - Buffer password; - Buffer salt; - Buffer key; - password.buffer = keyCtx->password; - password.bufferSize = keyCtx->passwordSize; - salt.buffer = ctx->salt; - salt.bufferSize = SALT_SIZE; - key.buffer = keyCtx->key; - key.bufferSize = keyCtx->codecConst.keySize; - opensslKdf(&password, &salt, keyCtx->iter, &key, keyCtx->codecConst.kdfAlgo); - keyCtx->keyInfo[0] = 'x'; - keyCtx->keyInfo[1] = '\''; - sqlite3CodecBin2Hex(keyCtx->key, keyCtx->codecConst.keySize, keyCtx->keyInfo + 2); - sqlite3CodecBin2Hex(ctx->salt, SALT_SIZE, keyCtx->keyInfo + 2 + keyCtx->codecConst.keySize * 2); - keyCtx->keyInfo[keyCtx->codecConst.keyInfoSize - 1] = '\''; - } - int i; - for(i = 0; i < SALT_SIZE; i++){ - ctx->hmacSalt[i] = ctx->salt[i] ^ HMAC_SALT_MASK; - } - Buffer hmacPassword; - Buffer hmacSalt; - Buffer hmacKey; - hmacPassword.buffer = keyCtx->key; - hmacPassword.bufferSize = keyCtx->codecConst.keySize; - hmacSalt.buffer = ctx->hmacSalt; - hmacSalt.bufferSize = SALT_SIZE; - hmacKey.buffer = keyCtx->hmacKey; - hmacKey.bufferSize = keyCtx->codecConst.keySize; - opensslKdf(&hmacPassword, &hmacSalt, HMAC_ITER, &hmacKey, keyCtx->codecConst.kdfAlgo); - keyCtx->deriveFlag = 1; - if(sqlite3CodecKeyCtxCmp(keyCtx, secondKeyCtx)){ - sqlite3CodecClearDeriveKey(secondKeyCtx); - int rc = sqlite3CodecCopyDeriveKey(keyCtx, secondKeyCtx); - if(rc == SQLITE_OK){ - secondKeyCtx->deriveFlag = 1; - // clear password - if(!(ctx->savePassword)){ - sqlite3CodecClearPassword(secondKeyCtx); - } - } - } - // clear password - if(!(ctx->savePassword)){ - sqlite3CodecClearPassword(keyCtx); - } - return SQLITE_OK; -} - -// This function may clear key derive infos -CODEC_STATIC int sqlite3CodecSetCodecConstant(KeyContext *keyCtx, const char *cipherName){ - if(keyCtx->codecConst.cipher){ - if(sqlite3StrICmp(cipherName, opensslGetCipherName(keyCtx->codecConst.cipher)) == 0){ - return SQLITE_OK; - } - } - sqlite3CodecClearDeriveKey(keyCtx); - void *cipher = opensslGetCipher(cipherName); - if(cipher != NULL){ - keyCtx->codecConst.cipher = cipher; - } else { - return SQLITE_ERROR; - } - keyCtx->codecConst.keySize = opensslGetKeySize(keyCtx->codecConst.cipher); - keyCtx->codecConst.keyInfoSize = (keyCtx->codecConst.keySize + SALT_SIZE) * 2 + 3; - keyCtx->codecConst.initVectorSize = opensslGetInitVectorSize(keyCtx->codecConst.cipher); - return SQLITE_OK; -} - -// You should clear key derive infos before you call this function -CODEC_STATIC int sqlite3CodecSetIter(KeyContext *keyCtx, int iter){ - keyCtx->iter = iter; - return SQLITE_OK; -} - -#ifdef SQLITE_CODEC_ATTACH_CHANGED -#define CIPHER_ID_AES_256_CBC 0 -#define CIPHER_ID_AES_256_GCM 1 - -#define CIPHER_TOTAL_NUM 2 - -#define CIPHER_NAME_AES_256_CBC "aes-256-cbc" -#define CIPHER_NAME_AES_256_GCM "aes-256-gcm" - -struct CodecCipherNameId { - int cipherId; - const char *cipherName; -}; - -static const struct CodecCipherNameId g_cipherNameIdMap[CIPHER_TOTAL_NUM] = { - { CIPHER_ID_AES_256_CBC, CIPHER_NAME_AES_256_CBC }, - { CIPHER_ID_AES_256_GCM, CIPHER_NAME_AES_256_GCM } -}; - -SQLITE_PRIVATE void sqlite3CodecResetParameters(CodecParameter *p) -{ - p->kdfIter = DEFAULT_ITER; - p->pageSize = DEFAULT_PAGE_SIZE; - p->cipher = CIPHER_ID_AES_256_GCM; - p->hmacAlgo = DEFAULT_HMAC_ALGORITHM; - p->kdfAlgo = DEFAULT_KDF_ALGORITHM; -} - -CODEC_STATIC void sqlite3CodecSetDefaultAttachCipher(CodecParameter *parm, const char *cipherName){ - int i; - for( i=0; icipher = g_cipherNameIdMap[i].cipherId; - sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - return; - } - } - sqlite3_log(SQLITE_WARNING, "invalid attach cipher algorithm"); -} - -CODEC_STATIC const char *sqlite3CodecGetDefaultAttachCipher(CodecParameter *parm){ - const char *attachedCipher = CIPHER_NAME_AES_256_GCM; - sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - if( (parm->cipher>=0) && (parm->ciphercipher].cipherName; - } - sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - return attachedCipher; -} - -CODEC_STATIC void sqlite3CodecSetDefaultAttachKdfIter(CodecParameter *parm, int iter){ - if( iter<=0 ){ - return; - } - sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - parm->kdfIter = iter; - sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -} - -CODEC_STATIC int sqlite3CodecGetDefaultAttachKdfIter(CodecParameter *parm){ - sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - int iterNum = parm->kdfIter; - sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - return iterNum; -} - -CODEC_STATIC void sqlite3CodecSetDefaultAttachHmacAlgo(CodecParameter *parm, int hmacAlgo){ - sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - parm->hmacAlgo = hmacAlgo; - sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -} - -CODEC_STATIC int sqlite3CodecGetDefaultAttachHmacAlgo(CodecParameter *parm){ - sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - int hmacAlgo = parm->hmacAlgo; - sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - return hmacAlgo; -} - -CODEC_STATIC void sqlite3CodecSetDefaultAttachKdfAlgo(CodecParameter *parm, int kdfAlgo){ - sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - parm->kdfAlgo = kdfAlgo; - sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -} - -CODEC_STATIC int sqlite3CodecGetDefaultAttachKdfAlgo(CodecParameter *parm){ - sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - int kdfAlgo = parm->kdfAlgo; - sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - return kdfAlgo; -} - -CODEC_STATIC void sqlite3CodecSetDefaultAttachPageSize(CodecParameter *parm, int pageSize){ - sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - parm->pageSize = pageSize; - sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); -} - -CODEC_STATIC int sqlite3CodecGetDefaultAttachPageSize(CodecParameter *parm){ - sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - int pageSize = parm->pageSize; - sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); - return pageSize; -} - -#endif /* SQLITE_CODEC_ATTACH_CHANGED */ - -// You should clear key derive infos and password infos before you call this function -CODEC_STATIC int sqlite3CodecSetPassword(KeyContext *keyCtx, const void *zKey, int nKey){ - keyCtx->passwordSize = nKey; - keyCtx->password = (unsigned char *)sqlite3Malloc(keyCtx->passwordSize); - if(keyCtx->password == NULL){ - return SQLITE_NOMEM; - } - errno_t rc = memcpy_s(keyCtx->password, keyCtx->passwordSize, zKey, nKey); - if(rc != EOK){ - sqlite3CodecClearPassword(keyCtx); - return SQLITE_ERROR; - } - return SQLITE_OK; -} - -// You should clear key derive infos and password infos before you call this function -CODEC_STATIC int sqlite3CodecSetHmacAlgorithm(KeyContext *keyCtx, int hmacAlgo){ - keyCtx->codecConst.hmacAlgo = hmacAlgo; - keyCtx->codecConst.hmacSize = opensslGetHmacSize(keyCtx); - int cipherBlockSize = opensslGetBlockSize(keyCtx->codecConst.cipher); - int blockSize = cipherBlockSize; - while(blockSize < MIN_BLOCK_SIZE){ - blockSize += cipherBlockSize; - } - int reserveSize = MAX_INIT_VECTOR_SIZE + keyCtx->codecConst.hmacSize; - if(reserveSize % blockSize == 0){ - keyCtx->codecConst.reserveSize = reserveSize; - }else{ - keyCtx->codecConst.reserveSize = (reserveSize / blockSize + 1) * blockSize; - } - return SQLITE_OK; -} - -CODEC_STATIC int sqlite3CodecSetKdfAlgorithm(KeyContext *keyCtx, int kdfAlgo){ - keyCtx->codecConst.kdfAlgo = kdfAlgo; - return SQLITE_OK; -} - -CODEC_STATIC int sqlite3CodecSetCipherPageSize(CodecContext *ctx, int size){ - if(!((size != 0) && ((size & (size - 1)) == 0)) || size < 512 || size > 65536) { - sqlite3_log(SQLITE_ERROR, "codec: cipher_page_size not a power of 2 and between 512 and 65536 inclusive(%d).", size); - return SQLITE_ERROR; - } - int cipherPageSize = ctx->readCtx->codecConst.cipherPageSize; - (void)memset_s(ctx->buffer, cipherPageSize, 0, cipherPageSize); - sqlite3_free(ctx->buffer); - ctx->readCtx->codecConst.cipherPageSize = size; - ctx->writeCtx->codecConst.cipherPageSize = size; - - ctx->buffer = (unsigned char *)sqlite3Malloc(size); - if (ctx->buffer == NULL) { - sqlite3_log(SQLITE_NOMEM, "codec: alloc mem failed when set cipher page size(%d).", size); - return SQLITE_NOMEM; - } - return SQLITE_OK; -} - -// You should clear output before you call this function -CODEC_STATIC int sqlite3CodecCopyKeyContext(KeyContext *input, KeyContext *output){ - errno_t rc = memcpy_s(output, sizeof(KeyContext), input, KEY_CONTEXT_HEAD_SIZE); - if(rc != EOK){ - return SQLITE_ERROR; - } - if(input->password != NULL && input->passwordSize > 0){ - output->password = (unsigned char *)sqlite3Malloc(output->passwordSize); - if(output->password == NULL){ - sqlite3CodecFreeKeyContext(output); - return SQLITE_NOMEM; - } - rc = memcpy_s(output->password, output->passwordSize, input->password, input->passwordSize); - if(rc != EOK){ - sqlite3CodecFreeKeyContext(output); - return SQLITE_ERROR; - } - } - return sqlite3CodecCopyDeriveKey(input, output); -} - -// You should clear key context before you call this function -#ifdef SQLITE_CODEC_ATTACH_CHANGED -CODEC_STATIC int sqlite3CodecInitKeyContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey, int attachFlag){ -#else -CODEC_STATIC int sqlite3CodecInitKeyContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey){ -#endif /* SQLITE_CODEC_ATTACH_CHANGED */ - int rc = SQLITE_OK; - KeyContext *keyCtx = ctx->readCtx; -#ifdef SQLITE_CODEC_ATTACH_CHANGED - if( attachFlag!=0 ){ - CodecParameter *parm = &p->db->codecParm; - int hmacAlgo = sqlite3CodecGetDefaultAttachHmacAlgo(parm); - rc = sqlite3CodecSetCodecConstant(keyCtx, sqlite3CodecGetDefaultAttachCipher(parm)); - rc += sqlite3CodecSetIter(keyCtx, sqlite3CodecGetDefaultAttachKdfIter(parm)); - if( hmacAlgo!=0 ){ - rc += sqlite3CodecSetHmacAlgorithm(keyCtx, hmacAlgo); - } - int attachKdfAlgo = sqlite3CodecGetDefaultAttachKdfAlgo(parm); - if( attachKdfAlgo!=0 ){ - rc += sqlite3CodecSetKdfAlgorithm(keyCtx, attachKdfAlgo); - } - int cipherPageSize = sqlite3CodecGetDefaultAttachPageSize(parm); - if( cipherPageSize!=0 ){ - rc += sqlite3CodecSetCipherPageSize(ctx, cipherPageSize); - if ( rc != SQLITE_OK ) { - sqlite3CodecFreeKeyContext(keyCtx); - return SQLITE_ERROR; - } - rc += sqlite3BtreeSetPageSize(p, cipherPageSize, keyCtx->codecConst.reserveSize, 0); - } - }else{ - rc = sqlite3CodecSetCodecConstant(keyCtx, DEFAULT_CIPHER); - rc += sqlite3CodecSetIter(keyCtx, DEFAULT_ITER); - rc += sqlite3CodecSetHmacAlgorithm(keyCtx, DEFAULT_HMAC_ALGORITHM); - rc += sqlite3CodecSetKdfAlgorithm(keyCtx, DEFAULT_KDF_ALGORITHM); - } -#else - rc = sqlite3CodecSetCodecConstant(keyCtx, DEFAULT_CIPHER); - rc += sqlite3CodecSetIter(keyCtx, DEFAULT_ITER); - rc += sqlite3CodecSetHmacAlgorithm(keyCtx, DEFAULT_HMAC_ALGORITHM); - rc += sqlite3CodecSetKdfAlgorithm(keyCtx, DEFAULT_KDF_ALGORITHM); -#endif /* SQLITE_CODEC_ATTACH_CHANGED */ - keyCtx->codecConst.rekeyHmacAlgo = DEFAULT_HMAC_ALGORITHM; - rc += sqlite3CodecSetPassword(keyCtx, zKey, nKey); - if(rc != SQLITE_OK){ - sqlite3CodecFreeKeyContext(keyCtx); - return SQLITE_ERROR; - } - return SQLITE_OK; -} - -// This function will free all resources of codec context, except it self. -CODEC_STATIC void sqlite3CodecFreeContext(CodecContext *ctx){ - if(ctx->buffer){ - int cipherPageSize = ctx->readCtx->codecConst.cipherPageSize; - (void)memset_s(ctx->buffer, cipherPageSize, 0, cipherPageSize); - sqlite3_free(ctx->buffer); - ctx->buffer = NULL; - } - if(ctx->readCtx){ - sqlite3CodecFreeKeyContext(ctx->readCtx); - sqlite3_free(ctx->readCtx); - ctx->readCtx = NULL; - } - if(ctx->writeCtx){ - sqlite3CodecFreeKeyContext(ctx->writeCtx); - sqlite3_free(ctx->writeCtx); - ctx->writeCtx = NULL; - } - (void)memset_s(ctx, sizeof(CodecContext), 0, sizeof(CodecContext)); - return; -} -#ifdef SQLITE_CODEC_ATTACH_CHANGED -CODEC_STATIC int sqlite3CodecInitContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey, int nDb){ - int attachFlag = (nDb > 1) ? 1 : 0; - int defaultPageSz = attachFlag ? p->db->codecParm.pageSize : DEFAULT_PAGE_SIZE; -#else -CODEC_STATIC int sqlite3CodecInitContext(CodecContext *ctx, Btree *p, const void *zKey, int nKey){ - int defaultPageSz = DEFAULT_PAGE_SIZE; -#endif /* SQLITE_CODEC_ATTACH_CHANGED */ - sqlite3_file *fd = p->pBt->pPager->fd; - ctx->pBt = p; - ctx->savePassword = 0; - ctx->buffer = (unsigned char *)sqlite3Malloc(defaultPageSz); - ctx->readCtx = (KeyContext *)sqlite3Malloc(sizeof(KeyContext)); - ctx->writeCtx = (KeyContext *)sqlite3Malloc(sizeof(KeyContext)); - if(ctx->buffer == NULL || ctx->readCtx == NULL || ctx->writeCtx == NULL){ - sqlite3CodecFreeContext(ctx); - return SQLITE_NOMEM; - } - errno_t memsetRc = memset_s(ctx->buffer, defaultPageSz, 0, defaultPageSz); - memsetRc += memset_s(ctx->readCtx, sizeof(KeyContext), 0, sizeof(KeyContext)); - memsetRc += memset_s(ctx->writeCtx, sizeof(KeyContext), 0, sizeof(KeyContext)); - if(memsetRc != EOK){ - sqlite3CodecFreeContext(ctx); - return SQLITE_ERROR; - } - ctx->readCtx->codecConst.cipherPageSize = defaultPageSz; - ctx->writeCtx->codecConst.cipherPageSize = defaultPageSz; -#ifdef SQLITE_CODEC_ATTACH_CHANGED - int rc = sqlite3CodecInitKeyContext(ctx, p, zKey, nKey, attachFlag); -#else - int rc = sqlite3CodecInitKeyContext(ctx, p, zKey, nKey); -#endif /* SQLITE_CODEC_ATTACH_CHANGED */ - if(rc != SQLITE_OK){ - sqlite3CodecFreeContext(ctx); - return SQLITE_ERROR; - } - rc = sqlite3CodecCopyKeyContext(ctx->readCtx, ctx->writeCtx); - if(rc != SQLITE_OK){ - sqlite3CodecFreeContext(ctx); - return SQLITE_ERROR; - } - if(fd == NULL || !(isOpen(fd)) || sqlite3OsRead(fd, ctx->salt, SALT_SIZE, 0) != SQLITE_OK){ - Buffer salt; - salt.buffer = ctx->salt; - salt.bufferSize = SALT_SIZE; - rc = opensslGetRandom(&salt); - if(rc != SQLITE_OK){ - sqlite3CodecFreeContext(ctx); - return rc; - } - } - return SQLITE_OK; -} - -CODEC_STATIC int sqlite3CodecGetDbIndex(sqlite3 *db, const char *zDb){ - int nDbIndex; - if(zDb == NULL){ - return 0; - } - for(nDbIndex = 0; nDbIndex < db->nDb; nDbIndex++){ - const char *zDbSName = db->aDb[nDbIndex].zDbSName; - if(strcmp(zDbSName, zDb) == 0){ - return nDbIndex; - } - } - return 0; -} - -CODEC_STATIC void sqlite3CodecTransPgno(Pgno input, unsigned char *output){ -#ifdef CIPHER_BIG_ENDAIN - sqlite3Put4byte(output, input); -#else - output[0] = (u8)input; - output[1] = (u8)(input>>8); - output[2] = (u8)(input>>16); - output[3] = (u8)(input>>24); -#endif -} - -CODEC_STATIC int sqlite3CodecHmac(KeyContext *ctx, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *output){ - Buffer key; - key.buffer = ctx->hmacKey; - key.bufferSize = ctx->codecConst.keySize; - Buffer input1; - input1.buffer = input; - input1.bufferSize = bufferSize; - Buffer input2; - unsigned char pgnoBuffer[sizeof(Pgno)]; - sqlite3CodecTransPgno(pgno, pgnoBuffer); - input2.buffer = pgnoBuffer; - input2.bufferSize = sizeof(Pgno); - Buffer outputBuffer; - outputBuffer.buffer = output; - outputBuffer.bufferSize = 0; - int rc = opensslHmac(&key, &input1, &input2, &outputBuffer, ctx->codecConst.hmacAlgo); - if(rc != SQLITE_OK || outputBuffer.bufferSize != ctx->codecConst.hmacSize){ - return SQLITE_ERROR; - } - return SQLITE_OK; -} - -CODEC_STATIC int sqlite3CodecCheckHmac(KeyContext *ctx, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *expectResult){ - if (ctx->codecConst.hmacSize <= 0) { - return 1; - } - int rc = SQLITE_OK; - if (ctx->codecConst.hmacSize <= MAX_HMAC_SIZE) { - unsigned char buffer[MAX_HMAC_SIZE]; - rc = sqlite3CodecHmac(ctx, pgno, bufferSize, input, buffer); - if(rc != SQLITE_OK){ - return 1; - } - return memcmp(buffer, expectResult, ctx->codecConst.hmacSize); - } else { - unsigned char *output = (unsigned char *)malloc(ctx->codecConst.hmacSize); - if (output == NULL) { - return 1; - } - rc = sqlite3CodecHmac(ctx, pgno, bufferSize, input, output); - if(rc != SQLITE_OK){ - free(output); - return 1; - } - rc = memcmp(output, expectResult, ctx->codecConst.hmacSize); - free(output); - return rc; - } -} - -CODEC_STATIC int sqlite3CodecEncryptData(CodecContext *ctx, OperateContext whichKey, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *output){ - KeyContext *keyCtx = NULL; - switch(whichKey){ - case OPERATE_CONTEXT_READ: - keyCtx = ctx->readCtx; - break; - case OPERATE_CONTEXT_WRITE: - keyCtx = ctx->writeCtx; - break; - default: - return SQLITE_ERROR; - } - int rc = SQLITE_OK; - if(!(keyCtx->deriveFlag)){ - rc = sqlite3CodecDeriveKey(ctx, whichKey); - if(rc != SQLITE_OK){ - return rc; - } - } - if(keyCtx->codecConst.keySize == 0){ - return SQLITE_ERROR; - } - Buffer inputBuffer; - inputBuffer.buffer = input; - inputBuffer.bufferSize = bufferSize - keyCtx->codecConst.reserveSize; - Buffer initVector; - initVector.buffer = output + inputBuffer.bufferSize; - initVector.bufferSize = keyCtx->codecConst.initVectorSize; - rc = opensslGetRandom(&initVector); - if(rc != SQLITE_OK){ - return rc; - } - void *cipherCtx = opensslGetCtx(keyCtx->codecConst.cipher, CODEC_OPERATION_ENCRYPT, keyCtx->key, initVector.buffer); - if(cipherCtx == NULL){ - return SQLITE_ERROR; - } - rc = opensslCipher(cipherCtx, &inputBuffer, output); - opensslFreeCtx(cipherCtx); - if(rc != SQLITE_OK){ - return rc; - } - rc = sqlite3CodecHmac(keyCtx, pgno, inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize, output, output + inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize); - if(rc != SQLITE_OK){ - return rc; - } - return SQLITE_OK; -} - -CODEC_STATIC int sqlite3CodecDecryptData(CodecContext *ctx, OperateContext whichKey, Pgno pgno, int bufferSize, unsigned char *input, unsigned char *output){ - KeyContext *keyCtx = NULL; - switch(whichKey){ - case OPERATE_CONTEXT_READ: - keyCtx = ctx->readCtx; - break; - case OPERATE_CONTEXT_WRITE: - keyCtx = ctx->writeCtx; - break; - default: - return SQLITE_ERROR; - } - int rc = SQLITE_OK; - if(!(keyCtx->deriveFlag)){ - rc = sqlite3CodecDeriveKey(ctx, whichKey); - if(rc != SQLITE_OK){ - return rc; - } - } - if(keyCtx->codecConst.keySize == 0){ - return SQLITE_ERROR; - } - if(sqlite3CodecIfMemset(input, 0, bufferSize)){ - errno_t memsetRc = memset_s(output, bufferSize, 0, bufferSize); - if(memsetRc != EOK){ - return SQLITE_ERROR; - } - return SQLITE_OK; - }else{ - Buffer inputBuffer; - inputBuffer.buffer = input; - inputBuffer.bufferSize = bufferSize - keyCtx->codecConst.reserveSize; - if(sqlite3CodecCheckHmac(keyCtx, pgno, inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize, input, input + inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize)){ - sqlite3_log(SQLITE_ERROR, "codec: check hmac error at page %d, hmac %d, kdf %d, pageSize %d, iter %d.", - pgno, keyCtx->codecConst.hmacAlgo, keyCtx->codecConst.kdfAlgo, keyCtx->codecConst.cipherPageSize, keyCtx->iter); - return SQLITE_ERROR; - } - unsigned char *initVector = input + inputBuffer.bufferSize; - void *cipherCtx = opensslGetCtx(keyCtx->codecConst.cipher, CODEC_OPERATION_DECRYPT, keyCtx->key, initVector); - if(cipherCtx == NULL){ - return SQLITE_ERROR; - } - rc = opensslCipher(cipherCtx, &inputBuffer, output); - opensslFreeCtx(cipherCtx); - if(rc != SQLITE_OK){ - return rc; - } - } - return SQLITE_OK; -} - -void* sqlite3Codec(void *ctx, void *data, Pgno pgno, int mode){ - CodecContext *pCtx = (CodecContext *)ctx; - unsigned char *pData = (unsigned char *)data; - int offset = 0; - int rc = SQLITE_OK; - errno_t memcpyRc = EOK; - if(ctx == NULL || data == NULL){ - return pData; - } - if(pgno == 1){ - offset = FILE_HEADER_SIZE; - } - int cipherPageSize = pCtx->readCtx->codecConst.cipherPageSize; - switch(mode){ - case 0: - case 2: - case 3: - if(pgno == 1){ - memcpyRc = memcpy_s(pCtx->buffer, cipherPageSize, SQLITE_FILE_HEADER, FILE_HEADER_SIZE); - if(memcpyRc != EOK){ - sqlite3CodecSetError(pCtx, SQLITE_ERROR); - return pData; - } - } - rc = sqlite3CodecDecryptData(pCtx, OPERATE_CONTEXT_READ, pgno, cipherPageSize - offset, (unsigned char *)(pData + offset), pCtx->buffer + offset); - if(rc != SQLITE_OK){ - sqlite3CodecSetError(pCtx, rc); - } - (void)memcpy_s(pData, cipherPageSize, pCtx->buffer, cipherPageSize); - return pData; - break; - case 6: - if(pgno == 1){ - memcpyRc = memcpy_s(pCtx->buffer, cipherPageSize, pCtx->salt, FILE_HEADER_SIZE); - if(memcpyRc != EOK){ - sqlite3CodecSetError(pCtx, SQLITE_ERROR); - return pData; - } - } - rc = sqlite3CodecEncryptData(pCtx, OPERATE_CONTEXT_WRITE, pgno, cipherPageSize - offset, (unsigned char *)(pData + offset), pCtx->buffer + offset); - if(rc != SQLITE_OK){ - sqlite3CodecSetError(pCtx, rc); - return pData; - } - return pCtx->buffer; - break; - case 7: - if(pgno == 1){ - memcpyRc = memcpy_s(pCtx->buffer, cipherPageSize, pCtx->salt, FILE_HEADER_SIZE); - if(memcpyRc != EOK){ - sqlite3CodecSetError(pCtx, SQLITE_ERROR); - return pData; - } - } - rc = sqlite3CodecEncryptData(pCtx, OPERATE_CONTEXT_READ, pgno, cipherPageSize - offset, (unsigned char *)(pData + offset), pCtx->buffer + offset); - if(rc != SQLITE_OK){ - sqlite3CodecSetError(pCtx, rc); - return pData; - } - return pCtx->buffer; - break; - default: - return pData; - break; - } -} - -void sqlite3CodecDetach(void *ctx){ - if(ctx != NULL){ - sqlite3CodecFreeContext((CodecContext *)ctx); - sqlite3_free(ctx); - opensslDeactive(); - } - return; -} - -int sqlite3CodecAttach(sqlite3* db, int nDb, const void *pKey, int nKey){ - if(db == NULL){ - return SQLITE_ERROR; - } - Btree *p = db->aDb[nDb].pBt; - if(p == NULL || pKey == NULL || nKey <= 0){ - return SQLITE_OK; - } - opensslActive(); - CodecContext *ctx = (CodecContext *)sqlite3Malloc(sizeof(CodecContext)); - if(ctx == NULL){ - return SQLITE_NOMEM; - } - errno_t memsetRc = memset_s(ctx, sizeof(CodecContext), 0, sizeof(CodecContext)); - if(memsetRc != EOK){ - sqlite3_free(ctx); - return SQLITE_ERROR; - } - sqlite3_mutex_enter(db->mutex); -#ifdef SQLITE_CODEC_ATTACH_CHANGED - int rc = sqlite3CodecInitContext(ctx, p, pKey, nKey, nDb); -#else - int rc = sqlite3CodecInitContext(ctx, p, pKey, nKey); -#endif /* SQLITE_CODEC_ATTACH_CHANGED */ - if(rc != SQLITE_OK){ - sqlite3_free(ctx); - return rc; - } - sqlite3PagerSetCodec(sqlite3BtreePager(p), sqlite3Codec, NULL, sqlite3CodecDetach, (void *)ctx); - - db->nextPagesize = ctx->readCtx->codecConst.cipherPageSize; - p->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED; - sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); - sqlite3BtreeSecureDelete(p, 1); - if(isOpen(p->pBt->pPager->fd)){ - sqlite3BtreeSetAutoVacuum(p, SQLITE_DEFAULT_AUTOVACUUM); - } - - sqlite3_mutex_leave(db->mutex); - - return SQLITE_OK; -} - -void sqlite3CodecGetKey(sqlite3* db, int nDb, void **pKey, int *nKey) -{ - Btree *p = db->aDb[nDb].pBt; - if(p == NULL){ - return; - } - CodecContext *ctx = (CodecContext *)(p->pBt->pPager->pCodec); - if(ctx){ - if(ctx->savePassword){ - *pKey = ctx->readCtx->password; - *nKey = ctx->readCtx->passwordSize; - }else{ - *pKey = ctx->readCtx->keyInfo; - *nKey = ctx->readCtx->codecConst.keyInfoSize; - } - }else{ - *pKey = NULL; - *nKey = 0; - } - return; -} - -int sqlite3_key(sqlite3 *db, const void *pKey, int nKey){ - return sqlite3_key_v2(db, "main", pKey, nKey); -} - -int sqlite3_key_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey){ - if(db == NULL || pKey == NULL || nKey <= 0){ - return SQLITE_ERROR; - } - int iDb = sqlite3CodecGetDbIndex(db, zDb); - return sqlite3CodecAttach(db, iDb, pKey, nKey); -} - -int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey){ - return sqlite3_rekey_v2(db, "main", pKey, nKey); -} - -int sqlite3_rekey_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey){ - if(db == NULL || pKey == NULL || nKey == 0){ - return SQLITE_ERROR; - } - int iDb = sqlite3CodecGetDbIndex(db, zDb); - Btree *p = db->aDb[iDb].pBt; - if(p == NULL){ - return SQLITE_OK; - } - int pageCount; - Pgno pgno; - PgHdr *page = NULL; - Pager *pPager = p->pBt->pPager; - CodecContext *ctx = (CodecContext *)(p->pBt->pPager->pCodec); - if(ctx == NULL){ - return SQLITE_OK; - } - sqlite3CodecClearDeriveKey(ctx->writeCtx); - sqlite3CodecClearPassword(ctx->writeCtx); - int rc = sqlite3CodecSetPassword(ctx->writeCtx, pKey, nKey); - if(rc != SQLITE_OK){ - return rc; - } - sqlite3_mutex_enter(db->mutex); - (void)sqlite3BtreeBeginTrans(p, 1, 0); - sqlite3PagerPagecount(pPager, &pageCount); - // support hmac algo changed by using rekey operation - int oldHmacAlgo = ctx->writeCtx->codecConst.hmacAlgo; - if( ctx->writeCtx->codecConst.rekeyHmacAlgo!=ctx->writeCtx->codecConst.hmacAlgo ){ - sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, ctx->writeCtx->codecConst.rekeyHmacAlgo); - sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, ctx->writeCtx->codecConst.rekeyHmacAlgo); - } - - for(pgno = 1; pgno <= (unsigned int)pageCount; pgno++){ - if(PAGER_SJ_PGNO(pPager) != pgno){ - rc = sqlite3PagerGet(pPager, pgno, &page, 0); - if(rc == SQLITE_OK){ - rc = sqlite3PagerWrite(page); - if(rc == SQLITE_OK){ - sqlite3PagerUnref(page); - }else{ - sqlite3_log(SQLITE_WARNING, "sqlite3_rekey_v2: error when writing page %d: errno = %d.", pgno, rc); - } - }else{ - sqlite3_log(SQLITE_WARNING, "sqlite3_rekey_v2: error when reading page %d: errno = %d.", pgno, rc); - } - } - } - if(rc == SQLITE_OK){ - (void)sqlite3BtreeCommit(p); - sqlite3CodecFreeKeyContext(ctx->readCtx); - (void)sqlite3CodecCopyKeyContext(ctx->writeCtx, ctx->readCtx); - }else{ - if( ctx->writeCtx->codecConst.rekeyHmacAlgo!=oldHmacAlgo ){ - sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, oldHmacAlgo); - sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, oldHmacAlgo); - } - (void)sqlite3BtreeRollback(p, SQLITE_ABORT_ROLLBACK, 0); - } - sqlite3_mutex_leave(db->mutex); - - return rc; -} - -void sqlite3_activate_see(const char* zPassPhrase){ - return; -} - -CODEC_STATIC void sqlite3CodecReturnPragmaResult(Parse *parse, const char *label, const char *value){ - Vdbe *v = sqlite3GetVdbe(parse); - sqlite3VdbeSetNumCols(v, 1); - sqlite3VdbeSetColName(v, 0, COLNAME_NAME, label, SQLITE_STATIC); - sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, value, 0); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); - return; -} - -// Each configuration setting operation should be done before read/write DB file or there might be some error. -int sqlite3CodecPragma(sqlite3 *db, int iDb, Parse *parse, const char *zLeft, const char *zRight){ - Btree *p = db->aDb[iDb].pBt; - if(p == NULL){ - return 0; - } - CodecContext *ctx = (CodecContext *)(p->pBt->pPager->pCodec); -#ifdef SQLITE_CODEC_ATTACH_CHANGED - CodecParameter *parm = &db->codecParm; - if(sqlite3StrICmp(zLeft, "cipher_default_attach_cipher") == 0 && zRight != NULL){ - (void)sqlite3CodecSetDefaultAttachCipher(parm, zRight); - return 1; - }else if(sqlite3StrICmp(zLeft, "cipher_default_attach_kdf_iter") == 0 && zRight != NULL){ - (void)sqlite3CodecSetDefaultAttachKdfIter(parm, atoi(zRight)); - return 1; - }else if( sqlite3StrICmp(zLeft, "cipher_default_attach_hmac_algo")==0 && zRight!=NULL ){ - /* - ** Make sure to set the Kdf algorithm after setting the Hmac algorithm, or it will not take effect. - ** This behavior is to ensure backward compatible. - */ - if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA1)==0 ){ - sqlite3CodecSetDefaultAttachHmacAlgo(parm, CIPHER_HMAC_ALGORITHM_SHA1); - sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA1); - }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA256)==0 ){ - sqlite3CodecSetDefaultAttachHmacAlgo(parm, CIPHER_HMAC_ALGORITHM_SHA256); - sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA256); - }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA512)==0 ){ - sqlite3CodecSetDefaultAttachHmacAlgo(parm, CIPHER_HMAC_ALGORITHM_SHA512); - sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA512); - }else{ - return 0; - } - return 1; - }else if( sqlite3StrICmp(zLeft, "cipher_default_attach_kdf_algo")==0 && zRight!=NULL ){ - if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA1)==0 ){ - sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA1); - }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA256)==0 ){ - sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA256); - }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA512)==0 ){ - sqlite3CodecSetDefaultAttachKdfAlgo(parm, CIPHER_KDF_ALGORITHM_SHA512); - }else{ - return 0; - } - return 1; - }else if( sqlite3StrICmp(zLeft, "cipher_default_attach_page_size")==0 && zRight!=NULL ){ - (void)sqlite3CodecSetDefaultAttachPageSize(parm, atoi(zRight)); - return 1; - } -#endif /* SQLITE_CODEC_ATTACH_CHANGED */ - if(ctx == NULL){ - return 0; - } - if(sqlite3StrICmp(zLeft, "codec_cipher") == 0){ - if(zRight){ - sqlite3_mutex_enter(db->mutex); - (void)sqlite3CodecSetCodecConstant(ctx->readCtx, zRight); - (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, ctx->readCtx->codecConst.hmacAlgo); - (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, ctx->readCtx->codecConst.hmacAlgo); - sqlite3CodecFreeKeyContext(ctx->writeCtx); - (void)sqlite3CodecCopyKeyContext(ctx->readCtx, ctx->writeCtx); - sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); - sqlite3_mutex_leave(db->mutex); - }else{ - sqlite3CodecReturnPragmaResult(parse, "codec_cipher", opensslGetCipherName(ctx->writeCtx->codecConst.cipher)); - } - }else if(sqlite3StrICmp(zLeft, "codec_kdf_iter") == 0){ - if(zRight){ - (void)sqlite3CodecSetIter(ctx->readCtx, atoi(zRight)); - (void)sqlite3CodecSetIter(ctx->writeCtx, atoi(zRight)); - }else{ - char *iter = sqlite3_mprintf("%d", ctx->writeCtx->iter); - if(iter != NULL){ - sqlite3CodecReturnPragmaResult(parse, "codec_kdf_iter", iter); - sqlite3_free(iter); - } - } - }else if( sqlite3StrICmp(zLeft, "codec_hmac_algo")==0 ){ - /* - ** Make sure to set the Kdf algorithm after setting the Hmac algorithm, or it will not take effect. - ** This behavior is to ensure backward compatible. - */ - if(zRight){ - sqlite3_mutex_enter(db->mutex); - if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA1)==0 ){ - (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, CIPHER_HMAC_ALGORITHM_SHA1); - (void)sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, CIPHER_HMAC_ALGORITHM_SHA1); - (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA1); - (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA1); - }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA256)==0 ){ - (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, CIPHER_HMAC_ALGORITHM_SHA256); - (void)sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, CIPHER_HMAC_ALGORITHM_SHA256); - (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA256); - (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA256); - }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA512)==0 ){ - (void)sqlite3CodecSetHmacAlgorithm(ctx->readCtx, CIPHER_HMAC_ALGORITHM_SHA512); - (void)sqlite3CodecSetHmacAlgorithm(ctx->writeCtx, CIPHER_HMAC_ALGORITHM_SHA512); - (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA512); - (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA512); - }else{ - sqlite3_mutex_leave(db->mutex); - return 0; - } - sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); - sqlite3_mutex_leave(db->mutex); - }else{ - if( ctx->writeCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){ - sqlite3CodecReturnPragmaResult(parse, "codec_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA1); - }else if( ctx->writeCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){ - sqlite3CodecReturnPragmaResult(parse, "codec_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA256); - }else if( ctx->writeCtx->codecConst.hmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){ - sqlite3CodecReturnPragmaResult(parse, "codec_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA512); - } - } - }else if( sqlite3StrICmp(zLeft, "codec_kdf_algo")==0 ){ - if(zRight){ - sqlite3_mutex_enter(db->mutex); - if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA1)==0 ){ - (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA1); - (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA1); - }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA256)==0 ){ - (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA256); - (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA256); - }else if( sqlite3_stricmp(zRight, CIPHER_KDF_ALGORITHM_NAME_SHA512)==0 ){ - (void)sqlite3CodecSetKdfAlgorithm(ctx->readCtx, CIPHER_KDF_ALGORITHM_SHA512); - (void)sqlite3CodecSetKdfAlgorithm(ctx->writeCtx, CIPHER_KDF_ALGORITHM_SHA512); - }else{ - sqlite3_mutex_leave(db->mutex); - return 0; - } - sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); - sqlite3_mutex_leave(db->mutex); - }else{ - if( ctx->writeCtx->codecConst.kdfAlgo==CIPHER_KDF_ALGORITHM_SHA1 ){ - sqlite3CodecReturnPragmaResult(parse, "codec_kdf_algo", CIPHER_KDF_ALGORITHM_NAME_SHA1); - }else if( ctx->writeCtx->codecConst.kdfAlgo==CIPHER_KDF_ALGORITHM_SHA256 ){ - sqlite3CodecReturnPragmaResult(parse, "codec_kdf_algo", CIPHER_KDF_ALGORITHM_NAME_SHA256); - }else if( ctx->writeCtx->codecConst.kdfAlgo==CIPHER_KDF_ALGORITHM_SHA512 ){ - sqlite3CodecReturnPragmaResult(parse, "codec_kdf_algo", CIPHER_KDF_ALGORITHM_NAME_SHA512); - } - } - }else if( sqlite3StrICmp(zLeft, "codec_page_size")==0 ){ - if(zRight){ - sqlite3_mutex_enter(db->mutex); - int rc = sqlite3CodecSetCipherPageSize(ctx, atoi(zRight)); - if (rc != SQLITE_OK){ - sqlite3_mutex_leave(db->mutex); - return 0; - } - sqlite3BtreeSetPageSize(p, ctx->readCtx->codecConst.cipherPageSize, ctx->readCtx->codecConst.reserveSize, 0); - sqlite3_mutex_leave(db->mutex); - } else { - char *pageSize = sqlite3_mprintf("%d", ctx->readCtx->codecConst.cipherPageSize); - if (pageSize != NULL) { - sqlite3CodecReturnPragmaResult(parse, "codec_page_size", pageSize); - sqlite3_free(pageSize); - } - } - }else if(sqlite3StrICmp(zLeft, "codec_rekey_hmac_algo") == 0){ - if(zRight){ - sqlite3_mutex_enter(db->mutex); - if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA1)==0 ){ - ctx->writeCtx->codecConst.rekeyHmacAlgo = CIPHER_HMAC_ALGORITHM_SHA1; - }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA256)==0 ){ - ctx->writeCtx->codecConst.rekeyHmacAlgo = CIPHER_HMAC_ALGORITHM_SHA256; - }else if( sqlite3_stricmp(zRight, CIPHER_HMAC_ALGORITHM_NAME_SHA512)==0 ){ - ctx->writeCtx->codecConst.rekeyHmacAlgo = CIPHER_HMAC_ALGORITHM_SHA512; - }else{ - sqlite3_mutex_leave(db->mutex); - return 0; - } - sqlite3_mutex_leave(db->mutex); - }else{ - if( ctx->writeCtx->codecConst.rekeyHmacAlgo==CIPHER_HMAC_ALGORITHM_SHA1 ){ - sqlite3CodecReturnPragmaResult(parse, "codec_rekey_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA1); - }else if( ctx->writeCtx->codecConst.rekeyHmacAlgo==CIPHER_HMAC_ALGORITHM_SHA256 ){ - sqlite3CodecReturnPragmaResult(parse, "codec_rekey_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA256); - }else if( ctx->writeCtx->codecConst.rekeyHmacAlgo==CIPHER_HMAC_ALGORITHM_SHA512 ){ - sqlite3CodecReturnPragmaResult(parse, "codec_rekey_hmac_algo", CIPHER_HMAC_ALGORITHM_NAME_SHA512); - } - } - }else{ - return 0; - } - return 1; -} - -CODEC_STATIC int sqlite3CodecExportMetadata(sqlite3 *db, const char *dbName, const char *metaName){ - char *sql = sqlite3_mprintf("PRAGMA %s;", metaName); - if(sql == NULL){ - return SQLITE_NOMEM; - } - sqlite3_stmt *statement = NULL; - int rc = sqlite3_prepare_v2(db, sql, -1, &statement, NULL); - sqlite3_free(sql); - if(rc != SQLITE_OK){ - return rc; - } - rc = sqlite3_step(statement); - if(rc != SQLITE_ROW){ - sqlite3_finalize(statement); - return rc; - } - int metadata = sqlite3_column_int(statement, 0); - sqlite3_finalize(statement); - - sql = sqlite3_mprintf("PRAGMA %s.%s=%d;", dbName, metaName, metadata); - if(sql == NULL){ - return SQLITE_NOMEM; - } - rc = sqlite3_exec(db, sql, NULL, NULL, NULL); - sqlite3_free(sql); - return rc; -} - -CODEC_STATIC int sqlite3CodecBatchExportSql(sqlite3 *db, const char *sql, char **errMsg){ - sqlite3_stmt *statement = NULL; - int rc = sqlite3_prepare_v2(db, sql, -1, &statement, NULL); - if(rc != SQLITE_OK){ - return rc; - } - while(sqlite3_step(statement) == SQLITE_ROW){ - rc = sqlite3_exec(db, (char*)sqlite3_column_text(statement, 0), NULL, NULL, errMsg); - if(rc != SQLITE_OK){ - sqlite3_finalize(statement); - return rc; - } - } - sqlite3_finalize(statement); - return rc; -} - -void sqlite3CodecExportData(sqlite3_context *context, int argc, sqlite3_value **argv){ - sqlite3 *db = sqlite3_context_db_handle(context); - const char *dbName = (const char*) sqlite3_value_text(argv[0]); - - int rc = SQLITE_OK; - char *sql = NULL; - char *errMsg = NULL; - - u64 flagsBackup = db->flags; - u32 mDbFlagsBackup = db->mDbFlags; - int nChangeBackup = db->nChange; - int nTotalChangeBackup = db->nTotalChange; - int (*xTraceBackup)(u32,void*,void*,void*) = db->trace.xV2; - - db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; - db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder); - db->mDbFlags |= DBFLAG_PreferBuiltin; - db->trace.xV2 = 0; - - rc = sqlite3CodecExportMetadata(db, dbName, "schema_version"); - if(rc != SQLITE_OK){ - goto export_finish; - } - rc = sqlite3CodecExportMetadata(db, dbName, "user_version"); - if(rc != SQLITE_OK){ - goto export_finish; - } - rc = sqlite3CodecExportMetadata(db, dbName, "application_id"); - if(rc != SQLITE_OK){ - goto export_finish; - } - sql = sqlite3_mprintf("SELECT 'CREATE TABLE %s.' || substr(sql,14) FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence' AND rootpage>0;", dbName); - if(sql == NULL){ - rc = SQLITE_NOMEM; - goto export_finish; - } - rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); - sqlite3_free(sql); - if(rc != SQLITE_OK){ - goto export_finish; - } - sql = sqlite3_mprintf("SELECT 'CREATE INDEX %s.' || substr(sql,14) FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %%';", dbName); - if(sql == NULL){ - rc = SQLITE_NOMEM; - goto export_finish; - } - rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); - sqlite3_free(sql); - if(rc != SQLITE_OK){ - goto export_finish; - } - sql = sqlite3_mprintf("SELECT 'CREATE UNIQUE INDEX %s.' || substr(sql,21) FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%';", dbName); - if(sql == NULL){ - rc = SQLITE_NOMEM; - goto export_finish; - } - rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); - sqlite3_free(sql); - if(rc != SQLITE_OK){ - goto export_finish; - } - sql = sqlite3_mprintf("SELECT 'INSERT INTO %s.' || quote(name) || ' SELECT * FROM main.' || quote(name) || ';' FROM main.sqlite_master WHERE type = 'table' AND name!='sqlite_sequence' AND rootpage>0;", dbName); - if(sql == NULL){ - rc = SQLITE_NOMEM; - goto export_finish; - } - rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); - sqlite3_free(sql); - if(rc != SQLITE_OK){ - goto export_finish; - } - sql = sqlite3_mprintf("SELECT 'DELETE FROM %s.' || quote(name) || ';' FROM %s.sqlite_master WHERE name='sqlite_sequence';", dbName, dbName); - if(sql == NULL){ - rc = SQLITE_NOMEM; - goto export_finish; - } - rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); - sqlite3_free(sql); - if(rc != SQLITE_OK){ - goto export_finish; - } - sql = sqlite3_mprintf("SELECT 'INSERT INTO %s.' || quote(name) || ' SELECT * FROM main.' || quote(name) || ';' FROM %s.sqlite_master WHERE name=='sqlite_sequence';", dbName, dbName); - if(sql == NULL){ - rc = SQLITE_NOMEM; - goto export_finish; - } - rc = sqlite3CodecBatchExportSql(db, sql, &errMsg); - sqlite3_free(sql); - if(rc != SQLITE_OK){ - goto export_finish; - } - sql = sqlite3_mprintf("INSERT INTO %s.sqlite_master SELECT type, name, tbl_name, rootpage, sql FROM main.sqlite_master WHERE type='view' OR type='trigger' OR (type='table' AND rootpage=0);", dbName, dbName); - if(sql == NULL){ - rc = SQLITE_NOMEM; - goto export_finish; - } - rc = sqlite3_exec(db, sql, NULL, NULL, &errMsg); - sqlite3_free(sql); - if(rc != SQLITE_OK){ - goto export_finish; - } -export_finish: - db->flags = flagsBackup; - db->mDbFlags = mDbFlagsBackup; - db->nChange = nChangeBackup; - db->nTotalChange = nTotalChangeBackup; - db->trace.xV2 = xTraceBackup; - if(rc != SQLITE_OK){ - if(errMsg != NULL) { - sqlite3_result_error(context, errMsg, -1); - sqlite3DbFree(db, errMsg); - } else { - sqlite3_result_error(context, sqlite3ErrStr(rc), -1); - } - } - return; -} -/************** End file hw_codec.c *****************************************/ -#endif -#ifdef SQLITE_META_DWR -#define META_DWR_MAX_PAGES 500 -#define META_DWR_MAGIC 0x234A86D9 -#define META_DWR_VERSION 0x00000001 -#define META_DWR_INVALID_ZONE 0x55 -#define META_DWR_HEADER_PAGE_SIZE 4096 -#define META_DWR_HEADER_DEFAULT_PAGE_CNT 8 -typedef struct ScanPages { - u32 pageCnt; - u32 pageBufSize; - u32 maxPageNo; - Pgno *pages; -} ScanPages; - -typedef struct MetaDwrHdr { - u32 magic; - u32 version; - u32 dbSize; - u32 mxFrameInWal; - u32 freeListPageNo; - u32 freeListPageCnt; - u32 schemaCookie; - u32 pageSz; - u32 pageCnt; - u64 dbFileInode; - u32 reserved[12]; - u32 checkSum; - u8 *zones; - Pgno *pages; - u32 pageBufSize; - u8 hdrValid; - u8 checkFileId; - u16 needSync; - i64 lastSyncTime; -} MetaDwrHdr; - -#define META_VERIFIED_HDR_LEN (offsetof(MetaDwrHdr, zones)) -#define META_ZONES_LENGTH (META_DWR_MAX_PAGES * sizeof(u8)) -#define META_PAGE_NO_OFFSET (META_VERIFIED_HDR_LEN + META_ZONES_LENGTH) -#define META_FILE_UPDATE_TIMES_PER_SYNC 100 // sync once for every 100 update -#define META_FILE_SYNC_TIMEOUT_MS 30000 // 30 seconds - -static int MetaDwrHeaderSimpleCheck(Pager *pPager, MetaDwrHdr *hdr) { -#if SQLITE_OS_UNIX - if (hdr->checkFileId) { - unixFile *fd = (unixFile *)pPager->fd; - if (fd == NULL || fd->pInode == NULL || pPager->pVfs == NULL) { - return SQLITE_INTERNAL; - } - if (fd->pInode->fileId.ino != hdr->dbFileInode) { - sqlite3_log(SQLITE_IOERR_DATA, "Ino mismatch file %llu dwr file %llu", - fd->pInode->fileId.ino, hdr->dbFileInode); - return SQLITE_IOERR_DATA; - } - } -#endif - if (hdr->pageCnt > META_DWR_MAX_PAGES || hdr->version != META_DWR_VERSION || - hdr->magic != META_DWR_MAGIC || hdr->checkSum != META_DWR_MAGIC) { - sqlite3_log(SQLITE_IOERR_DATA, "Meta dwr file check wrong pageCnt %u, version %u, magic %u, checkSum %u", - hdr->pageCnt, hdr->version, hdr->magic, hdr->checkSum); - return SQLITE_IOERR_DATA; - } - if (hdr->pageSz != pPager->pageSize) { - sqlite3_log(SQLITE_IOERR_DATA, "Meta dwr file check wrong pageSz %u-%u", hdr->pageSz, pPager->pageSize); - return SQLITE_IOERR_DATA; - } - return SQLITE_OK; -} - -static int PragmaMetaDoubleWrie(sqlite3 *db, int iDb, Parse *parse, const char *zLeft, const char *zRight) { - Btree *pBt = db->aDb[iDb].pBt; - if (pBt == NULL || zLeft == NULL || sqlite3StrICmp(zLeft, "meta_double_write") != 0) { - return 0; - } - Pager *pPager = pBt->pBt->pPager; - if (pPager == NULL) { - sqlite3_log(SQLITE_WARNING_DUMP, "Invalid pager handle"); - return 1; - } - if (zRight == NULL) { - Vdbe *v = sqlite3GetVdbe(parse); - sqlite3VdbeSetNumCols(v, 1); - sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "meta_double_write", SQLITE_STATIC); - sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, pPager->metaFd ? "enabled" : "disabled", 0); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); - } else if (strncmp(zRight, "enabled", 7) == 0) { - sqlite3_mutex_enter(db->mutex); - // only support enabled meta double write - int rc = MetaDwrOpenAndCheck(pBt); - if (rc != SQLITE_OK && rc != SQLITE_PERM) { - parse->nErr++; - parse->rc = rc; - } - sqlite3_mutex_leave(db->mutex); - } else if (strncmp(zRight, "disabled", 8) == 0) { - sqlite3_mutex_enter(db->mutex); - MetaDwrDisable(pBt); - sqlite3_mutex_leave(db->mutex); - } - return 1; -} - -static int GetBtreePageNo(MemPage *pPage, void *args) { - ScanPages *pInfo = (ScanPages *)args; - // realloc buffer to store pages - u32 pageCnt = pInfo->pageCnt; - if (pageCnt == pInfo->pageBufSize) { - u32 memSz = sizeof(Pgno) * ROUND8(pageCnt + 1); - Pgno *pages = sqlite3Malloc(memSz); - if (pages == NULL) { - sqlite3_log(SQLITE_NOMEM, "GetPages alloc buffer go wrong %u", memSz); - return SQLITE_NOMEM; - } - if (pageCnt != 0) { - memcpy(pages, pInfo->pages, pageCnt * sizeof(Pgno)); - } - sqlite3_free(pInfo->pages); - pInfo->pageBufSize = ROUND8(pageCnt + 1); - pInfo->pages = pages; - } - pInfo->pages[pageCnt] = pPage->pgno; - pInfo->pageCnt++; - if (pInfo->maxPageNo < pPage->pgno) { - pInfo->maxPageNo = pPage->pgno; - } - return 0; -} - -typedef int (*ScanFn)(MemPage *pPage, void *args); -static SQLITE_NOINLINE int ScanOverflowPages( - MemPage *pPage, /* The page that contains the Cell */ - unsigned char *pCell, /* First byte of the Cell */ - CellInfo *pInfo, /* Size information about the cell */ - ScanFn fn, /* Scan pages function */ - void *args) { - BtShared *pBt; - Pgno ovflPgno; - int rc; - int nOvfl; - u32 ovflPageSize; - - if (pCell + pInfo->nSize > pPage->aDataEnd) { - /* Cell extends past end of page */ - return SQLITE_CORRUPT_BKPT; - } - ovflPgno = get4byte(pCell + pInfo->nSize - 4); - pBt = pPage->pBt; - assert(pBt->usableSize > 4); - ovflPageSize = pBt->usableSize - 4; - nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1) / ovflPageSize; - assert(nOvfl > 0 || - (CORRUPT_DB && (pInfo->nPayload + ovflPageSize) < ovflPageSize)); - while (nOvfl > 0) { - nOvfl--; - Pgno iNext = 0; - MemPage *pOvfl = 0; - if (ovflPgno < 2 || ovflPgno > btreePagecount(pBt)) { - sqlite3_log(SQLITE_WARNING_DUMP, "Ignore for ovfl page not as expect, pgno %u ovflPgno %u novfl %d payload %u local %u", - pPage->pgno, ovflPgno, nOvfl, pInfo->nPayload, pInfo->nLocal); - return SQLITE_MISUSE; - } - rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext); - if (rc) - return rc; - if (pOvfl) { - rc = fn(pOvfl, args); - if (rc) { - return rc; - } - sqlite3PagerUnref(pOvfl->pDbPage); - } - ovflPgno = iNext; - } - return SQLITE_OK; -} - -static int ScanBtreePage( - BtShared *pBt, /* The BTree that contains the table */ - Pgno pgno, /* Page number to clear */ - ScanFn fn, /* Scan pages function */ - void *args) { /* Scan pages args */ - MemPage *pPage; - int rc; - unsigned char *pCell; - int i; - int hdr; - CellInfo info; - - assert(sqlite3_mutex_held(pBt->mutex)); - if (pgno > btreePagecount(pBt)) { - return SQLITE_OK; - } - rc = getAndInitPage(pBt, pgno, &pPage, 0, 0); - if (rc) { - return rc; - } - rc = fn(pPage, args); - if (rc) { - goto SCAN_PAGE_OUT; - } - hdr = pPage->hdrOffset; - for (i = pPage->nCell - 1; i >= 0; i--) { - pCell = findCell(pPage, i); - if (!pPage->leaf) { - rc = ScanBtreePage(pBt, get4byte(pCell), fn, args); - if (rc) { - goto SCAN_PAGE_OUT; - } - } - pPage->xParseCell(pPage, pCell, &info); - if (info.nLocal < info.nPayload) { - rc = ScanOverflowPages(pPage, pCell, &info, fn, args); - if (rc) { - goto SCAN_PAGE_OUT; - } - } - } - if (!pPage->leaf) { - rc = ScanBtreePage(pBt, get4byte(&pPage->aData[hdr + 8]), fn, args); - if (rc) { - goto SCAN_PAGE_OUT; - } - } -SCAN_PAGE_OUT: - releasePage(pPage); - return rc; -} - -static inline int ScanMetaPages(Btree *pBt, ScanPages *pages) { - return ScanBtreePage(pBt->pBt, 1, GetBtreePageNo, pages); -} - -static int ReleaseMetaPages(ScanPages *pages) { - sqlite3_free(pages->pages); - pages->pages = NULL; - return SQLITE_OK; -} - -static void InitMetaHeader(MetaDwrHdr *hdr) { - (void)memset(hdr, 0, META_VERIFIED_HDR_LEN); - hdr->magic = META_DWR_MAGIC; - hdr->version = META_DWR_VERSION; - hdr->checkSum = META_DWR_MAGIC; -} - -static void MetaDwrReleaseHdr(MetaDwrHdr *hdr) { - if (!hdr) { - return; - } - sqlite3_free(hdr->zones); - sqlite3_free(hdr); -} - -static int ExpandMetaPageBuf(MetaDwrHdr *hdr, u32 minimalPageCnt, u32 bufHasData) { - if (minimalPageCnt < hdr->pageBufSize && hdr->zones != NULL) { - return SQLITE_OK; - } - int pageBufSz = ROUND8(MAX(hdr->pageCnt, minimalPageCnt)); - u8 *zones = (u8 *)sqlite3Malloc(pageBufSz * (sizeof(u8) + sizeof(Pgno))); - if (zones == NULL) { - return SQLITE_NOMEM_BKPT; - } - Pgno *pgnos = (Pgno *)(zones + pageBufSz); - if (hdr->zones != NULL) { - if (bufHasData && hdr->pageCnt > 0) { - (void)memcpy(zones, hdr->zones, hdr->pageCnt * sizeof(u8)); - (void)memcpy(pgnos, hdr->pages, hdr->pageCnt * sizeof(Pgno)); - } - sqlite3_free(hdr->zones); - } - hdr->pageBufSize = pageBufSz; - hdr->zones = zones; - hdr->pages = pgnos; - return SQLITE_OK; -} - -static MetaDwrHdr *AllocInitMetaHeaderDwr(Pager *pPager) { - MetaDwrHdr *hdr = sqlite3MallocZero(sizeof(MetaDwrHdr)); - if (hdr == NULL) { - return NULL; - } - InitMetaHeader(hdr); - int rc = ExpandMetaPageBuf(hdr, META_DWR_HEADER_DEFAULT_PAGE_CNT, 0); - if (rc != SQLITE_OK) { - MetaDwrReleaseHdr(hdr); - return NULL; - } - hdr->checkFileId = (pPager->pVfs != NULL && sqlite3_stricmp(pPager->pVfs->zName, "unix") == 0); - return hdr; -} - -static void MetaDwrCloseFile(Pager *pPager) { - if (!pPager->metaFd) { - return; - } -#if SQLITE_OS_UNIX - if (pPager->metaMapPage) { - osMunmap(pPager->metaMapPage, META_DWR_HEADER_PAGE_SIZE); - pPager->metaMapPage = NULL; - } -#endif - if (pPager->metaHdr && pPager->metaHdr->needSync > 0) { - (void)sqlite3OsSync(pPager->metaFd, SQLITE_SYNC_NORMAL); - } - sqlite3OsClose(pPager->metaFd); -} - -static void MetaDwrPagerRelease(Pager *pPager) { - MetaDwrCloseFile(pPager); - MetaDwrReleaseHdr(pPager->metaHdr); - pPager->metaHdr = NULL; - if (pPager->metaFd) { - sqlite3_free(pPager->metaFd); - pPager->metaFd = NULL; - } -} - -static inline int ReadFromHdrPage(Pager *pPager, void *data, int amt, i64 offset) { - if (pPager->metaMapPage) { - (void)memcpy(data, (u8 *)pPager->metaMapPage + offset, amt); - return SQLITE_OK; - } - return sqlite3OsRead(pPager->metaFd, data, amt, offset); -} - -static int MetaDwrReadHeader(Pager *pPager, MetaDwrHdr *hdr) { - i64 sz = 0; - int rc = sqlite3OsFileSize(pPager->metaFd, &sz); - if (rc != SQLITE_OK) { - sqlite3_log(rc, "Meta dwr file size go wrong"); - return rc; - } - if (sz <= META_DWR_HEADER_PAGE_SIZE) { - rc = SQLITE_IOERR_DATA; - goto READ_META_OUT; - } - rc = ReadFromHdrPage(pPager, hdr, META_VERIFIED_HDR_LEN, 0); - if (rc != SQLITE_OK) { - sqlite3_log(rc, "Meta dwr file header read wrong"); - goto READ_META_OUT; - } - rc = MetaDwrHeaderSimpleCheck(pPager, hdr); - if (rc != SQLITE_OK) { - goto READ_META_OUT; - } - // avoid realloc buffer if buf can't hold all pages - rc = ExpandMetaPageBuf(hdr, hdr->pageCnt, 0); - if (rc != SQLITE_OK) { - goto READ_META_OUT; - } - int zoneSize = hdr->pageCnt * sizeof(u8); - rc = ReadFromHdrPage(pPager, hdr->zones, zoneSize, META_VERIFIED_HDR_LEN); - if (rc != SQLITE_OK) { - goto READ_META_OUT; - } - rc = ReadFromHdrPage(pPager, hdr->pages, hdr->pageCnt * sizeof(Pgno), META_PAGE_NO_OFFSET); - if (rc != SQLITE_OK) { - goto READ_META_OUT; - } - for (u32 i = 0; i < hdr->pageCnt; i++) { - u8 zoneIdx = hdr->zones[i]; - if (zoneIdx != 0 && zoneIdx != 1 && zoneIdx != META_DWR_INVALID_ZONE) { - sqlite3_log(SQLITE_IOERR_DATA, "Invalid zoneIdx %d", zoneIdx); - rc = SQLITE_IOERR_DATA; - break; - } - } -READ_META_OUT: - if (rc == SQLITE_IOERR_DATA) { - InitMetaHeader(hdr); - rc = SQLITE_OK; - } - return rc; -} - -static inline u64 CaculateMetaDwrWriteOffset(int pageSz, u32 idx, u8 zone) { - // 1 header page, idx correspond 2 zone pages - return META_DWR_HEADER_PAGE_SIZE + pageSz * (idx * 2 + zone); -} - -static void MetaDwrUpdateHeaderDbInfo(BtShared *pBt) { - MetaDwrHdr *hdr = pBt->pPager->metaHdr; - // 28 offset: dbSize, freelist pageNo, freelist pages count, schema cookie - const u8 *dbHdrInfo = &pBt->pPage1->aData[28]; - hdr->dbSize = sqlite3Get4byte(dbHdrInfo); -#ifndef SQLITE_OMIT_WAL - if (pagerUseWal(pBt->pPager)) { - WalIndexHdr *pWalHdr = &pBt->pPager->pWal->hdr; - if (pWalHdr->isInit) { - hdr->mxFrameInWal = pWalHdr->mxFrame; - hdr->dbSize = pWalHdr->nPage; - } - } else { - hdr->mxFrameInWal = 0; - } -#endif -#if SQLITE_OS_UNIX - if (hdr->checkFileId) { - unixFile *fd = (unixFile *)pBt->pPager->fd; - if (fd == NULL || fd->pInode == NULL) { - sqlite3_log(SQLITE_WARNING_DUMP, "update meta header invalid fd"); - hdr->hdrValid = 0; - return; - } - hdr->dbFileInode = fd->pInode->fileId.ino; - } -#endif - hdr->freeListPageNo = sqlite3Get4byte(dbHdrInfo + 4); - hdr->freeListPageCnt = sqlite3Get4byte(dbHdrInfo + 8); - hdr->schemaCookie = sqlite3Get4byte(dbHdrInfo + 12); - hdr->hdrValid = 1; -} - -static inline int WriteToHdrPage(Pager *pPager, const void *data, int amt, i64 offset) { - if (pPager->metaMapPage) { - (void)memcpy((u8 *)pPager->metaMapPage + offset, data, amt); - return SQLITE_OK; - } - return sqlite3OsWrite(pPager->metaFd, data, amt, offset); -} - -static int MetaDwrWriteHeader(Pager *pPager, MetaDwrHdr *hdr) { - if (pPager->metaChanged == 0 || hdr == NULL || hdr->pageCnt == 0 || hdr->hdrValid == 0) { - return SQLITE_OK; - } - hdr->hdrValid = 0; - hdr->pageSz = pPager->pageSize; - hdr->dbSize = pPager->dbSize; - int rc = WriteToHdrPage(pPager, hdr, META_VERIFIED_HDR_LEN, 0); - if (rc != SQLITE_OK) { - sqlite3_log(rc, "update meta header write hdr %u wrong", META_VERIFIED_HDR_LEN); - return rc; - } - if (hdr->zones) { - int zoneSize = hdr->pageCnt * sizeof(u8); - rc = WriteToHdrPage(pPager, hdr->zones, zoneSize, META_VERIFIED_HDR_LEN); - if (rc != SQLITE_OK) { - sqlite3_log(rc, "update meta header write zonebuf %u wrong", zoneSize); - return rc; - } - } - if (hdr->pages) { - int pageBufSz = hdr->pageCnt * sizeof(Pgno); - rc = WriteToHdrPage(pPager, hdr->pages, pageBufSz, META_PAGE_NO_OFFSET); - if (rc != SQLITE_OK) { - sqlite3_log(rc, "update meta header write pagebuf %u wrong", pageBufSz); - } - } - if (rc == SQLITE_OK) { - u64 size = CaculateMetaDwrWriteOffset((int)pPager->pageSize, hdr->pageCnt, 0); - rc = sqlite3OsTruncate(pPager->metaFd, size); - if (rc != SQLITE_OK) { - sqlite3_log(rc, "update meta header truncate filesz %lu wrong", size); - } - i64 timeMs = 0; - sqlite3OsCurrentTimeInt64(pPager->pVfs, &timeMs); - if ((timeMs - hdr->lastSyncTime) > META_FILE_SYNC_TIMEOUT_MS || - hdr->needSync >= META_FILE_UPDATE_TIMES_PER_SYNC) { - rc = sqlite3OsSync(pPager->metaFd, SQLITE_SYNC_NORMAL); - if (rc != SQLITE_OK) { - sqlite3_log(rc, "update meta header sync filesz %lu wrong", size); - } - hdr->lastSyncTime = timeMs; - hdr->needSync = 0; - } else { - hdr->needSync++; - } - } - return rc; -} - -static int MetaDwrFindPageIdx(MetaDwrHdr *hdr, u32 pgno, u32 *idx) { - for (u32 i = 0; i < hdr->pageCnt && i < META_DWR_MAX_PAGES; i++) { - if (pgno == hdr->pages[i]) { - *idx = i; - return 1; - } - } - return 0; -} - -static int MetaDwrWriteOnePage(Btree *pBt, PgHdr *pPage, MetaDwrHdr *hdr, u8 curZones, u32 idx) { - int rc = SQLITE_OK; - u8 pageExpand = 0; - if (hdr->pageCnt <= idx) { - rc = ExpandMetaPageBuf(hdr, idx + 1, 1); - if (rc != SQLITE_OK) { - return rc; - } - pageExpand = 1; - } - Pager *pPager = pBt->pBt->pPager; - // asume zone 0 or 1 - u8 zone = 1 - curZones; - int pageSz = sqlite3BtreeGetPageSize(pBt); - u64 ofs = CaculateMetaDwrWriteOffset(pageSz, idx, zone); - void *pData; -#if defined(SQLITE_HAS_CODEC) - if ((pData = sqlite3PagerCodec(pPage)) == 0) - return SQLITE_NOMEM; -#else - pData = pPage->pData; -#endif - rc = sqlite3OsWrite(pPager->metaFd, pData, pageSz, ofs); - if (rc != SQLITE_OK) { - return rc; - } - hdr->zones[idx] = zone; - hdr->pages[idx] = pPage->pgno; - if (pageExpand) { - hdr->pageCnt++; - } - return SQLITE_OK; -} - -static int MetaDwrRestoreAllPages(Btree *pBt, const ScanPages *metaPages, MetaDwrHdr *hdr) { - u32 i = 0; - PgHdr *p = NULL; - int rc = SQLITE_OK; - for (i = 0; i < metaPages->pageCnt && i < META_DWR_MAX_PAGES; i++) { - Pgno pgno = metaPages->pages[i]; - if (pgno > btreePagecount(pBt->pBt)) { - sqlite3_log(SQLITE_WARNING_DUMP, "pageno %d overlimit", pgno); - return SQLITE_CORRUPT_BKPT; - } - rc = sqlite3PagerGet(pBt->pBt->pPager, pgno, &p, 0); - if (rc) { - return rc; - } - rc = MetaDwrWriteOnePage(pBt, p, hdr, 1, i); - sqlite3PagerUnref(p); - if (rc) { - return rc; - } - } - hdr->pageCnt = metaPages->pageCnt; - MetaDwrUpdateHeaderDbInfo(pBt->pBt); - return rc; -} - -static inline const char *GetMetaFilePath(Pager *pPager) -{ - return pPager->metaFd == NULL ? NULL : ((const char *)pPager->metaFd + ROUND8(pPager->pVfs->szOsFile)); -} - -static int MetaDwrCheckPerm(sqlite3_vfs *pVfs, u8 openCreate, char *metaPath) { - int exists = 0; - int rc = sqlite3OsAccess(pVfs, metaPath, SQLITE_ACCESS_EXISTS, &exists); - if (rc != SQLITE_OK) { - return rc; - } - if (!exists && !openCreate) { - return SQLITE_PERM; - } -#ifdef HARMONY_OS - // check if the path have enough permission - rc = osAccess(metaPath, W_OK|R_OK); - if (rc == 0 || errno == ENOENT) { - return SQLITE_OK; - } - rc = SQLITE_PERM; - if (openCreate) { - sqlite3_log(SQLITE_WARNING_DUMP, "Meta double write disabled, sysno %d", errno); - } -#endif - return rc; -} - -static int MetaDwrOpenFile(Pager *pPager, u8 openCreate) { - if (pPager->metaFd || pPager->zFilename == NULL) { - return SQLITE_OK; - } - sqlite3BeginBenignMalloc(); - sqlite3_vfs *pVfs = pPager->pVfs; - int size = strlen(pPager->zFilename) + sizeof("-dwr"); - int szOsFile = ROUND8(pVfs->szOsFile); - sqlite3_file *metaFd = (sqlite3_file *)sqlite3MallocZero(szOsFile + size); - char *metaPath = (char *)metaFd + szOsFile; - if (metaFd == NULL) { - sqlite3EndBenignMalloc(); - sqlite3_log(SQLITE_NOMEM_BKPT, "sqlite alloc memsize %d go wrong", szOsFile + size); - return SQLITE_NOMEM_BKPT; - } - sqlite3_snprintf(size, metaPath, "%s-dwr", pPager->zFilename); - int rc = MetaDwrCheckPerm(pVfs, openCreate, metaPath); - if (rc != SQLITE_OK) { - goto INIT_META_OUT; - } - u32 flags = (SQLITE_OPEN_READWRITE | SQLITE_OPEN_SUPER_JOURNAL); - if (openCreate) { - flags |= SQLITE_OPEN_CREATE; - } - rc = sqlite3OsOpen(pVfs, metaPath, metaFd, (int)flags, 0); - if (rc != SQLITE_OK) { - goto INIT_META_OUT; - } -#if SQLITE_OS_UNIX - if (pPager->metaMapPage == NULL) { - sqlite3_int64 sz = META_DWR_HEADER_PAGE_SIZE; - sqlite3OsFileControlHint(metaFd, SQLITE_FCNTL_CHUNK_SIZE, &sz); - sqlite3OsFileControlHint(metaFd, SQLITE_FCNTL_SIZE_HINT, &sz); - void *page = osMmap(0, META_DWR_HEADER_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, - ((unixFile *)metaFd)->h, 0); - if (page != MAP_FAILED) { - pPager->metaMapPage = page; - } - } -#endif - pPager->metaFd = metaFd; -INIT_META_OUT: - sqlite3EndBenignMalloc(); - if (rc != SQLITE_OK && metaFd != NULL) { - sqlite3_free(metaFd); - } - return rc; -} - -void MetaDwrCheckVacuum(BtShared *pBt) { - if (!pBt || !pBt->pPager->metaFd) { - return; - } - if (pBt->nPage < pBt->maxMetaPage) { - pBt->pPager->metaChanged = META_SCHEMA_CHANGED; - } -} - -static inline u8 LocalMetaHdrValid(Pager *pPager) { - return pPager->metaMapPage != NULL && memcmp(pPager->metaMapPage, pPager->metaHdr, - META_VERIFIED_HDR_LEN) == 0; -} - -static int MetaDwrLoadHdr(Pager *pPager) { - if (!pPager->metaHdr) { - pPager->metaHdr = AllocInitMetaHeaderDwr(pPager); - if (pPager->metaHdr == NULL) { - return SQLITE_NOMEM_BKPT; - } - } - if (LocalMetaHdrValid(pPager)) { - return SQLITE_OK; - } - return MetaDwrReadHeader(pPager, pPager->metaHdr); -} - -static int MetaDwrLoadAndCheckMetaFile(BtShared *pBt, u8 reportErr) { - int rc = MetaDwrLoadHdr(pBt->pPager); - if (rc != SQLITE_OK) { - return rc; - } - MetaDwrHdr *hdr = pBt->pPager->metaHdr; - if (hdr->pageCnt == 0) { - return reportErr ? SQLITE_IOERR_DATA : SQLITE_OK; - } - // 28 offset: dbSize, freelist pageNo, freelist pages count, schema cookie - u8 *dbHdrInfo = &pBt->pPage1->aData[28]; - if (hdr->dbSize != pBt->pPager->dbSize || hdr->dbSize != sqlite3Get4byte(dbHdrInfo) || - hdr->freeListPageNo != sqlite3Get4byte(dbHdrInfo + 4) || - hdr->freeListPageCnt != sqlite3Get4byte(dbHdrInfo + 8) || - hdr->schemaCookie != sqlite3Get4byte(dbHdrInfo + 12)) { - sqlite3_log(SQLITE_IOERR_DATA, "Meta dwr file expect %u-%u-%u-%u-%u but gotton %u-%u-%u-%u-%u", - pBt->pPager->dbSize, hdr->dbSize, sqlite3Get4byte(dbHdrInfo), sqlite3Get4byte(dbHdrInfo + 4), - sqlite3Get4byte(dbHdrInfo + 8), sqlite3Get4byte(dbHdrInfo + 12), hdr->dbSize, hdr->freeListPageNo, - hdr->freeListPageCnt, hdr->schemaCookie); - // reinit - InitMetaHeader(hdr); - if (reportErr) { - return SQLITE_IOERR_DATA; - } - } - return SQLITE_OK; -} - -static int MetaDwrReadOnePage(Pager *pPager, MetaDwrHdr *hdr, int idx, u8 *pData) { - u64 ofs = CaculateMetaDwrWriteOffset(pPager->pageSize, idx, hdr->zones[idx]); - int rc = sqlite3OsRead(pPager->metaFd, pData, pPager->pageSize, ofs); - CODEC1(pPager, pData, hdr->pages[idx], 3, rc = SQLITE_NOMEM_BKPT); - return rc; -} - -static int MetaDwrRecoverHeadPage( - Pager *pPager, /* The pager open on the database file */ - Pgno pgno, /* Page number to fetch */ - DbPage **pDbPage, - int flag) { - if (pPager->metaFd == NULL) { - return pgno == 1 ? SQLITE_NOTADB : SQLITE_CORRUPT; - } - sqlite3_pcache_page *pCachePage = sqlite3PcacheFetch(pPager->pPCache, pgno, 3); - if (pCachePage == NULL) { - sqlite3_log(SQLITE_NOMEM_BKPT, "Get meta page wrong %d", pgno); - return SQLITE_NOMEM_BKPT; - } - DbPage *pPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pCachePage); - pPage->pPager = pPager; - assert(pCachePage != 0); - int rc = MetaDwrLoadHdr(pPager); - if (rc != SQLITE_OK) { - goto RELEASE_OUT; - } - MetaDwrHdr *hdr = pPager->metaHdr; - u8 walChecked = 0; -#ifndef SQLITE_OMIT_WAL - if (pagerUseWal(pPager)) { - WalIndexHdr *pWalHdr = &pPager->pWal->hdr; - if (pWalHdr->isInit && pWalHdr->mxFrame != 0) { - if (hdr->mxFrameInWal != pWalHdr->mxFrame || hdr->dbSize != pWalHdr->nPage) { - rc = SQLITE_NOTADB; - sqlite3_log(SQLITE_WARNING_DUMP, "Meta dwr wal hdr expect %u-%u but gotten %u-%u", - hdr->mxFrameInWal, hdr->dbSize, pWalHdr->mxFrame, pWalHdr->nPage); - goto RELEASE_OUT; - } else { - walChecked = 1; - } - } - } - if (walChecked == 0) { - i64 size = 0; - rc = sqlite3OsFileSize(pPager->fd, &size); - if (rc != SQLITE_OK) { - rc = SQLITE_NOTADB; - sqlite3_log(SQLITE_WARNING_DUMP, "Meta dwr get db file size go wrong"); - goto RELEASE_OUT; - } - i64 expectSz = (i64)hdr->dbSize * (i64)hdr->pageSz; - if (size != expectSz) { - rc = SQLITE_NOTADB; - sqlite3_log(SQLITE_WARNING_DUMP, "Meta dwr expect file size %lu but gotten size %llu", - expectSz, size); - goto RELEASE_OUT; - } - } -#endif - rc = SQLITE_NOTADB; - for (u32 i = 0; i < hdr->pageCnt; i++) { - if (hdr->pages[i] != pgno) { - continue; - } - rc = MetaDwrReadOnePage(pPager, hdr, i, sqlite3PagerGetData(pPage)); - if (rc == SQLITE_OK) { - *pDbPage = pPage; - if (pPage->pgno == 1) { - memcpy(&pPager->dbFileVers, &((u8 *)pPage->pData)[24], sizeof(pPager->dbFileVers)); - } - pager_set_pagehash(pPage); - } - break; - } -RELEASE_OUT: - if (rc != SQLITE_OK && pPage != NULL) { - sqlite3PcacheDrop(pPage); - } - return rc; -} - -static int MetaDwrRestoreChangedPages(Btree *pBt) { - Pager *pPager = pBt->pBt->pPager; - MetaDwrHdr *hdr = pPager->metaHdr; - u8 *zones = sqlite3MallocZero(hdr->pageBufSize * sizeof(u8)); - if (zones == NULL) { - sqlite3_log(SQLITE_NOMEM_BKPT, "Alloc zones buffer size %u go wrong", hdr->pageBufSize * sizeof(u8)); - return SQLITE_NOMEM_BKPT; - } - if (hdr->pageCnt > 0) { - memcpy(zones, hdr->zones, hdr->pageCnt * sizeof(u8)); - } - u32 idx = 0; - PgHdr *p = 0; - PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache); - int rc = SQLITE_OK; - for (p = pList; p; p = p->pDirty) { - if (MetaDwrFindPageIdx(hdr, p->pgno, &idx) == 0) { - continue; - } - rc = MetaDwrWriteOnePage(pBt, p, hdr, zones[idx], idx); - if (rc != SQLITE_OK) { - break; - } - } - if (rc == SQLITE_OK) { - MetaDwrUpdateHeaderDbInfo(pBt->pBt); - } - sqlite3_free(zones); - return rc; -} - -static int MetaDwrUpdateMetaPages(Btree *pBt) { - Pager *pPager = pBt->pBt->pPager; - if (!pPager || !pPager->metaFd || pPager->memDb || pPager->readOnly || pBt->pBt->pPage1 == NULL) { - return SQLITE_OK; - } - if (pPager->metaChanged == 0) { - if ((pBt->pBt->pPage1->pDbPage->flags & PGHDR_DIRTY) == 0) { - return SQLITE_OK; - } - pPager->metaChanged = META_HEADER_CHANGED; - } - sqlite3BeginBenignMalloc(); - int rc = MetaDwrLoadHdr(pPager); - if (rc != SQLITE_OK) { - goto UPDATE_OUT; - } - // only update header page - if (pPager->metaChanged == META_HEADER_CHANGED) { - rc = MetaDwrRestoreChangedPages(pBt); - goto UPDATE_OUT; - } - // update schema pages - ScanPages metaPages = {0}; - rc = ScanMetaPages(pBt, &metaPages); - if (rc != SQLITE_OK) { - goto UPDATE_OUT; - } - MetaDwrHdr *hdr = pPager->metaHdr; - // rewrite - if (hdr->pageCnt == 0 || hdr->pageCnt != metaPages.pageCnt || pBt->pBt->nPage > pBt->pBt->maxMetaPage || - memcmp(hdr->pages, metaPages.pages, hdr->pageCnt * sizeof(Pgno))) { - // if page numbers unorderred, restore all pages - rc = MetaDwrRestoreAllPages(pBt, &metaPages, hdr); - } else { - rc = MetaDwrRestoreChangedPages(pBt); - } - if (rc == SQLITE_OK) { - pBt->pBt->maxMetaPage = metaPages.maxPageNo; - } - ReleaseMetaPages(&metaPages); -UPDATE_OUT: - sqlite3EndBenignMalloc(); - return rc; -} - -static int MetaDwrRecoverSinglePage(Btree *pBt, int pgno, u8 *pData) { - if (pgno < 1 || pBt == NULL) { - return SQLITE_CORRUPT_BKPT; - } - Pager *pPager = sqlite3BtreePager(pBt); - DbPage *pDbPage = NULL; - int rc = sqlite3PagerGet(pPager, pgno, &pDbPage, 0); - if (rc) { - return rc; - } - if ((rc = sqlite3PagerWrite(pDbPage)) == SQLITE_OK) { - memcpy(sqlite3PagerGetData(pDbPage), pData, pPager->pageSize); - } else { - sqlite3_log(rc, "Dwr recoverwrite meta page %d failed", pgno); - } - sqlite3PagerUnref(pDbPage); - return rc; -} - -static int MetaDwrCheckMeta(Btree *pBt) { - int nErr = 0; - Pgno aRoot[2] = {0, 1}; // quick check and only check root btree - char *errStr = sqlite3BtreeIntegrityCheck(pBt->db, pBt, &aRoot[0], 2, SQLITE_INTEGRITY_CHECK_ERROR_MAX, - &nErr); - if (nErr == 0) { - assert(errStr == 0); - return SQLITE_OK; - } - if (errStr == 0) { - sqlite3_log(SQLITE_NOMEM, "Meta integrity check no mem"); - return SQLITE_NOMEM; - } - sqlite3_log(SQLITE_WARNING_DUMP, "Meta integrity check %s", errStr); - sqlite3DbFree(pBt->db, errStr); - return SQLITE_CORRUPT; -} - -static int MetaDwrBeginTrans(Btree *pBt, int wrflag) { - pBt->pBt->btsFlags &= ~BTS_READ_ONLY; - Pager *pPager = pBt->pBt->pPager; - void *xGetMethod = pPager->xGet; - pPager->xGetMethod = MetaDwrRecoverHeadPage; - pPager->xGet = MetaDwrRecoverHeadPage; - int rc = sqlite3BtreeBeginTrans(pBt, wrflag, 0); - pPager->xGet = xGetMethod; - pPager->xGetMethod = 0; - if (rc == SQLITE_OK) { - sqlite3PagerWrite(pBt->pBt->pPage1->pDbPage); - sqlite3_log(rc, "sqlite fix meta header"); - } - return rc; -} - -static int MetaDwrRecoverAndBeginTran(Btree *pBt, int wrflag, int *pSchemaVersion) -{ - Pager *pPager = pBt->pBt->pPager; - assert(sqlite3_mutex_held(pBt->pBt->mutex)); - if (!pPager->metaFd || pBt->pBt->metaRecoverStatus || pPager->readOnly || pPager->memDb) { - return SQLITE_NOTADB; - } - int rc = MetaDwrLoadHdr(pPager); - if (rc != SQLITE_OK) { - sqlite3_log(rc, "MetaDwr load header failed"); - return rc; - } - pBt->pBt->metaRecoverStatus = META_IN_RECOVERY; - rc = MetaDwrBeginTrans(pBt, 2); - if (rc != SQLITE_OK) { - return rc; - } - void *pData = NULL; - pPager->metaChanged = META_HEADER_CHANGED; - MetaDwrHdr *hdr = pPager->metaHdr; - sqlite3_log(SQLITE_WARNING_DUMP, "sqlite meta recover %u frames", hdr->pageCnt); - int szPage = sqlite3BtreeGetPageSize(pBt); - pData = sqlite3Malloc(szPage); - if (pData == NULL) { - rc = SQLITE_NOMEM; - sqlite3_log(rc, "Dwr malloc mem size %d failed", szPage); - goto DWR_RECOVER_OUT; - } - for (u32 i = 0; i < hdr->pageCnt; i++) { - rc = MetaDwrReadOnePage(pPager, hdr, i, pData); - if (rc != SQLITE_OK) { - sqlite3_log(rc, "Dwr read %d meta page failed ", i); - break; - } - rc = MetaDwrRecoverSinglePage(pBt, hdr->pages[i], pData); - if (rc != SQLITE_OK) { - sqlite3_log(rc, "Dwr recover %d meta page failed ", i); - break; - } - } -DWR_RECOVER_OUT: - /* Close the transaction, if one was opened. */ - if (rc == SQLITE_OK) { - sqlite3BtreeCommit(pBt); - } else { - (void)sqlite3BtreeRollback(pBt, SQLITE_ABORT_ROLLBACK, 0); - } - if (rc == SQLITE_OK) { - rc = sqlite3BtreeBeginTrans(pBt, wrflag, pSchemaVersion); - } - if (rc == SQLITE_OK) { - pBt->pBt->metaRecoverStatus = META_RECOVER_SUCCESS; - } - if (pData) { - sqlite3_free(pData); - } - return rc; -} - -static int Sqlite3MetaDwrCheckRestore(Btree *pBt) { - Pager *pPager = pBt->pBt->pPager; - int rc = MetaDwrOpenFile(pPager, 1); - if (rc != SQLITE_OK) { - return rc; - } - ScanPages metaPages = {0}; - rc = ScanMetaPages(pBt, &metaPages); - if (rc != SQLITE_OK || metaPages.pageCnt == 0) { - goto CHK_RESTORE_OUT; - } - rc = MetaDwrLoadAndCheckMetaFile(pBt->pBt, 0); - if (rc != SQLITE_OK) { - goto CHK_RESTORE_OUT; - } - MetaDwrHdr *hdr = pPager->metaHdr; - if (hdr->pageCnt == 0 || hdr->pageCnt != metaPages.pageCnt || - memcmp(hdr->pages, metaPages.pages, hdr->pageCnt * sizeof(Pgno))) { - sqlite3_log(SQLITE_WARNING_DUMP, "sqlite meta restore all"); - rc = MetaDwrRestoreAllPages(pBt, &metaPages, hdr); - if (rc == SQLITE_OK) { - pPager->metaChanged = META_SCHEMA_CHANGED; - rc = MetaDwrWriteHeader(pPager, hdr); - pPager->metaChanged = 0; - } - } - if (rc == SQLITE_OK) { - pBt->pBt->maxMetaPage = metaPages.maxPageNo; - } -CHK_RESTORE_OUT: - ReleaseMetaPages(&metaPages); - return rc; -} - -static inline u8 IsConnectionValidForCheck(Pager *pPager) -{ -#if SQLITE_OS_UNIX - unixFile *fd = (unixFile *)pPager->fd; - // unix and only one connection exist - if (fd == NULL || fd->pInode == NULL || pPager->pVfs == NULL || - sqlite3_stricmp(pPager->pVfs->zName, "unix") != 0 || fd->pInode->nRef != 1) { - return 0; - } - return 1; -#else - return 0; -#endif -} - -static int MetaDwrOpenAndCheck(Btree *pBt) -{ - Pager *pPager = pBt->pBt->pPager; - if (pPager->memDb || pPager->readOnly || !IsConnectionValidForCheck(pPager)) { - return SQLITE_OK; - } -#ifdef SQLITE_HAS_CODEC - // not support codec right now - if (pPager->xCodec) { - return SQLITE_OK; - } -#endif - sqlite3BtreeEnter(pBt); - int rc = SQLITE_OK; - int openedTransaction = 0; - int tnxState = sqlite3BtreeTxnState(pBt); - if (tnxState == SQLITE_TXN_NONE) { - rc = sqlite3BtreeBeginTrans(pBt, 0, 0); - if (rc != SQLITE_OK) { - goto DWR_OPEN_OUT; - } - openedTransaction = 1; - } - rc = MetaDwrCheckMeta(pBt); - if (rc == SQLITE_CORRUPT || rc == SQLITE_NOTADB) { - // keep txn status after recover - rc = MetaDwrRecoverAndBeginTran(pBt, tnxState == SQLITE_TXN_WRITE ? 1 : 0, 0); - goto DWR_OPEN_OUT; - } - rc = Sqlite3MetaDwrCheckRestore(pBt); -DWR_OPEN_OUT: - if (rc == SQLITE_OK && pBt->pBt->metaRecoverStatus == META_RECOVER_SUCCESS) { - rc = MetaDwrCheckMeta(pBt); - if (rc == SQLITE_OK) { - rc = SQLITE_META_RECOVERED; - } - } - /* Close the transaction, if one was opened. */ - if (openedTransaction) { - sqlite3BtreeCommit(pBt); - } - sqlite3BtreeLeave(pBt); - return rc; -} - -static void MetaDwrDisable(Btree *pBt) -{ - Pager *pPager = pBt->pBt->pPager; - if (pPager->metaFd == NULL || pPager->memDb || pPager->readOnly || !IsConnectionValidForCheck(pPager)) { - return; - } -#ifdef SQLITE_HAS_CODEC - // not support codec right now - if (pPager->xCodec) { - return; - } -#endif - sqlite3BtreeEnter(pBt); - MetaDwrCloseFile(pPager); - MetaDwrReleaseHdr(pPager->metaHdr); - pPager->metaHdr = NULL; - const char *metaPath = GetMetaFilePath(pPager); - if (metaPath != NULL) { - (void)osUnlink(metaPath); - } - if (pPager->metaFd) { - sqlite3_free(pPager->metaFd); - pPager->metaFd = NULL; - } - sqlite3BtreeLeave(pBt); -} -#endif -#if SQLITE_OS_UNIX -#include -#include -static inline int OsGetTid(void) -{ -#if defined(__linux__) - return (int)syscall(__NR_gettid); -#elif defined(__APPLE__) - return (int)syscall(SYS_thread_selfid); -#else - return 0; -#endif -} - -static void ResetLockStatus(void) -{ - (void)memset(&g_lockStatus, 0, sizeof(g_lockStatus)); - g_lockStatus.curTid = OsGetTid(); -} -/* -** Record lock info, correspond wal aLock buf, 1 aLock: 1 -*/ -static inline void TryRecordTid(int *tidBuf, int ofs, int lockLen) -{ - int lockOfs = ofs + lockLen; - for (int i = ofs; i < lockOfs; i++) { - if (tidBuf[i] == 0) { - tidBuf[i] = g_lockStatus.curTid; - } - } -} -/* -** Clear locks info. -*/ -static inline void TryClearTid(int *tidBuf, int ofs, int lockLen) -{ - int lockOfs = ofs + lockLen; - for (int i = ofs; i < lockOfs; i++) { - if (tidBuf[i] == g_lockStatus.curTid) { - tidBuf[i] = 0; - } - } -} - -static inline void MarkLockBusy(u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess) -{ - g_lockStatus.busyLockIdx = lockIdx; - g_lockStatus.busyLockType = lockType; - g_lockStatus.lockByProcess = lockByProcess; - g_lockStatus.lockLen = lockLen; -} - -static void MarkLockStatus(u32 lockIdx, u32 lockLen, u8 lockType) -{ - if (lockLen == 0 || (lockIdx + lockLen) > MAX_LOCK_NUM) { - sqlite3_log(SQLITE_ERROR, "Unexpect lock index %u lockLen %d!", lockIdx, lockLen); - return; - } - // only busy error code need record - if (g_lockStatus.lockLen != 0 && lockIdx == g_lockStatus.busyLockIdx) { - g_lockStatus.busyLockIdx = 0; - g_lockStatus.busyLockType = NO_LOCK; - g_lockStatus.lockLen = 0; - } - if (lockLen == 1) { - g_lockStatus.lockStatus[lockIdx] = lockType; - } else { - size_t len = sizeof(u8) * lockLen; - (void)memset(&g_lockStatus.lockStatus[lockIdx], lockType, len); - } -} - -static inline void MarkLockStatusByRc(int rc, u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess) -{ - if (rc == SQLITE_OK) { - MarkLockStatus(lockIdx, lockLen, lockType); - } else if (rc == SQLITE_BUSY) { - MarkLockBusy(lockIdx, lockLen, lockType, lockByProcess); - } -} - -static inline const char *IdxToLockName(u32 idx) -{ - const char *lockName[MAX_LOCK_NUM] = {"write", "ckpt", "recover", "read0", - "read1", "read2", "read3", "read4", "wal_dms", "trxLock"}; - return (idx < MAX_LOCK_NUM) ? lockName[idx] : "errLock"; -} - -static void DumpHandleLock(char *dumpBuf, int dumpBufLen) -{ - char *tmp = dumpBuf; - u8 *lockStatus = g_lockStatus.lockStatus; - int availLen = dumpBufLen - 1; - dumpBuf[availLen] = '\0'; - for (int i = 0; i < MAX_LOCK_NUM && availLen > DUMP_MAX_STR_LEN; i++) { - if (lockStatus[i] != NO_LOCK) { - tmp[0] = '\0'; - sqlite3_snprintf(availLen, tmp, "<%s, %d>", IdxToLockName((u32)i), lockStatus[i]); - int len = strlen(tmp); - tmp += len; - availLen -= len; - } - } - sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]BusyLine:%d, idx:%d, type:%d, fileLock:%d, len:%d, handleLocks:%s", - g_lockStatus.busyLine, g_lockStatus.busyLockIdx, g_lockStatus.busyLockType, g_lockStatus.lockByProcess, - g_lockStatus.lockLen, tmp != dumpBuf ? dumpBuf : "none"); -} - -static inline const char *FlockToName(int l_type) -{ - return l_type == F_RDLCK ? "F_RDLCK" : - l_type == F_WRLCK ? "F_WRLCK" : - l_type == F_UNLCK ? "F_UNLCK" : "F_UNKNOWN"; -} - -static int DumpProcessLocks(int fd, struct flock *lock, const char *lockName, char *dumpBuf, int bufLen) -{ - dumpBuf[0] = '\0'; - if (osFcntl(fd, F_GETLK, lock) != SQLITE_OK) { - sqlite3_log(SQLITE_ERROR, "[SQLite]Get wal file lock ofs %u failed, errno: %d", lock->l_start, errno); - return 0; - } - if (lock->l_type != F_UNLCK) { - sqlite3_snprintf(bufLen, dumpBuf, "<%s, pid:%u, %s>", lockName, lock->l_pid, FlockToName(lock->l_type)); - return strlen(dumpBuf); - } - return 0; -} - -static void DumpTrxProcessLocks(unixFile *file, char *dumpBuf, int dumpBufLen) -{ - unixInodeInfo *inode = file->pInode; - if (inode == NULL) { - sqlite3_log(SQLITE_ERROR, "[SQLite]Inode is null!"); - return; - } - sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]acqLock:%d, dbRef:%d, lockCnt:%d, curLock:%d, processLock:%d", - file->eFileLock, inode->nRef, inode->nLock, inode->eFileLock, inode->bProcessLock); - const char *lockName[DB_LOCK_NUM] = {"pending", "reserved", "shared_first"}; - char *tmp = dumpBuf; - int availLen = dumpBufLen - 1; - dumpBuf[availLen] = '\0'; - for (int i = 0; i < DB_LOCK_NUM && availLen > DUMP_MAX_STR_LEN; i++) { - off_t ofs = i + PENDING_BYTE; - off_t lockLen = (ofs == SHARED_FIRST) ? SHARED_SIZE : 1; - struct flock lock = {.l_type = F_WRLCK, .l_start = ofs, .l_len = lockLen, .l_whence = SEEK_SET}; - int lockBufLen = DumpProcessLocks(file->h, &lock, lockName[i], tmp, availLen); - tmp += lockBufLen; - availLen -= lockBufLen; - } - if (tmp != dumpBuf) { - sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]Trx locks: %s", dumpBuf); - } -} - -static void DumpWalLocks(unixFile *file, u8 walEnabled, char *dumpBuf, int dumpBufLen) -{ - if (file->pShm == NULL || file->pShm->pShmNode == NULL) { - sqlite3_log(SQLITE_ERROR, "[SQLite]Wal mode disabled! pShm or pShmNode is NULL"); - return; - } - if (!walEnabled) { - sqlite3_log(SQLITE_ERROR, "[SQLite] walEnabled false"); - } - unixShmNode *pShmNode = file->pShm->pShmNode; - char *tmp = dumpBuf; - int availLen = dumpBufLen - 1; - dumpBuf[availLen] = '\0'; - for (int i = 0; i < WAL_LOCK_NUM && availLen > DUMP_MAX_STR_LEN; i++) { - if (i < SQLITE_SHM_NLOCK && pShmNode->aLock[i]) { - tmp[0] = '\0'; - sqlite3_snprintf(availLen, tmp, "<%s, %d, tid:%d>", IdxToLockName((u32)i), pShmNode->aLock[i], - pShmNode->aLockTid[i]); - int strLen = strlen(tmp); - tmp += strLen; - availLen -= strLen; - } - off_t ofs = i + WALINDEX_LOCK_OFFSET; - struct flock lock = {.l_type = F_WRLCK, .l_start = ofs, .l_len = 1, .l_whence = SEEK_SET}; - int bufLen = DumpProcessLocks(pShmNode->hShm, &lock, IdxToLockName((u32)i), tmp, availLen); - tmp += bufLen; - availLen -= bufLen; - } - if (tmp != dumpBuf) { - sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]Wal locks: %s", dumpBuf); - } -} - -static void DumpLocksInfo(unixFile *file, int walEnabled) -{ - char *dumpBuf = sqlite3Malloc(DUMP_BUF_MAX_LEN); - if (dumpBuf == NULL) { - sqlite3_log(SQLITE_ERROR, "[SQLite]Can't alloc bufferSz %d for dump!", DUMP_BUF_MAX_LEN); - return; - } - DumpHandleLock(dumpBuf, DUMP_BUF_MAX_LEN); - DumpTrxProcessLocks(file, dumpBuf, DUMP_BUF_MAX_LEN); - DumpWalLocks(file, walEnabled, dumpBuf, DUMP_BUF_MAX_LEN); - sqlite3_free(dumpBuf); -} - -#ifndef SQLITE_OMIT_WAL -static void DumpLocksByWal(Wal *pWal) -{ - if (pWal == NULL) { - sqlite3_log(SQLITE_ERROR, "Wal ptr is NULL!"); - return; - } - if (pWal->pVfs == NULL || sqlite3_stricmp(pWal->pVfs->zName, "unix") != 0) { - return; - } - DumpLocksInfo((unixFile *)(pWal->pDbFd), 1); -} -#endif /* #ifndef SQLITE_OMIT_WAL */ - -static void DumpLocksByPager(Pager *pPager) -{ - if (pPager == NULL) { - sqlite3_log(SQLITE_ERROR, "Pager ptr is NULL!"); - return; - } - if (pPager->pVfs == NULL || sqlite3_stricmp(pPager->pVfs->zName, "unix") != 0) { - return; - } -#ifndef SQLITE_OMIT_WAL - DumpLocksInfo((unixFile *)(pPager->fd), pPager->pWal != NULL); -#else /* #ifndef SQLITE_OMIT_WAL */ - DumpLocksInfo((unixFile *)(pPager->fd), 0); -#endif /* #ifndef SQLITE_OMIT_WAL */ -} -#endif /* SQLITE_OS_UNIX */ - -#ifndef SQLITE_OMIT_WAL -static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime) { - sqlite3_int64 endTime; - sqlite3OsCurrentTimeInt64(db->pVfs, &endTime); - sqlite3_int64 timeUse = endTime - startTime; - /* Only when timeUse > 1500ms or wal size > 50MB, default pageSize 4K, 50*1024/4 = 12800 */ - if (timeUse > 1500 || pWal->hdr.mxFrame > 12800) { - sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]Wal ckpt use time: %lld(ms), wal frame: %u", - timeUse, pWal->hdr.mxFrame); - } -} -#endif -// hw export the symbols -#ifdef SQLITE_EXPORT_SYMBOLS -#ifndef SQLITE_CKSUMVFS_STATIC -int sqlite3_register_cksumvfs(const char *NotUsed){ - return SQLITE_MISUSE; -} -int sqlite3_unregister_cksumvfs(void){ - return SQLITE_MISUSE; -} - -struct sqlite3_api_routines_cksumvfs { - int (*register_cksumvfs)(const char *); - int (*unregister_cksumvfs)(); -}; -typedef struct sqlite3_api_routines_cksumvfs sqlite3_api_routines_cksumvfs; -static const sqlite3_api_routines_cksumvfs sqlite3CksumvfsApis = { - sqlite3_register_cksumvfs, - sqlite3_unregister_cksumvfs -}; - -EXPORT_SYMBOLS const sqlite3_api_routines_cksumvfs *sqlite3_export_cksumvfs_symbols = &sqlite3CksumvfsApis; -#endif - -struct sqlite3_api_routines_hw { - int (*initialize)(); - int (*config)(int,...); - int (*key)(sqlite3*,const void*,int); - int (*key_v2)(sqlite3*,const char*,const void*,int); - int (*rekey)(sqlite3*,const void*,int); - int (*rekey_v2)(sqlite3*,const char*,const void*,int); -}; - -typedef struct sqlite3_api_routines_hw sqlite3_api_routines_hw; -static const sqlite3_api_routines_hw sqlite3HwApis = { - sqlite3_initialize, - sqlite3_config, -#ifdef SQLITE_HAS_CODEC - sqlite3_key, - sqlite3_key_v2, - sqlite3_rekey, - sqlite3_rekey_v2 -#else - 0, - 0, - 0, - 0 -#endif /* SQLITE_HAS_CODEC */ -}; - -EXPORT_SYMBOLS const sqlite3_api_routines *sqlite3_export_symbols = &sqlite3Apis; -EXPORT_SYMBOLS const sqlite3_api_routines_hw *sqlite3_export_hw_symbols = &sqlite3HwApis; -/************** End hw export the symbols *****************************************/ -#endif /* SQLITE_EXPORT_SYMBOLS */ diff --git a/src/sqlite3icu.c b/src/sqlite3icu.c deleted file mode 100644 index 6a581fc..0000000 --- a/src/sqlite3icu.c +++ /dev/null @@ -1,892 +0,0 @@ -/****************************************************************************** -** This file is an amalgamation of many separate C source files from SQLite -** version 3.40.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 -** of 5% or more are commonly seen when SQLite is compiled as a single -** translation unit. -** -** This file is all you need to compile SQLite. To use SQLite in other -** programs, you need this file and the "sqlite3.h" header file that defines -** the programming interface to the SQLite library. (If you do not have -** the "sqlite3.h" header file at hand, you will find a copy embedded within -** the text of this file. Search for "Begin file sqlite3.h" to find the start -** of the embedded sqlite3.h header file.) Additional code files may be needed -** if you want a wrapper to interface SQLite with your choice of programming -** language. The code for the "sqlite3" command-line shell is also in a -** separate file. This file contains only code for the core SQLite library. -*/ -/* -** 2019.09.02-Complete codec logic for encryption and decryption. -** Huawei Technologies Co, Ltd. -*/ -/************** Begin file icu.c *********************************************/ -/* -** 2007 May 6 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $ -** -** This file implements an integration between the ICU library -** ("International Components for Unicode", an open-source library -** for handling unicode data) and SQLite. The integration uses -** ICU to provide the following to SQLite: -** -** * An implementation of the SQL regexp() function (and hence REGEXP -** operator) using the ICU uregex_XX() APIs. -** -** * Implementations of the SQL scalar upper() and lower() functions -** for case mapping. -** -** * Integration of ICU and SQLite collation sequences. -** -** * An implementation of the LIKE operator that uses ICU to -** provide case-independent matching. -*/ -#include -#include -#include -#include -#include - -#include "sqlite3icu.h" -#include "sqlite3.h" - -#ifdef HARMONY_OS -#include "common/unicode/putil.h" -#endif - -#if !defined(SQLITE_CORE) \ - || defined(SQLITE_ENABLE_ICU) \ - || defined(SQLITE_ENABLE_ICU_COLLATIONS) - -/* Include ICU headers */ -#include -#include -#include -#include - -#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) - /* This case when the file really is being compiled as a loadable - ** extension */ -# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; -# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; -# define SQLITE_EXTENSION_INIT3 \ - extern const sqlite3_api_routines *sqlite3_api; -#else - /* 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 */ -# define SQLITE_EXTENSION_INIT3 /*no-op*/ -#endif - -/* #include */ - -#ifndef SQLITE_CORE -/* #include "sqlite3ext.h" */ - SQLITE_EXTENSION_INIT1 -#else -/* #include "sqlite3.h" */ -#endif - -// hw export the symbols -#ifdef SQLITE_EXPORT_SYMBOLS -#if defined(__GNUC__) -# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) -#elif defined(_MSC_VER) -# define EXPORT_SYMBOLS __declspec(dllexport) -#else -# define EXPORT_SYMBOLS -#endif -#endif - -EXPORT_SYMBOLS SQLITE_API int sqlite3IcuInit(sqlite3 *db); -#ifdef SQLITE_ENABLE_ICU -EXPORT_SYMBOLS SQLITE_API void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); -#endif -/* -** This function is called when an ICU function called from within -** the implementation of an SQL scalar function returns an error. -** -** The scalar function context passed as the first argument is -** loaded with an error message based on the following two args. -*/ -static void icuFunctionError( - sqlite3_context *pCtx, /* SQLite scalar function context */ - const char *zName, /* Name of ICU function that failed */ - UErrorCode e /* Error code returned by ICU function */ -){ - char zBuf[128]; - sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e)); - zBuf[127] = '\0'; - sqlite3_result_error(pCtx, zBuf, -1); -} - -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) - -/* -** Maximum length (in bytes) of the pattern in a LIKE or GLOB -** operator. -*/ -#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH -# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000 -#endif - -/* -** Version of sqlite3_free() that is always a function, never a macro. -*/ -static void xFree(void *p){ - sqlite3_free(p); -} - -/* -** This lookup table is used to help decode the first byte of -** a multi-byte UTF8 character. It is copied here from SQLite source -** code file utf8.c. -*/ -static const unsigned char icuUtf8Trans1[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, -}; - -#define SQLITE_ICU_READ_UTF8(zIn, c) \ - c = *(zIn++); \ - if( c>=0xc0 ){ \ - c = icuUtf8Trans1[c-0xc0]; \ - while( (*zIn & 0xc0)==0x80 ){ \ - c = (c<<6) + (0x3f & *(zIn++)); \ - } \ - } - -#define SQLITE_ICU_SKIP_UTF8(zIn) \ - assert( *zIn ); \ - if( *(zIn++)>=0xc0 ){ \ - while( (*zIn & 0xc0)==0x80 ){zIn++;} \ - } - - -/* -** Compare two UTF-8 strings for equality where the first string is -** a "LIKE" expression. Return true (1) if they are the same and -** false (0) if they are different. -*/ -static int icuLikeCompare( - const uint8_t *zPattern, /* LIKE pattern */ - const uint8_t *zString, /* The UTF-8 string to compare against */ - const UChar32 uEsc /* The escape character */ -){ - static const uint32_t MATCH_ONE = (uint32_t)'_'; - static const uint32_t MATCH_ALL = (uint32_t)'%'; - - int prevEscape = 0; /* True if the previous character was uEsc */ - - while( 1 ){ - - /* Read (and consume) the next character from the input pattern. */ - uint32_t uPattern; - SQLITE_ICU_READ_UTF8(zPattern, uPattern); - if( uPattern==0 ) break; - - /* There are now 4 possibilities: - ** - ** 1. uPattern is an unescaped match-all character "%", - ** 2. uPattern is an unescaped match-one character "_", - ** 3. uPattern is an unescaped escape character, or - ** 4. uPattern is to be handled as an ordinary character - */ - if( uPattern==MATCH_ALL && !prevEscape && uPattern!=(uint32_t)uEsc ){ - /* Case 1. */ - uint8_t c; - - /* Skip any MATCH_ALL or MATCH_ONE characters that follow a - ** MATCH_ALL. For each MATCH_ONE, skip one character in the - ** test string. - */ - while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){ - if( c==MATCH_ONE ){ - if( *zString==0 ) return 0; - SQLITE_ICU_SKIP_UTF8(zString); - } - zPattern++; - } - - if( *zPattern==0 ) return 1; - - while( *zString ){ - if( icuLikeCompare(zPattern, zString, uEsc) ){ - return 1; - } - SQLITE_ICU_SKIP_UTF8(zString); - } - return 0; - - }else if( uPattern==MATCH_ONE && !prevEscape && uPattern!=(uint32_t)uEsc ){ - /* Case 2. */ - if( *zString==0 ) return 0; - SQLITE_ICU_SKIP_UTF8(zString); - - }else if( uPattern==(uint32_t)uEsc && !prevEscape ){ - /* Case 3. */ - prevEscape = 1; - - }else{ - /* Case 4. */ - uint32_t uString; - SQLITE_ICU_READ_UTF8(zString, uString); - uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT); - uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT); - if( uString!=uPattern ){ - return 0; - } - prevEscape = 0; - } - } - - return *zString==0; -} - -/* -** Implementation of the like() SQL function. This function implements -** the build-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 -** -** is implemented as like(B, A). If there is an escape character E, -** -** A LIKE B ESCAPE E -** -** is mapped to like(B, A, E). -*/ -static void icuLikeFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - const unsigned char *zA = sqlite3_value_text(argv[0]); - const unsigned char *zB = sqlite3_value_text(argv[1]); - UChar32 uEsc = 0; - - /* Limit the length of the LIKE or GLOB pattern to avoid problems - ** of deep recursion and N*N behavior in patternCompare(). - */ - if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){ - sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); - return; - } - - - if( argc==3 ){ - /* The escape character string must consist of a single UTF-8 character. - ** Otherwise, return an error. - */ - int nE= sqlite3_value_bytes(argv[2]); - const unsigned char *zE = sqlite3_value_text(argv[2]); - int i = 0; - if( zE==0 ) return; - U8_NEXT(zE, i, nE, uEsc); - if( i!=nE){ - sqlite3_result_error(context, - "ESCAPE expression must be a single character", -1); - return; - } - } - - if( zA && zB ){ - sqlite3_result_int(context, icuLikeCompare(zA, zB, uEsc)); - } -} - -/* -** Function to delete compiled regexp objects. Registered as -** a destructor function with sqlite3_set_auxdata(). -*/ -static void icuRegexpDelete(void *p){ - URegularExpression *pExpr = (URegularExpression *)p; - uregex_close(pExpr); -} - -/* -** Implementation of SQLite REGEXP operator. This scalar function takes -** two arguments. The first is a regular expression pattern to compile -** the second is a string to match against that pattern. If either -** argument is an SQL NULL, then NULL Is returned. Otherwise, the result -** is 1 if the string matches the pattern, or 0 otherwise. -** -** SQLite maps the regexp() function to the regexp() operator such -** that the following two are equivalent: -** -** zString REGEXP zPattern -** regexp(zPattern, zString) -** -** Uses the following ICU regexp APIs: -** -** uregex_open() -** uregex_matches() -** uregex_close() -*/ -static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ - UErrorCode status = U_ZERO_ERROR; - URegularExpression *pExpr; - UBool res; - const UChar *zString = sqlite3_value_text16(apArg[1]); - - (void)nArg; /* Unused parameter */ - - /* If the left hand side of the regexp operator is NULL, - ** then the result is also NULL. - */ - if( !zString ){ - return; - } - - pExpr = sqlite3_get_auxdata(p, 0); - if( !pExpr ){ - const UChar *zPattern = sqlite3_value_text16(apArg[0]); - if( !zPattern ){ - return; - } - pExpr = uregex_open(zPattern, -1, 0, 0, &status); - - if( U_SUCCESS(status) ){ - sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete); - pExpr = sqlite3_get_auxdata(p, 0); - } - if( !pExpr ){ - icuFunctionError(p, "uregex_open", status); - return; - } - } - - /* Configure the text that the regular expression operates on. */ - uregex_setText(pExpr, zString, -1, &status); - if( !U_SUCCESS(status) ){ - icuFunctionError(p, "uregex_setText", status); - return; - } - - /* Attempt the match */ - res = uregex_matches(pExpr, 0, &status); - if( !U_SUCCESS(status) ){ - icuFunctionError(p, "uregex_matches", status); - return; - } - - /* Set the text that the regular expression operates on to a NULL - ** pointer. This is not really necessary, but it is tidier than - ** leaving the regular expression object configured with an invalid - ** pointer after this function returns. - */ - uregex_setText(pExpr, 0, 0, &status); - - /* Return 1 or 0. */ - sqlite3_result_int(p, res ? 1 : 0); -} - -/* -** Implementations of scalar functions for case mapping - upper() and -** lower(). Function upper() converts its input to upper-case (ABC). -** Function lower() converts to lower-case (abc). -** -** ICU provides two types of case mapping, "general" case mapping and -** "language specific". Refer to ICU documentation for the differences -** between the two. -** -** To utilise "general" case mapping, the upper() or lower() scalar -** functions are invoked with one argument: -** -** upper('ABC') -> 'abc' -** lower('abc') -> 'ABC' -** -** To access ICU "language specific" case mapping, upper() or lower() -** should be invoked with two arguments. The second argument is the name -** of the locale to use. Passing an empty string ("") or SQL NULL value -** as the second argument is the same as invoking the 1 argument version -** of upper() or lower(). -** -** lower('I', 'en_us') -> 'i' -** lower('I', 'tr_tr') -> '\u131' (small dotless i) -** -** http://www.icu-project.org/userguide/posix.html#case_mappings -*/ -static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ - const UChar *zInput; /* Pointer to input string */ - UChar *zOutput = 0; /* Pointer to output buffer */ - int nInput; /* Size of utf-16 input string in bytes */ - int nOut; /* Size of output buffer in bytes */ - int cnt; - int bToUpper; /* True for toupper(), false for tolower() */ - UErrorCode status; - const char *zLocale = 0; - - assert(nArg==1 || nArg==2); - bToUpper = (sqlite3_user_data(p)!=0); - if( nArg==2 ){ - zLocale = (const char *)sqlite3_value_text(apArg[1]); - } - - zInput = sqlite3_value_text16(apArg[0]); - if( !zInput ){ - return; - } - nOut = nInput = sqlite3_value_bytes16(apArg[0]); - if( nOut==0 ){ - sqlite3_result_text16(p, "", 0, SQLITE_STATIC); - return; - } - - for(cnt=0; cnt<2; cnt++){ - UChar *zNew = sqlite3_realloc(zOutput, nOut); - if( zNew==0 ){ - sqlite3_free(zOutput); - sqlite3_result_error_nomem(p); - return; - } - zOutput = zNew; - status = U_ZERO_ERROR; - if( bToUpper ){ - nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); - }else{ - nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); - } - - if( U_SUCCESS(status) ){ - sqlite3_result_text16(p, zOutput, nOut, xFree); - }else if( status==U_BUFFER_OVERFLOW_ERROR ){ - assert( cnt==0 ); - continue; - }else{ - icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status); - } - return; - } - assert( 0 ); /* Unreachable */ -} - -#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ - -/* -** Collation sequence destructor function. The pCtx argument points to -** a UCollator structure previously allocated using ucol_open(). -*/ -static void icuCollationDel(void *pCtx){ - UCollator *p = (UCollator *)pCtx; - ucol_close(p); -} - -/* -** Collation sequence comparison function. The pCtx argument points to -** a UCollator structure previously allocated using ucol_open(). -*/ -static int icuCollationColl( - void *pCtx, - int nLeft, - const void *zLeft, - int nRight, - const void *zRight -){ - UCollationResult res; - UCollator *p = (UCollator *)pCtx; - res = ucol_strcoll(p, (UChar *)zLeft, nLeft/2, (UChar *)zRight, nRight/2); - switch( res ){ - case UCOL_LESS: return -1; - case UCOL_GREATER: return +1; - case UCOL_EQUAL: return 0; - } - assert(!"Unexpected return value from ucol_strcoll()"); - return 0; -} - -/* -** Implementation of the scalar function icu_load_collation(). -** -** This scalar function is used to add ICU collation based collation -** types to an SQLite database connection. It is intended to be called -** as follows: -** -** SELECT icu_load_collation(, ); -** -** Where is a string containing an ICU locale identifier (i.e. -** "en_AU", "tr_TR" etc.) and is the name of the -** collation sequence to create. -*/ -static void icuLoadCollation( - sqlite3_context *p, - int nArg, - sqlite3_value **apArg -){ - sqlite3 *db = (sqlite3 *)sqlite3_user_data(p); - UErrorCode status = U_ZERO_ERROR; - const char *zLocale; /* Locale identifier - (eg. "jp_JP") */ - const char *zName; /* SQL Collation sequence name (eg. "japanese") */ - UCollator *pUCollator; /* ICU library collation object */ - int rc; /* Return code from sqlite3_create_collation_x() */ - - assert(nArg==2); - (void)nArg; /* Unused parameter */ - zLocale = (const char *)sqlite3_value_text(apArg[0]); - zName = (const char *)sqlite3_value_text(apArg[1]); - - if( !zLocale || !zName ){ - return; - } - - pUCollator = ucol_open(zLocale, &status); - if( !U_SUCCESS(status) ){ - icuFunctionError(p, "ucol_open", status); - return; - } - assert(p); - - rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator, - icuCollationColl, icuCollationDel - ); - if( rc!=SQLITE_OK ){ - ucol_close(pUCollator); - sqlite3_result_error(p, "Error registering collation function", -1); - } -} - -/* -** Register the ICU extension functions with database db. -*/ -EXPORT_SYMBOLS SQLITE_API int sqlite3IcuInit(sqlite3 *db){ -# define SQLITEICU_EXTRAFLAGS (SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS) - static const struct IcuScalar { - const char *zName; /* Function name */ - unsigned char nArg; /* Number of arguments */ - unsigned int enc; /* Optimal text encoding */ - unsigned char iContext; /* sqlite3_user_data() context */ - void (*xFunc)(sqlite3_context*,int,sqlite3_value**); - } scalars[] = { - {"icu_load_collation",2,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}, - {"lower", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, - {"upper", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, - {"upper", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, - {"lower", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, - {"lower", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, - {"upper", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, - {"upper", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, - {"like", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc}, - {"like", 3, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc}, -#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ - }; -#ifdef HARMONY_OS - extern void SetOhosIcuDirectory(); - SetOhosIcuDirectory(); -#endif - int rc = SQLITE_OK; - int i; - - for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){ - const struct IcuScalar *p = &scalars[i]; - rc = sqlite3_create_function( - db, p->zName, p->nArg, p->enc, - p->iContext ? (void*)db : (void*)0, - p->xFunc, 0, 0 - ); - } - - return rc; -} - -#if !SQLITE_CORE -#ifdef _WIN32 -__declspec(dllexport) -#endif -SQLITE_API int sqlite3_icu_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi -){ - SQLITE_EXTENSION_INIT2(pApi) - return sqlite3IcuInit(db); -} -#endif - -#endif - -/************** End of icu.c *************************************************/ -/************** Begin file fts3_icu.c ****************************************/ -/* -** 2007 June 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** This file implements a tokenizer for fts3 based on the ICU library. -*/ -/* #include "fts3Int.h" */ -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) -#ifdef SQLITE_ENABLE_ICU - -/* #include */ -/* #include */ -/* #include "fts3_tokenizer.h" */ - -#include -/* #include */ -/* #include */ -#include - -typedef struct IcuTokenizer IcuTokenizer; -typedef struct IcuCursor IcuCursor; - -struct IcuTokenizer { - sqlite3_tokenizer base; - char *zLocale; -}; - -struct IcuCursor { - sqlite3_tokenizer_cursor base; - - UBreakIterator *pIter; /* ICU break-iterator object */ - int nChar; /* Number of UChar elements in pInput */ - UChar *aChar; /* Copy of input using utf-16 encoding */ - int *aOffset; /* Offsets of each character in utf-8 input */ - - int nBuffer; - char *zBuffer; - - int iToken; -}; - -/* -** Create a new tokenizer instance. -*/ -static int icuCreate( - int argc, /* Number of entries in argv[] */ - const char * const *argv, /* Tokenizer creation arguments */ - sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ -){ - IcuTokenizer *p; - int n = 0; - - if( argc>0 ){ - n = strlen(argv[0])+1; - } - p = (IcuTokenizer *)sqlite3_malloc64(sizeof(IcuTokenizer)+n); - if( !p ){ - return SQLITE_NOMEM; - } - memset(p, 0, sizeof(IcuTokenizer)); - - if( n ){ - p->zLocale = (char *)&p[1]; - memcpy(p->zLocale, argv[0], n); - } - - *ppTokenizer = (sqlite3_tokenizer *)p; - - return SQLITE_OK; -} - -/* -** Destroy a tokenizer -*/ -static int icuDestroy(sqlite3_tokenizer *pTokenizer){ - IcuTokenizer *p = (IcuTokenizer *)pTokenizer; - sqlite3_free(p); - return SQLITE_OK; -} - -/* -** Prepare to begin tokenizing a particular string. The input -** string to be tokenized is pInput[0..nBytes-1]. A cursor -** used to incrementally tokenize this string is returned in -** *ppCursor. -*/ -static int icuOpen( - sqlite3_tokenizer *pTokenizer, /* The tokenizer */ - const char *zInput, /* Input string */ - int nInput, /* Length of zInput in bytes */ - sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ -){ - IcuTokenizer *p = (IcuTokenizer *)pTokenizer; - IcuCursor *pCsr; - - const int32_t opt = U_FOLD_CASE_DEFAULT; - UErrorCode status = U_ZERO_ERROR; - int nChar; - - UChar32 c; - int iInput = 0; - int iOut = 0; - - *ppCursor = 0; - - if( zInput==0 ){ - nInput = 0; - zInput = ""; - }else if( nInput<0 ){ - nInput = strlen(zInput); - } - nChar = nInput+1; - pCsr = (IcuCursor *)sqlite3_malloc64( - sizeof(IcuCursor) + /* IcuCursor */ - ((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */ - (nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */ - ); - if( !pCsr ){ - return SQLITE_NOMEM; - } - memset(pCsr, 0, sizeof(IcuCursor)); - pCsr->aChar = (UChar *)&pCsr[1]; - pCsr->aOffset = (int *)&pCsr->aChar[(nChar+3)&~3]; - - pCsr->aOffset[iOut] = iInput; - U8_NEXT(zInput, iInput, nInput, c); - while( c>0 ){ - int isError = 0; - c = u_foldCase(c, opt); - U16_APPEND(pCsr->aChar, iOut, nChar, c, isError); - if( isError ){ - sqlite3_free(pCsr); - return SQLITE_ERROR; - } - pCsr->aOffset[iOut] = iInput; - - if( iInputpIter = ubrk_open(UBRK_WORD, p->zLocale, pCsr->aChar, iOut, &status); - if( !U_SUCCESS(status) ){ - sqlite3_free(pCsr); - return SQLITE_ERROR; - } - pCsr->nChar = iOut; - - ubrk_first(pCsr->pIter); - *ppCursor = (sqlite3_tokenizer_cursor *)pCsr; - return SQLITE_OK; -} - -/* -** Close a tokenization cursor previously opened by a call to icuOpen(). -*/ -static int icuClose(sqlite3_tokenizer_cursor *pCursor){ - IcuCursor *pCsr = (IcuCursor *)pCursor; - ubrk_close(pCsr->pIter); - sqlite3_free(pCsr->zBuffer); - sqlite3_free(pCsr); - return SQLITE_OK; -} - -/* -** Extract the next token from a tokenization cursor. -*/ -static int icuNext( - sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by simpleOpen */ - const char **ppToken, /* OUT: *ppToken is the token text */ - int *pnBytes, /* OUT: Number of bytes in token */ - int *piStartOffset, /* OUT: Starting offset of token */ - int *piEndOffset, /* OUT: Ending offset of token */ - int *piPosition /* OUT: Position integer of token */ -){ - IcuCursor *pCsr = (IcuCursor *)pCursor; - - int iStart = 0; - int iEnd = 0; - int nByte = 0; - - while( iStart==iEnd ){ - UChar32 c; - - iStart = ubrk_current(pCsr->pIter); - iEnd = ubrk_next(pCsr->pIter); - if( iEnd==UBRK_DONE ){ - return SQLITE_DONE; - } - - while( iStartaChar, iWhite, pCsr->nChar, c); - if( u_isspace(c) ){ - iStart = iWhite; - }else{ - break; - } - } - assert(iStart<=iEnd); - } - - do { - UErrorCode status = U_ZERO_ERROR; - if( nByte ){ - char *zNew = sqlite3_realloc(pCsr->zBuffer, nByte); - if( !zNew ){ - return SQLITE_NOMEM; - } - pCsr->zBuffer = zNew; - pCsr->nBuffer = nByte; - } - - u_strToUTF8( - pCsr->zBuffer, pCsr->nBuffer, &nByte, /* Output vars */ - &pCsr->aChar[iStart], iEnd-iStart, /* Input vars */ - &status /* Output success/failure */ - ); - } while( nByte>pCsr->nBuffer ); - - *ppToken = pCsr->zBuffer; - *pnBytes = nByte; - *piStartOffset = pCsr->aOffset[iStart]; - *piEndOffset = pCsr->aOffset[iEnd]; - *piPosition = pCsr->iToken++; - - return SQLITE_OK; -} - -/* -** The set of routines that implement the simple tokenizer -*/ -static const sqlite3_tokenizer_module icuTokenizerModule = { - 0, /* iVersion */ - icuCreate, /* xCreate */ - icuDestroy, /* xCreate */ - icuOpen, /* xOpen */ - icuClose, /* xClose */ - icuNext, /* xNext */ - 0, /* xLanguageid */ -}; - -/* -** Set *ppModule to point at the implementation of the ICU tokenizer. -*/ -EXPORT_SYMBOLS SQLITE_API void sqlite3Fts3IcuTokenizerModule( - sqlite3_tokenizer_module const**ppModule -){ - *ppModule = &icuTokenizerModule; -} - -#endif /* defined(SQLITE_ENABLE_ICU) */ -#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ - -/************** End of fts3_icu.c ********************************************/ -- Gitee