diff --git a/Cargo.lock b/Cargo.lock index 9cc05d6..db9ac47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,4 +4,4 @@ version = 3 [[package]] name = "sqlite3mc-src" -version = "205.1.0+sqlite3mc-2.5.1-sqlite-3.53.4" +version = "206.1.0+sqlite3mc-2.6.1-sqlite-3.54.0" diff --git a/Cargo.toml b/Cargo.toml index bf615e8..678e443 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sqlite3mc-src" # SQLite3MC X.Y.Z is (100X+Y).Z.n, where n counts our own republishes of that release. -version = "205.1.0+sqlite3mc-2.5.1-sqlite-3.53.4" +version = "206.1.0+sqlite3mc-2.6.1-sqlite-3.54.0" edition = "2021" rust-version = "1.81" description = "Untouched SQLite3 Multiple Ciphers amalgamation for Rust -sys crates to build" diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index df8405e..6722f56 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -121,7 +121,7 @@ checksum = "d983a7f69ae93370d5101e82b9442dce8c4e510977d97374c3e668d6dff32d08" [[package]] name = "sqlite3mc-src" -version = "205.1.0+sqlite3mc-2.5.1-sqlite-3.53.4" +version = "206.1.0+sqlite3mc-2.6.1-sqlite-3.54.0" [[package]] name = "sqlite3mc-src-fuzz" diff --git a/smoke/Cargo.lock b/smoke/Cargo.lock index 9f0173d..2604d13 100644 --- a/smoke/Cargo.lock +++ b/smoke/Cargo.lock @@ -26,7 +26,7 @@ checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "sqlite3mc-src" -version = "205.1.0+sqlite3mc-2.5.1-sqlite-3.53.4" +version = "206.1.0+sqlite3mc-2.6.1-sqlite-3.54.0" [[package]] name = "sqlite3mc-src-smoke" diff --git a/sqlite3mc/SHA256SUMS b/sqlite3mc/SHA256SUMS index c1a9668..d0733fd 100644 --- a/sqlite3mc/SHA256SUMS +++ b/sqlite3mc/SHA256SUMS @@ -1,4 +1,4 @@ -59e30889a7b0106152e6d4fc3c18ac1592f252cb4defbb0a7e618fdecf1a221c sqlite3mc_amalgamation.c -034c22a23268735059850aa22ea79333865c093c90c32287cc03cc606dcbc177 sqlite3mc_amalgamation.h -ac9645e5c9ff0cf176efdd6e75cb5e98f46295d38e02db5c4d208826a39ab4be sqlite3ext.h +9b129d1ceb2c7d5dbf374b833eb29a640ecfa8e4a5af6d48508b429019c707b0 sqlite3mc_amalgamation.c +99b3e6997aa5fc604d9ea2352e6ae89dfd4d0af8d5bd7cbfe7293d959779e6eb sqlite3mc_amalgamation.h +48963abfefb41ac329ef9d706acb5eadba952a99a748285c9ded6b5e0942721b sqlite3ext.h 39205ec18e0f25f56c62d3bda9768e7509b63a74ba58beb7442903dfc81c247a LICENSE diff --git a/sqlite3mc/sqlite3ext.h b/sqlite3mc/sqlite3ext.h index cad1a2a..d377778 100644 --- a/sqlite3mc/sqlite3ext.h +++ b/sqlite3mc/sqlite3ext.h @@ -109,7 +109,7 @@ struct sqlite3_api_routines { const char * (*libversion)(void); int (*libversion_number)(void); void *(*malloc)(int); - char * (*mprintf)(const char*,...); + char *(SQLITE_CDECL*mprintf)(const char*,...); int (*open)(const char*,sqlite3**); int (*open16)(const void*,sqlite3**); int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); @@ -130,11 +130,11 @@ struct sqlite3_api_routines { void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*)); void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*)); void (*result_value)(sqlite3_context*,sqlite3_value*); - void * (*rollback_hook)(sqlite3*,void(*)(void*),void*); + void *(*rollback_hook)(sqlite3*,void(*)(void*),void*); int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, const char*,const char*),void*); void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); - char * (*xsnprintf)(int,char*,const char*,...); + char *(SQLITE_CDECL*xsnprintf)(int,char*,const char*,...); int (*step)(sqlite3_stmt*); int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, char const**,char const**,int*,int*,int*); @@ -198,7 +198,7 @@ struct sqlite3_api_routines { int (*xthreadsafe)(void); void (*result_zeroblob)(sqlite3_context*,int); void (*result_error_code)(sqlite3_context*,int); - int (*test_control)(int, ...); + int (SQLITE_CDECL*test_control)(int, ...); void (*randomness)(int,void*); sqlite3 *(*context_db_handle)(sqlite3_context*); int (*extended_result_codes)(sqlite3*,int); @@ -218,11 +218,11 @@ struct sqlite3_api_routines { void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*), void(*xDestroy)(void*)); - int (*db_config)(sqlite3*,int,...); + int (SQLITE_CDECL*db_config)(sqlite3*,int,...); sqlite3_mutex *(*db_mutex)(sqlite3*); int (*db_status)(sqlite3*,int,int*,int*,int); int (*extended_errcode)(sqlite3*); - void (*log)(int,const char*,...); + void (SQLITE_CDECL*log)(int,const char*,...); sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64); const char *(*sourceid)(void); int (*stmt_status)(sqlite3_stmt*,int,int); @@ -232,7 +232,7 @@ struct sqlite3_api_routines { int (*wal_checkpoint)(sqlite3*,const char*); void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); - int (*vtab_config)(sqlite3*,int op,...); + int (SQLITE_CDECL*vtab_config)(sqlite3*,int op,...); int (*vtab_on_conflict)(sqlite3*); /* Version 3.7.16 and later */ int (*close_v2)(sqlite3*); @@ -301,7 +301,7 @@ struct sqlite3_api_routines { int (*keyword_check)(const char*,int); sqlite3_str *(*str_new)(sqlite3*); char *(*str_finish)(sqlite3_str*); - void (*str_appendf)(sqlite3_str*, const char *zFormat, ...); + void (SQLITE_CDECL*str_appendf)(sqlite3_str*, const char *zFormat, ...); void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list); void (*str_append)(sqlite3_str*, const char *zIn, int N); void (*str_appendall)(sqlite3_str*, const char *zIn); @@ -376,6 +376,9 @@ struct sqlite3_api_routines { void (*str_free)(sqlite3_str*); int (*carray_bind)(sqlite3_stmt*,int,void*,int,int,void(*)(void*)); int (*carray_bind_v2)(sqlite3_stmt*,int,void*,int,int,void(*)(void*),void*); + /* Version 3.54.0 and later */ + sqlite3_int64 (*incomplete)(const char*); + void (*result_str)(sqlite3_context*,sqlite3_str*,int); }; /* @@ -719,6 +722,9 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_str_free sqlite3_api->str_free #define sqlite3_carray_bind sqlite3_api->carray_bind #define sqlite3_carray_bind_v2 sqlite3_api->carray_bind_v2 +/* Version 3.54.0 and later */ +#define sqlite3_incomplete sqlite3_api->incomplete +#define sqlite3_result_str sqlite3_api->result_str #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) diff --git a/sqlite3mc/sqlite3mc_amalgamation.c b/sqlite3mc/sqlite3mc_amalgamation.c index 574d1da..77f894e 100644 --- a/sqlite3mc/sqlite3mc_amalgamation.c +++ b/sqlite3mc/sqlite3mc_amalgamation.c @@ -7,6 +7,21 @@ ** License: MIT */ +/* +** Keep temporary data in memory by default +** +** Temporary files (for example temporary tables, sort data and transient +** databases) are not encrypted. The default applies only if SQLITE_TEMP_STORE +** is not defined. Possible values: +** 0 = always use temporary files +** 1 = use temporary files, unless PRAGMA temp_store=MEMORY (SQLite's default) +** 2 = use memory, unless PRAGMA temp_store=FILE +** 3 = always use memory +*/ +#ifndef SQLITE_TEMP_STORE +#define SQLITE_TEMP_STORE 2 +#endif + /* ** If SQLite functions should be called through a dispatch table, ** thus hiding all SQLite function symbols from the linker, @@ -140,7 +155,7 @@ SQLITE_API LPWSTR sqlite3_win32_utf8_to_unicode(const char*); /*** Begin of #include "sqlite3patched.c" ***/ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.53.4. By combining all the individual C code files into this +** version 3.54.0. 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 @@ -158,7 +173,7 @@ SQLITE_API LPWSTR sqlite3_win32_utf8_to_unicode(const char*); ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in -** bf7c7f30031888f4e796e429ab3978879485 with changes in files: +** be8d059e9a49089ab2dce5ed26dd87aaf598 with changes in files: ** ** */ @@ -607,12 +622,12 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.53.4" -#define SQLITE_VERSION_NUMBER 3053004 -#define SQLITE_SOURCE_ID "2026-07-24 19:02:57 bf7c7f30031888f4e796e429ab3978879485813aaca6f641c7b33e4e09459bcc" -#define SQLITE_SCM_BRANCH "branch-3.53" -#define SQLITE_SCM_TAGS "release version-3.53.4" -#define SQLITE_SCM_DATETIME "2026-07-24T19:02:57.525Z" +#define SQLITE_VERSION "3.54.0" +#define SQLITE_VERSION_NUMBER 3054000 +#define SQLITE_SOURCE_ID "2026-10-09 15:46:58 be8d059e9a49089ab2dce5ed26dd87aaf598fdc5fbe0b107c0dd758464bcd5e3" +#define SQLITE_SCM_BRANCH "trunk" +#define SQLITE_SCM_TAGS "release major-release version-3.54.0" +#define SQLITE_SCM_DATETIME "2026-10-09T15:46:58.543Z" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -924,7 +939,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_FULL 13 /* Insertion failed because database is full */ #define SQLITE_CANTOPEN 14 /* Unable to open the database file */ #define SQLITE_PROTOCOL 15 /* Database lock protocol error */ -#define SQLITE_EMPTY 16 /* Internal use only */ +#define SQLITE_EMPTY 16 /* No content */ #define SQLITE_SCHEMA 17 /* The database schema changed */ #define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ #define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ @@ -3421,8 +3436,9 @@ SQLITE_API int sqlite3_is_interrupted(sqlite3*); ** These routines are useful during command-line input to determine if the ** currently entered text seems to form a complete SQL statement or ** if additional input is needed before sending the text into -** SQLite for parsing. ^These routines return 1 if the input string -** appears to be a complete SQL statement. ^A statement is judged to be +** SQLite for parsing. ^The sqlite3_complete(X) and sqlite3_complete16(X) +** routines return 1 if the input string X appears to be a complete SQL +** statement. ^A statement is judged to be ** complete if it ends with a semicolon token and is not a prefix of a ** well-formed CREATE TRIGGER statement. ^Semicolons that are embedded within ** string literals or quoted identifier names or comments are not @@ -3430,11 +3446,25 @@ SQLITE_API int sqlite3_is_interrupted(sqlite3*); ** embedded) and thus do not count as a statement terminator. ^Whitespace ** and comments that follow the final semicolon are ignored. ** -** ^These routines return 0 if the statement is incomplete. ^If a -** memory allocation fails, then SQLITE_NOMEM is returned. +** ^The sqlite3_complete(X) and sqlite3_complete16(X) routines return 0 +** if the statement is incomplete. ^If a memory allocation fails, then +** SQLITE_NOMEM is returned. ** -** ^These routines do not parse the SQL statements and thus -** will not detect syntactically incorrect SQL. +** The [sqlite3_incomplete(X)] routine is similar to [sqlite3_complete(X)] +** except that sqlite3_incomplete(X) returns SQLITE_OK if the input X is +** complete, SQLITE_EMPTY if input X consists entirely of whitespace and/or +** comments, SQLITE_MISUSE if X is a NULL pointer, and some other non-zero +** value if X is incomplete. The non-zero return from +** sqlite3_incomplete(X) contains additional information about what is +** needed to complete the input X. See the header comment on the +** implemenation of the sqlite3_incomplete() routine for a full description +** of its non-zero return values. The sqlite3_incomplete(X) interface +** is only available for UTF-8 text. +** +** ^None of these routines do a full parse the SQL statements and thus +** will not detect syntactically incorrect SQL. They only determine if +** input text has properly terminated comments, string literals, and +** quoted identifiers, and if the statement ends with a semicolon. ** ** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior ** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked @@ -3442,14 +3472,15 @@ SQLITE_API int sqlite3_is_interrupted(sqlite3*); ** then the return value from sqlite3_complete16() will be non-zero ** regardless of whether or not the input SQL is complete.)^ ** -** The input to [sqlite3_complete()] must be a zero-terminated -** UTF-8 string. +** The X input to [sqlite3_complete(X)] and [sqlite3_incomplete(X)] +** must be a zero-terminated UTF-8 string. ** ** The input to [sqlite3_complete16()] must be a zero-terminated ** UTF-16 string in native byte order. */ SQLITE_API int sqlite3_complete(const char *sql); SQLITE_API int sqlite3_complete16(const void *sql); +SQLITE_API sqlite3_int64 sqlite3_incomplete(const char *sql); /* ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors @@ -3862,7 +3893,7 @@ SQLITE_API void sqlite3_randomness(int N, void *P); ** ** ^The first parameter to the authorizer callback is a copy of the third ** parameter to the sqlite3_set_authorizer() interface. ^The second parameter -** to the callback is an integer [SQLITE_COPY | action code] that specifies +** to the callback is an integer [SQLITE_READ | action code] that specifies ** the particular action to be authorized. ^The third through sixth parameters ** to the callback are either NULL pointers or zero-terminated strings ** that contain additional details about the action to be authorized. @@ -3905,21 +3936,33 @@ SQLITE_API void sqlite3_randomness(int N, void *P); ** previous call.)^ ^Disable the authorizer by installing a NULL callback. ** The authorizer is disabled by default. ** -** The authorizer callback must not do anything that will modify +**

Limitations And Caveats

*/ SQLITE_API int sqlite3_set_authorizer( sqlite3*, @@ -3960,6 +4003,11 @@ SQLITE_API int sqlite3_set_authorizer( ** is the name of the inner-most trigger or view that is responsible for ** the access attempt or NULL if this access attempt is directly from ** top-level SQL code. +** +** The case of strings in the 3rd through the 6th argument to the +** authorization callback is arbitrary. Authorization callbacks +** implementations should use [sqlite3_stricmp()] or similar when +** doing comparisons against those values. */ /******************************************* 3rd ************ 4th ***********/ #define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */ @@ -3994,9 +4042,14 @@ SQLITE_API int sqlite3_set_authorizer( #define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */ #define SQLITE_FUNCTION 31 /* NULL Function Name */ #define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ -#define SQLITE_COPY 0 /* No longer used */ #define SQLITE_RECURSIVE 33 /* NULL NULL */ +/* +** Note: The SQLITE_COPY macro (with value 0) used to be one of the +** action codes above. That macro has now been repurposed as a possible +** value to the 3rd argument to sqlite3_result_str(). +*/ + /* ** CAPI3REF: Deprecated Tracing And Profiling Functions ** DEPRECATED @@ -4503,8 +4556,7 @@ SQLITE_API int sqlite3_open_v2( ** ** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a ** 64-bit signed integer and returns that integer, or D if P does not -** exist. If the value of P is something other than an integer, then -** zero is returned. +** exist or if the value of P is something other than an integer. ** ** The sqlite3_uri_key(F,N) returns a pointer to the name (not ** the value) of the N-th query parameter for filename F, or a NULL @@ -4865,6 +4917,14 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** [[SQLITE_LIMIT_WORKER_THREADS]] ^(
SQLITE_LIMIT_WORKER_THREADS
**
The maximum number of auxiliary worker threads that a single ** [prepared statement] may start.
)^ +** +** [[SQLITE_LIMIT_SCHEMA]] ^(
SQLITE_LIMIT_SCHEMA
+**
The maximum number of objects (tables, indexes, triggers, and views) +** defined by the database schema.
)^ +** +** [[SQLITE_LIMIT_TRIGGER_STEPS]] ^(
SQLITE_LIMIT_TRIGGER_STEPS
+**
The maximum number of SQL statements that can be contained within +** a single trigger.
)^ ** */ #define SQLITE_LIMIT_LENGTH 0 @@ -4880,6 +4940,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); #define SQLITE_LIMIT_TRIGGER_DEPTH 10 #define SQLITE_LIMIT_WORKER_THREADS 11 #define SQLITE_LIMIT_PARSER_DEPTH 12 +#define SQLITE_LIMIT_SCHEMA 13 +#define SQLITE_LIMIT_TRIGGER_STEPS 14 /* ** CAPI3REF: Prepare Flags @@ -4991,6 +5053,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** the nul-terminator. ** Note that nByte measures the length of the input in bytes, not ** characters, even for the UTF-16 interfaces. +** For the sqlite3_prepare16() and sqlite3_prepare16_v2() interfaces, +** the nByte value must be even or undefined behavior can result. ** ** ^If pzTail is not NULL then *pzTail is made to point to the first byte ** past the end of the first SQL statement in zSql. These routines only @@ -5737,7 +5801,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** [prepared statement]. ^In the "v2" interface, ** the more specific error code is returned directly by sqlite3_step(). ** -** [SQLITE_MISUSE] means that the this routine was called inappropriately. +** [SQLITE_MISUSE] means that this routine was called inappropriately. ** Perhaps it was called on a [prepared statement] that has ** already been [sqlite3_finalize | finalized] or on one that had ** previously returned [SQLITE_ERROR] or [SQLITE_DONE]. Or it could @@ -6910,7 +6974,11 @@ typedef void (*sqlite3_destructor_type)(void*); ** ** ^The sqlite3_result_zeroblob(C,N) and sqlite3_result_zeroblob64(C,N) ** interfaces set the result of the application-defined function to be -** a BLOB containing all zero bytes and N bytes in size. +** a BLOB containing all zero bytes and N bytes in size. The +** zeroblob64(C,N) interface returns a [result code], which is normally +** [SQLITE_OK] but might be some other value if the requested operation +** could not be complete, for example if insufficient memory is available +** or if the value of N is out of range. ** ** ^The sqlite3_result_double() interface sets the result from ** an application-defined function to be a floating point value specified @@ -9248,8 +9316,8 @@ SQLITE_API int sqlite3_keyword_check(const char*,int); **
  • ^The sqlite3_str object is created using [sqlite3_str_new()]. **
  • ^Text is appended to the sqlite3_str object using various ** methods, such as [sqlite3_str_appendf()]. -**
  • ^The sqlite3_str object is destroyed and the string it created -** is returned using the [sqlite3_str_finish()] interface. +**
  • The sqlite3_str object is destroyed and the string it created +** is returned using [sqlite3_str_finish()] or [sqlite3_result_str()]. ** */ typedef struct sqlite3_str sqlite3_str; @@ -9301,6 +9369,40 @@ SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3*); SQLITE_API char *sqlite3_str_finish(sqlite3_str*); SQLITE_API void sqlite3_str_free(sqlite3_str*); +/* +** CAPI3REF: Return A Dynamic String From an SQL Function +** +** The [sqlite3_result_str(C,S,F)] interface causes the +** [sqlite3_str|dynamic string] S to become the return value for the +** application-defined function or virtual table that uses +** [sqlite3_context] C. The F flag can be one of [SQLITE_COPY] +** or [SQLITE_XFER] or [SQLITE_FINISH]. +** +** If the dynamic string is invalid or incomplete due to an out-of-memory +** or string-too-large error, then this routine transfers that error +** over to the SQL function. +** +** If the F argument is SQLITE_COPY, then a copy of the dynamic string +** content is made and the dynamic string object is unchanged. +** If the F argument is SQLITE_XFER, then ownership of the content +** in the dynamic is transferred to the SQL function (via a pointer copy +** rather than a string copy) and the dynamic string is reset to an +** empty string. The SQLITE_FINISH value for F works like SQLITE_RESET +** except that it also invokes the [sqlite3_str_free(S)] destructor +** on the dynamic string object. +*/ +SQLITE_API void sqlite3_result_str(sqlite3_context*, sqlite3_str*, int); + +/* +** CAPI3REF: Control Flags For sqlite3_result_str() +** +** The following integers can be used as the third "F" argument +** to [sqlite3_result_str(C,S,F)]. +*/ +#define SQLITE_COPY 0 /* Results copied. Dynamic string unchanged */ +#define SQLITE_XFER 1 /* Results transfered. Dynamic string reset */ +#define SQLITE_FINISH 2 /* Like SQLITE_XFER, plus dynamic string freed */ + /* ** CAPI3REF: Add Content To A Dynamic String ** METHOD: sqlite3_str @@ -11666,8 +11768,19 @@ SQLITE_API unsigned char *sqlite3_serialize( ** used. The serialized database P is N bytes in size. M is the size ** of the buffer P, which might be larger than N. If M is larger than ** N, and the SQLITE_DESERIALIZE_READONLY bit is not set in F, then -** SQLite is permitted to add content to the in-memory database as -** long as the total size does not exceed M bytes. +** SQLite is permitted to add content to the in-memory database, in +** page-sized chunks, as long as the total size does not exceed M bytes. +** +** The parameter M must be greater than or equal to N. Ideally, M +** should have a value which is N+(512×K)+20 where K determines how +** must extra space is available to hold new content as the database +** grows. K can be 0 if the database is read-only. +** +** If the database content in P is malformed in a malicious way then +** it is possible that SQLite might try to read a few more than N bytes +** from P. If the veracity of the database content P is uncertain, +** then applications are advised to allocate about 20 extra bytes on +** the end of the P buffer to avoid a memory error. ** ** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will ** invoke sqlite3_free() on the serialization buffer when the database @@ -14817,6 +14930,8 @@ SQLITE_PRIVATE int sqlite3mcHandleMainKey(sqlite3*, const char*); typedef struct PgHdr PgHdrMC; SQLITE_PRIVATE void* sqlite3mcPagerCodec(PgHdrMC* pPg); typedef struct Pager PagerMC; +SQLITE_PRIVATE int sqlite3mcOpenTempFile(PagerMC* pPager, sqlite3_file* pFile); +SQLITE_PRIVATE int sqlite3mcOpenTempJournal(sqlite3* pDb, sqlite3_file* pFile); SQLITE_PRIVATE int sqlite3mcPagerHasCodec(PagerMC* pPager); SQLITE_PRIVATE void sqlite3mcInitMemoryMethods(); SQLITE_PRIVATE int sqlite3mcIsBackupSupported(sqlite3*, const char*, sqlite3*, const char*); @@ -14827,7 +14942,7 @@ SQLITE_PRIVATE int sqlite3mc_builtin_extensions(sqlite3* db); /************** Continuing where we left off in sqliteInt.h ******************/ /* -** Reuse the STATIC_LRU for mutex access to sqlite3_temp_directory. +** Reuse the STATIC_VFS1 for mutex access to sqlite3_temp_directory. */ #define SQLITE_MUTEX_STATIC_TEMPDIR SQLITE_MUTEX_STATIC_VFS1 @@ -15112,6 +15227,41 @@ SQLITE_PRIVATE int sqlite3mc_builtin_extensions(sqlite3* db); # define SQLITE_MAX_TRIGGER_DEPTH 1000 #endif +/* +** Maximum number of objects defined by a single database schema. +** Objects include: +** +** * tables (including the sqlite_schema table) +** * virtual tables +** * named indexes +** * indexes created automatically by UNIQUE and PRIMARY KEY constraints +** * triggers +** * views +** +** The total of all of the above is the number of objects in the schema, +** and that number may not exceed this value. +** +** The maximum number of objects is restricted to forestall theoretical +** signed integer overflow attacks using databases with billions of +** schema objects. Such attacks are "theoretical" because memory and +** disk space constraints would be reached long before billions of schema +** objects could be created. Even so, it seems good to have a well defined +** upper limit on the complexity of the schema, for defense in depth. +** No real-world application should ever get anywhere close to hitting +** this limit. +*/ +#ifndef SQLITE_MAX_SCHEMA +# define SQLITE_MAX_SCHEMA 10000000 +#endif + +/* +** Maximum number of SQL statements allowed in the body of a single +** trigger. +*/ +#ifndef SQLITE_MAX_TRIGGER_STEPS +# define SQLITE_MAX_TRIGGER_STEPS 65000 +#endif + /************** End of sqliteLimit.h *****************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ @@ -15180,22 +15330,50 @@ SQLITE_PRIVATE int sqlite3mc_builtin_extensions(sqlite3* db); #endif /* -** Macros to hint to the compiler that a function should or should not be -** inlined. +** Hint to the compiler that a function should or should not be inlined: +** +** SQLITE_NOINLINE Never in-line this function +** +** SQLITE_INLINE Strive to in-line this function +** +** SQLITE_OPT_INLINE In-line this function if building the +** amalgamation. +** +** SQLITE_USES_INLINE Set to 1 or 0 according to whether or not +** inline functions are supported. */ -#if defined(__GNUC__) -# define SQLITE_NOINLINE __attribute__((noinline)) -# define SQLITE_INLINE __attribute__((always_inline)) inline +#if defined(SQLITE_DISABLE_INLINE) +# define SQLITE_NOINLINE +# define SQLITE_INLINE +# define SQLITE_OPT_INLINE +# define SQLITE_USES_INLINE 0 +#elif defined(__GNUC__) +# define SQLITE_NOINLINE __attribute__((noinline)) +# define SQLITE_INLINE __attribute__((always_inline)) inline +# define SQLITE_OPT_INLINE __attribute__((always_inline)) inline +# define SQLITE_USES_INLINE 1 #elif defined(_MSC_VER) && _MSC_VER>=1310 -# define SQLITE_NOINLINE __declspec(noinline) -# define SQLITE_INLINE __forceinline +# define SQLITE_NOINLINE __declspec(noinline) +# define SQLITE_INLINE __forceinline +# define SQLITE_OPT_INLINE __forceinline +# define SQLITE_USES_INLINE 1 #else # define SQLITE_NOINLINE # define SQLITE_INLINE +# define SQLITE_OPT_INLINE +# define SQLITE_USES_INLINE 0 #endif #if defined(SQLITE_COVERAGE_TEST) || defined(__STRICT_ANSI__) # undef SQLITE_INLINE # define SQLITE_INLINE +# undef SQLITE_OPT_INLINE +# define SQLITE_OPT_INLINE +# undef SQLITE_USES_INLINE +# define SQLITE_USES_INLINE 0 +#endif +#if !defined(SQLITE_AMALGAMATION) +# undef SQLITE_OPT_INLINE +# define SQLITE_OPT_INLINE #endif /* @@ -15370,7 +15548,9 @@ SQLITE_PRIVATE int sqlite3mc_builtin_extensions(sqlite3* db); ** where multiple cases go to the same block of code, testcase() ** can insure that all cases are evaluated. */ -#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) +#if defined(SQLITE_MUTATION_TEST) +# define testcase(X) +#elif defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) # ifndef SQLITE_AMALGAMATION extern unsigned int sqlite3CoverageCounter; # endif @@ -17211,6 +17391,10 @@ SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*); SQLITE_PRIVATE int sqlite3PagerWalSystemErrno(Pager*); #endif +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_WALSTAT) +SQLITE_PRIVATE void sqlite3PagerWalStat(Pager*,sqlite3_str*); +#endif + #endif /* SQLITE_PAGER_H */ /************** End of pager.h ***********************************************/ @@ -17401,12 +17585,19 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p); ** implementations with limits on what needs to be prefetched and thereby ** reduce network bandwidth. ** +** BTREE_HINT_TABLECURSOR (arguments: BtCursor*) +** +** This hint is invoked on a non-covering index cursor soon after it +** is opened. The only argument is a pointer to the table cursor used to +** obtain non-covered fields from the database. +** ** 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 ** the SQLite parser and code generator but substitute their own storage ** engine. */ #define BTREE_HINT_RANGE 0 /* Range constraints on queries */ +#define BTREE_HINT_TABLECURSOR 1 /* Table csr associated with this index csr */ /* ** Values that may be OR'd together to form the argument to the @@ -17466,6 +17657,9 @@ SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned); #ifdef SQLITE_ENABLE_CURSOR_HINTS SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor*, int, ...); + #ifdef SQLITE_DEBUG +SQLITE_PRIVATE BtCursor *sqlite3BtreeCursorHintTblCsr(BtCursor*); + #endif #endif SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor*); @@ -17712,8 +17906,6 @@ struct VdbeOp { int i; /* Integer value if p4type==P4_INT32 */ void *p; /* Generic pointer */ char *z; /* Pointer to data for string (char array) types */ - i64 *pI64; /* Used when p4type is P4_INT64 */ - double *pReal; /* Used when p4type is P4_REAL */ FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */ sqlite3_context *pCtx; /* Used when p4type is P4_FUNCCTX */ CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */ @@ -17769,6 +17961,19 @@ struct VdbeOpList { }; typedef struct VdbeOpList VdbeOpList; +/* +** Combine two int32 values into a single int64. The least significant +** term comes first. +*/ +#define INT32_TO_64(a,b) (i64)(((u64)(u32)(b)<<32)|(u32)(a)) + +/* +** Return an int32 that is the lower or upper 32-bits of an int64. +*/ +#define LOWER32(x) (int)(((u64)(x))&0xffffffff) +#define UPPER32(x) (int)(((u64)(x))>>32) + + /* ** Allowed values of VdbeOp.p4type */ @@ -17788,12 +17993,10 @@ typedef struct VdbeOpList VdbeOpList; #define P4_EXPR (-10) /* P4 is a pointer to an Expr tree */ #define P4_MEM (-11) /* P4 is a pointer to a Mem* structure */ #define P4_VTAB (-12) /* P4 is a pointer to an sqlite3_vtab structure */ -#define P4_REAL (-13) /* P4 is a 64-bit floating point value */ -#define P4_INT64 (-14) /* P4 is a 64-bit signed integer */ -#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ -#define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */ -#define P4_TABLEREF (-17) /* Like P4_TABLE, but reference counted */ -#define P4_SUBRTNSIG (-18) /* P4 is a SubrtnSig pointer */ +#define P4_INTARRAY (-13) /* P4 is a vector of 32-bit integers */ +#define P4_FUNCCTX (-14) /* P4 is a pointer to an sqlite3_context object */ +#define P4_TABLEREF (-15) /* Like P4_TABLE, but reference counted */ +#define P4_SUBRTNSIG (-16) /* P4 is a SubrtnSig pointer */ /* Error message codes for OP_Halt */ #define P5_ConstraintNotNull 1 @@ -17860,32 +18063,32 @@ typedef struct VdbeOpList VdbeOpList; #define OP_SeekLE 22 /* jump0, synopsis: key=r[P3@P4] */ #define OP_SeekGE 23 /* jump0, synopsis: key=r[P3@P4] */ #define OP_SeekGT 24 /* jump0, synopsis: key=r[P3@P4] */ -#define OP_IfNotOpen 25 /* jump, synopsis: if( !csr[P1] ) goto P2 */ -#define OP_IfNoHope 26 /* jump, synopsis: key=r[P3@P4] */ -#define OP_NoConflict 27 /* jump, synopsis: key=r[P3@P4] */ -#define OP_NotFound 28 /* jump, synopsis: key=r[P3@P4] */ -#define OP_Found 29 /* jump, synopsis: key=r[P3@P4] */ -#define OP_SeekRowid 30 /* jump0, synopsis: intkey=r[P3] */ -#define OP_NotExists 31 /* jump, synopsis: intkey=r[P3] */ -#define OP_Last 32 /* jump0 */ -#define OP_IfSizeBetween 33 /* jump */ -#define OP_SorterSort 34 /* jump */ -#define OP_Sort 35 /* jump */ -#define OP_Rewind 36 /* jump0 */ -#define OP_IfEmpty 37 /* jump, synopsis: if( empty(P1) ) goto P2 */ -#define OP_SorterNext 38 /* jump */ -#define OP_Prev 39 /* jump */ -#define OP_Next 40 /* jump */ -#define OP_IdxLE 41 /* jump, synopsis: key=r[P3@P4] */ -#define OP_IdxGT 42 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IfNoHope 25 /* jump, synopsis: key=r[P3@P4] */ +#define OP_NoConflict 26 /* jump, synopsis: key=r[P3@P4] */ +#define OP_NotFound 27 /* jump, synopsis: key=r[P3@P4] */ +#define OP_Found 28 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekRowid 29 /* jump0, synopsis: intkey=r[P3] */ +#define OP_NotExists 30 /* jump, synopsis: intkey=r[P3] */ +#define OP_Last 31 /* jump0 */ +#define OP_IfSizeBetween 32 /* jump */ +#define OP_SorterSort 33 /* jump */ +#define OP_Sort 34 /* jump */ +#define OP_Rewind 35 /* jump0 */ +#define OP_IfEmpty 36 /* jump, synopsis: if( empty(P1) ) goto P2 */ +#define OP_SorterNext 37 /* jump */ +#define OP_Prev 38 /* jump */ +#define OP_Next 39 /* jump */ +#define OP_IdxLE 40 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxGT 41 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxLT 42 /* jump, synopsis: key=r[P3@P4] */ #define OP_Or 43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ #define OP_And 44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ -#define OP_IdxLT 45 /* jump, synopsis: key=r[P3@P4] */ -#define OP_IdxGE 46 /* jump, synopsis: key=r[P3@P4] */ -#define OP_IFindKey 47 /* jump */ -#define OP_RowSetRead 48 /* jump, synopsis: r[P3]=rowset(P1) */ -#define OP_RowSetTest 49 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */ -#define OP_Program 50 /* jump0 */ +#define OP_IdxGE 45 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IFindKey 46 /* jump */ +#define OP_RowSetRead 47 /* jump, synopsis: r[P3]=rowset(P1) */ +#define OP_RowSetTest 48 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */ +#define OP_Program 49 /* jump0 */ +#define OP_FkIfZero 50 /* jump, synopsis: if fkctr[P1]==0 goto P2 */ #define OP_IsNull 51 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ #define OP_NotNull 52 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ #define OP_Ne 53 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */ @@ -17895,49 +18098,49 @@ typedef struct VdbeOpList VdbeOpList; #define OP_Lt 57 /* jump, same as TK_LT, synopsis: IF r[P3]=r[P1] */ #define OP_ElseEq 59 /* jump, same as TK_ESCAPE */ -#define OP_FkIfZero 60 /* jump, synopsis: if fkctr[P1]==0 goto P2 */ -#define OP_IfPos 61 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ -#define OP_IfNotZero 62 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ -#define OP_DecrJumpZero 63 /* jump, synopsis: if (--r[P1])==0 goto P2 */ -#define OP_IncrVacuum 64 /* jump */ -#define OP_VNext 65 /* jump */ -#define OP_Filter 66 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */ -#define OP_PureFunc 67 /* synopsis: r[P3]=func(r[P2@NP]) */ -#define OP_Function 68 /* synopsis: r[P3]=func(r[P2@NP]) */ -#define OP_Return 69 -#define OP_EndCoroutine 70 -#define OP_HaltIfNull 71 /* synopsis: if r[P3]=null halt */ -#define OP_Halt 72 -#define OP_Integer 73 /* synopsis: r[P2]=P1 */ -#define OP_Int64 74 /* synopsis: r[P2]=P4 */ -#define OP_String 75 /* synopsis: r[P2]='P4' (len=P1) */ -#define OP_BeginSubrtn 76 /* synopsis: r[P2]=NULL */ -#define OP_Null 77 /* synopsis: r[P2..P3]=NULL */ -#define OP_SoftNull 78 /* synopsis: r[P1]=NULL */ -#define OP_Blob 79 /* synopsis: r[P2]=P4 (len=P1) */ -#define OP_Variable 80 /* synopsis: r[P2]=parameter(P1) */ -#define OP_Move 81 /* synopsis: r[P2@P3]=r[P1@P3] */ -#define OP_Copy 82 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ -#define OP_SCopy 83 /* synopsis: r[P2]=r[P1] */ -#define OP_IntCopy 84 /* synopsis: r[P2]=r[P1] */ -#define OP_FkCheck 85 -#define OP_ResultRow 86 /* synopsis: output=r[P1@P2] */ -#define OP_CollSeq 87 -#define OP_AddImm 88 /* synopsis: r[P1]=r[P1]+P2 */ -#define OP_RealAffinity 89 -#define OP_Cast 90 /* synopsis: affinity(r[P1]) */ -#define OP_Permutation 91 -#define OP_Compare 92 /* synopsis: r[P1@P3] <-> r[P2@P3] */ -#define OP_IsTrue 93 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */ -#define OP_ZeroOrNull 94 /* synopsis: r[P2] = 0 OR NULL */ -#define OP_Offset 95 /* synopsis: r[P3] = sqlite_offset(P1) */ -#define OP_Column 96 /* synopsis: r[P3]=PX cursor P1 column P2 */ -#define OP_TypeCheck 97 /* synopsis: typecheck(r[P1@P2]) */ -#define OP_Affinity 98 /* synopsis: affinity(r[P1@P2]) */ -#define OP_MakeRecord 99 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ -#define OP_Count 100 /* synopsis: r[P2]=count() */ -#define OP_ReadCookie 101 -#define OP_SetCookie 102 +#define OP_IfPos 60 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ +#define OP_IfNotZero 61 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ +#define OP_DecrJumpZero 62 /* jump, synopsis: if (--r[P1])==0 goto P2 */ +#define OP_IncrVacuum 63 /* jump */ +#define OP_VNext 64 /* jump */ +#define OP_Filter 65 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */ +#define OP_PureFunc 66 /* synopsis: r[P3]=func(r[P2@NP]) */ +#define OP_Function 67 /* synopsis: r[P3]=func(r[P2@NP]) */ +#define OP_Return 68 +#define OP_EndCoroutine 69 +#define OP_HaltIfNull 70 /* synopsis: if r[P3]=null halt */ +#define OP_Halt 71 +#define OP_Integer 72 /* synopsis: r[P2]=P1 */ +#define OP_Int64 73 /* synopsis: r[P2]=PINT13 */ +#define OP_String 74 /* synopsis: r[P2]='P4' (len=P1) */ +#define OP_BeginSubrtn 75 /* synopsis: r[P2]=NULL */ +#define OP_Null 76 /* synopsis: r[P2..P3]=NULL */ +#define OP_SoftNull 77 /* synopsis: r[P1]=NULL */ +#define OP_Blob 78 /* synopsis: r[P2]=P4 (len=P1) */ +#define OP_Variable 79 /* synopsis: r[P2]=parameter(P1) */ +#define OP_Move 80 /* synopsis: r[P2@P3]=r[P1@P3] */ +#define OP_Copy 81 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ +#define OP_SCopy 82 /* synopsis: r[P2]=r[P1] */ +#define OP_IntCopy 83 /* synopsis: r[P2]=r[P1] */ +#define OP_FkCheck 84 +#define OP_ResultRow 85 /* synopsis: output=r[P1@P2] */ +#define OP_CollSeq 86 +#define OP_AddImm 87 /* synopsis: r[P1]=r[P1]+P2 */ +#define OP_RealAffinity 88 +#define OP_Cast 89 /* synopsis: affinity(r[P1]) */ +#define OP_Permutation 90 +#define OP_Compare 91 /* synopsis: r[P1@P3] <-> r[P2@P3] */ +#define OP_IsTrue 92 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */ +#define OP_ZeroOrNull 93 /* synopsis: r[P2] = 0 OR NULL */ +#define OP_Offset 94 /* synopsis: r[P3] = sqlite_offset(P1) */ +#define OP_Column 95 /* synopsis: r[P3]=PX cursor P1 column P2 */ +#define OP_TypeCheck 96 /* synopsis: typecheck(r[P1@P2]) */ +#define OP_Affinity 97 /* synopsis: affinity(r[P1@P2]) */ +#define OP_MakeRecord 98 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ +#define OP_Count 99 /* synopsis: r[P2]=count() */ +#define OP_ReadCookie 100 +#define OP_SetCookie 101 +#define OP_ReopenIdx 102 /* synopsis: root=P2 iDb=P3 */ #define OP_BitAnd 103 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ #define OP_BitOr 104 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ #define OP_ShiftLeft 105 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ -#define OP_AggInverse 163 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */ -#define OP_AggStep 164 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggStep1 165 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggValue 166 /* synopsis: r[P3]=value N=P2 */ -#define OP_AggFinal 167 /* synopsis: accum=r[P1] N=P2 */ -#define OP_Expire 168 -#define OP_CursorLock 169 -#define OP_CursorUnlock 170 -#define OP_TableLock 171 /* synopsis: iDb=P1 root=P2 write=P3 */ -#define OP_VBegin 172 -#define OP_VCreate 173 -#define OP_VDestroy 174 -#define OP_VOpen 175 -#define OP_VCheck 176 -#define OP_VInitIn 177 /* synopsis: r[P2]=ValueList(P1,P3) */ -#define OP_VColumn 178 /* synopsis: r[P3]=vcolumn(P2) */ -#define OP_VRename 179 -#define OP_Pagecount 180 -#define OP_MaxPgcnt 181 -#define OP_ClrSubtype 182 /* synopsis: r[P1].subtype = 0 */ -#define OP_GetSubtype 183 /* synopsis: r[P2] = r[P1].subtype */ -#define OP_SetSubtype 184 /* synopsis: r[P2].subtype = r[P1] */ -#define OP_FilterAdd 185 /* synopsis: filter(P1) += key(P3@P4) */ -#define OP_Trace 186 -#define OP_CursorHint 187 -#define OP_ReleaseReg 188 /* synopsis: release r[P1@P2] mask P3 */ -#define OP_Noop 189 -#define OP_Explain 190 -#define OP_Abortable 191 +#define OP_OpenEphemeral 119 /* synopsis: nColumn=P2 */ +#define OP_SorterOpen 120 +#define OP_SequenceTest 121 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ +#define OP_OpenPseudo 122 /* synopsis: P3 columns in r[P2] */ +#define OP_Close 123 +#define OP_ColumnsUsed 124 /* synopsis: Cursor P1 uses columns PHEX23 */ +#define OP_SeekScan 125 /* synopsis: Scan-ahead up to P1 rows */ +#define OP_SeekHit 126 /* synopsis: set P2<=seekHit<=P3 */ +#define OP_Sequence 127 /* synopsis: r[P2]=cursor[P1].ctr++ */ +#define OP_NewRowid 128 /* synopsis: r[P2]=rowid */ +#define OP_Insert 129 /* synopsis: intkey=r[P3] data=r[P2] */ +#define OP_RowCell 130 +#define OP_Delete 131 +#define OP_ResetCount 132 +#define OP_SorterCompare 133 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ +#define OP_SorterData 134 /* synopsis: r[P2]=data */ +#define OP_RowData 135 /* synopsis: r[P2]=data */ +#define OP_Rowid 136 /* synopsis: r[P2]=PX rowid of P1 */ +#define OP_NullRow 137 +#define OP_SeekEnd 138 +#define OP_IdxInsert 139 /* synopsis: key=r[P2] */ +#define OP_SorterInsert 140 /* synopsis: key=r[P2] */ +#define OP_IdxDelete 141 /* synopsis: key=r[P2@P5] */ +#define OP_DeferredSeek 142 /* synopsis: Move P3 to P1.rowid if needed */ +#define OP_IdxRowid 143 /* synopsis: r[P2]=rowid */ +#define OP_FinishSeek 144 +#define OP_Destroy 145 +#define OP_Clear 146 +#define OP_ResetSorter 147 +#define OP_CreateBtree 148 /* synopsis: r[P2]=root iDb=P1 flags=P3 */ +#define OP_SqlExec 149 +#define OP_ParseSchema 150 +#define OP_LoadAnalysis 151 +#define OP_DropTable 152 +#define OP_DropIndex 153 +#define OP_Real 154 /* same as TK_FLOAT, synopsis: r[P2]=PDBL13 */ +#define OP_DropTrigger 155 +#define OP_IntegrityCk 156 +#define OP_RowSetAdd 157 /* synopsis: rowset(P1)=r[P2] */ +#define OP_Param 158 +#define OP_FkCounter 159 /* synopsis: fkctr[P1]+=P2 */ +#define OP_MemMax 160 /* synopsis: r[P1]=max(r[P1],r[P2]) */ +#define OP_OffsetLimit 161 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ +#define OP_AggInverse 162 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */ +#define OP_AggStep 163 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggStep1 164 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggValue 165 /* synopsis: r[P3]=value N=P2 */ +#define OP_AggFinal 166 /* synopsis: accum=r[P1] N=P2 */ +#define OP_Expire 167 +#define OP_CursorLock 168 +#define OP_CursorUnlock 169 +#define OP_TableLock 170 /* synopsis: iDb=P1 root=P2 write=P3 */ +#define OP_VBegin 171 +#define OP_VCreate 172 +#define OP_VDestroy 173 +#define OP_VOpen 174 +#define OP_VCheck 175 +#define OP_VInitIn 176 /* synopsis: r[P2]=ValueList(P1,P3) */ +#define OP_VColumn 177 /* synopsis: r[P3]=vcolumn(P2) */ +#define OP_VRename 178 +#define OP_Pagecount 179 +#define OP_MaxPgcnt 180 +#define OP_ClrSubtype 181 /* synopsis: r[P1].subtype = 0 */ +#define OP_GetSubtype 182 /* synopsis: r[P2] = r[P1].subtype */ +#define OP_SetSubtype 183 /* synopsis: r[P2].subtype = r[P1] */ +#define OP_FilterAdd 184 /* synopsis: filter(P1) += key(P3@P4) */ +#define OP_Trace 185 +#define OP_CursorHint 186 +#define OP_ReleaseReg 187 /* synopsis: release r[P1@P2] mask P3 */ +#define OP_Noop 188 +#define OP_Explain 189 +#define OP_Abortable 190 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c @@ -18044,28 +18246,27 @@ typedef struct VdbeOpList VdbeOpList; /* 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, 0x01, 0x41,\ -/* 40 */ 0x41, 0x41, 0x41, 0x26, 0x26, 0x41, 0x41, 0x09,\ -/* 48 */ 0x23, 0x0b, 0x81, 0x03, 0x03, 0x0b, 0x0b, 0x0b,\ -/* 56 */ 0x0b, 0x0b, 0x0b, 0x01, 0x01, 0x03, 0x03, 0x03,\ -/* 64 */ 0x01, 0x41, 0x01, 0x00, 0x00, 0x02, 0x02, 0x08,\ -/* 72 */ 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10,\ -/* 80 */ 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00,\ -/* 88 */ 0x02, 0x02, 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20,\ -/* 96 */ 0x40, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x26,\ +/* 24 */ 0xc9, 0x49, 0x49, 0x49, 0x49, 0xc9, 0x49, 0xc1,\ +/* 32 */ 0x01, 0x41, 0x41, 0xc1, 0x01, 0x01, 0x41, 0x41,\ +/* 40 */ 0x41, 0x41, 0x41, 0x26, 0x26, 0x41, 0x09, 0x23,\ +/* 48 */ 0x0b, 0x81, 0x01, 0x03, 0x03, 0x0b, 0x0b, 0x0b,\ +/* 56 */ 0x0b, 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x03, 0x01,\ +/* 64 */ 0x41, 0x01, 0x00, 0x00, 0x02, 0x02, 0x08, 0x00,\ +/* 72 */ 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10,\ +/* 80 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x02,\ +/* 88 */ 0x02, 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20, 0x40,\ +/* 96 */ 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x40, 0x26,\ /* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\ -/* 112 */ 0x26, 0x40, 0x40, 0x12, 0x00, 0x40, 0x10, 0x40,\ -/* 120 */ 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40,\ -/* 128 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,\ -/* 136 */ 0x00, 0x50, 0x00, 0x40, 0x04, 0x04, 0x00, 0x40,\ -/* 144 */ 0x50, 0x40, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00,\ -/* 152 */ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x10,\ -/* 160 */ 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,\ -/* 176 */ 0x10, 0x50, 0x40, 0x00, 0x10, 0x10, 0x02, 0x12,\ -/* 184 */ 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -} +/* 112 */ 0x26, 0x40, 0x00, 0x12, 0x40, 0x40, 0x10, 0x40,\ +/* 120 */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x10,\ +/* 128 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,\ +/* 136 */ 0x50, 0x00, 0x40, 0x04, 0x04, 0x00, 0x40, 0x50,\ +/* 144 */ 0x40, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\ +/* 152 */ 0x00, 0x00, 0x10, 0x00, 0x00, 0x06, 0x10, 0x00,\ +/* 160 */ 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10,\ +/* 176 */ 0x50, 0x40, 0x00, 0x10, 0x10, 0x02, 0x12, 0x12,\ +/* 184 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,} /* The resolve3P2Values() routine is able to run faster if it knows ** the value of the largest JUMP opcode. The smaller the maximum @@ -18073,7 +18274,7 @@ typedef struct VdbeOpList VdbeOpList; ** generated this include file strives to group all JUMP opcodes ** together near the beginning of the list. */ -#define SQLITE_MX_JUMP_OPCODE 66 /* Maximum JUMP opcode */ +#define SQLITE_MX_JUMP_OPCODE 65 /* Maximum JUMP opcode */ /************** End of opcodes.h *********************************************/ /************** Continuing where we left off in vdbe.h ***********************/ @@ -18097,8 +18298,9 @@ SQLITE_PRIVATE int sqlite3VdbeGoto(Vdbe*,int); SQLITE_PRIVATE int sqlite3VdbeLoadString(Vdbe*,int,const char*); SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe*,int,const char*,...); SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int); +SQLITE_PRIVATE int sqlite3VdbeAddInt64(Vdbe*,int,i64); +SQLITE_PRIVATE int sqlite3VdbeAddDouble(Vdbe*,int,double); SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int); -SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int); SQLITE_PRIVATE int sqlite3VdbeAddFunctionCall(Parse*,int,int,int,int,const FuncDef*,int); SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe*,int); @@ -18190,7 +18392,7 @@ SQLITE_PRIVATE int sqlite3VdbeUsesDoubleQuotedString(Vdbe*,const char*); SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe*,Vdbe*); SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*); SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8); -SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe*, int); +SQLITE_PRIVATE void sqlite3VdbeReprepareOnBind(Vdbe*, int, int); #ifndef SQLITE_OMIT_TRACE SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*); #endif @@ -18349,6 +18551,7 @@ SQLITE_PRIVATE int sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr) */ #ifndef _PCACHE_H_ +#define _PCACHE_H_ typedef struct PgHdr PgHdr; typedef struct PCache PCache; @@ -18571,7 +18774,7 @@ SQLITE_PRIVATE int sqlite3PCacheIsDirty(PCache *pCache); # define SQLITE_MUTEX_OMIT #endif #if SQLITE_THREADSAFE && !defined(SQLITE_MUTEX_NOOP) -# if SQLITE_OS_UNIX +# if SQLITE_OS_UNIX || defined(__CYGWIN__) # define SQLITE_MUTEX_PTHREADS # elif SQLITE_OS_WIN # define SQLITE_MUTEX_W32 @@ -18707,7 +18910,7 @@ struct Schema { ** The number of different kinds of things that can be limited ** using the sqlite3_limit() interface. */ -#define SQLITE_N_LIMIT (SQLITE_LIMIT_PARSER_DEPTH+1) +#define SQLITE_N_LIMIT (SQLITE_LIMIT_TRIGGER_STEPS+1) /* ** Lookaside malloc is a set of fixed-size buffers that can be used @@ -18870,7 +19073,7 @@ struct sqlite3 { struct sqlite3InitInfo { /* Information used during initialization */ Pgno newTnum; /* Rootpage of table being initialized */ u8 iDb; /* Which db file is being initialized */ - u8 busy; /* TRUE if currently initializing */ + u8 busy; /* TRUE if initing. 2 if due to ADD COLUMN */ unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */ unsigned imposterTable : 2; /* Building an imposter table */ unsigned reopenMemdb : 1; /* ATTACH is really a reopen using MemDB */ @@ -19069,7 +19272,7 @@ struct sqlite3 { #define SQLITE_QueryFlattener 0x00000001 /* Query flattening */ #define SQLITE_WindowFunc 0x00000002 /* Use xInverse for window functions */ #define SQLITE_GroupByOrder 0x00000004 /* GROUPBY cover of ORDERBY */ -#define SQLITE_FactorOutConst 0x00000008 /* Constant factoring */ + /* 0x00000008 -- Available for reuse */ #define SQLITE_DistinctOpt 0x00000010 /* DISTINCT using indexes */ #define SQLITE_CoverIdxScan 0x00000020 /* Covering index scans */ #define SQLITE_OrderByIdxJoin 0x00000040 /* ORDER BY of joins via index */ @@ -19078,7 +19281,7 @@ struct sqlite3 { #define SQLITE_CountOfView 0x00000200 /* The count-of-view optimization */ #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 */ + /* TH3 expects this value ^^^^^^^^^^ */ #define SQLITE_PushDown 0x00001000 /* WHERE-clause push-down opt */ #define SQLITE_SimplifyJoin 0x00002000 /* Convert LEFT JOIN to JOIN */ #define SQLITE_SkipScan 0x00004000 /* Skip-scans */ @@ -19086,13 +19289,14 @@ struct sqlite3 { #define SQLITE_MinMaxOpt 0x00010000 /* The min/max optimization */ #define SQLITE_SeekScan 0x00020000 /* The OP_SeekScan optimization */ #define SQLITE_OmitOrderBy 0x00040000 /* Omit pointless ORDER BY */ - /* TH3 expects this value ^^^^^^^^^^ to be 0x40000. Coordinate any change */ -#define SQLITE_BloomFilter 0x00080000 /* Use a Bloom filter on searches */ -#define SQLITE_BloomPulldown 0x00100000 /* Run Bloom filters early */ + /* TH3 expects this value ^^^^^^^^^^ */ +#define SQLITE_BloomFilter 0x00080000 /* Use a Bloom filters */ + /* TH3 expects this value ^^^^^^^^^^ */ + /* 0x00100000 -- Available for reuse */ #define SQLITE_BalancedMerge 0x00200000 /* Balance multi-way merges */ #define SQLITE_ReleaseReg 0x00400000 /* Use OP_ReleaseReg for testing */ #define SQLITE_FlttnUnionAll 0x00800000 /* Disable the UNION ALL flattener */ - /* TH3 expects this value ^^^^^^^^^^ See flatten04.test */ + /* TH3 expects this value ^^^^^^^^^^ */ #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 */ @@ -19100,6 +19304,7 @@ struct sqlite3 { #define SQLITE_OrderBySubq 0x10000000 /* ORDER BY in subquery helps outer */ #define SQLITE_StarQuery 0x20000000 /* Heurists for star queries */ #define SQLITE_ExistsToJoin 0x40000000 /* The EXISTS-to-JOIN optimization */ +#define SQLITE_UnionLimit 0x80000000 /* Optimizations for UNION + LIMIT */ #define SQLITE_AllOpts 0xffffffff /* All optimizations */ /* @@ -21026,6 +21231,13 @@ struct ParseCleanup { void (*xCleanup)(sqlite3*,void*); /* Deallocation routine */ }; +/* +** Number of 64-bit entried in the variable number bitmap cache (VNBMC). +*/ +#ifndef SQLITE_VNBMC +# define SQLITE_VNBMC 2 +#endif + /* ** An SQL parser context. A copy of this structure is passed through ** the parser and down into all the parser action routine in order to @@ -21074,12 +21286,12 @@ struct Parse { bft bHasWith :1; /* True if statement contains WITH */ bft okConstFactor:1; /* OK to factor out constants */ bft checkSchema :1; /* Causes schema cookie check after an error */ + bft usesAinc :1; /* True if pAinc is valid */ int nRangeReg; /* Size of the temporary register block */ int iRangeReg; /* First register in temporary register block */ int nErr; /* Number of errors seen */ int nTab; /* Number of previously allocated VDBE cursors */ int nMem; /* Number of memory cells used so far */ - int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */ int iSelfTab; /* Table associated with an index on expr, or negative ** of the base register during check-constraint eval */ int nNestSel; /* Number of nested SELECT statements and/or VIEWs */ @@ -21098,9 +21310,7 @@ struct Parse { #endif #ifndef SQLITE_OMIT_SHARED_CACHE int nTableLock; /* Number of locks in aTableLock */ - TableLock *aTableLock; /* Required table locks for shared-cache mode */ #endif - AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */ Parse *pToplevel; /* Parse structure for main program (or NULL) */ Table *pTriggerTab; /* Table triggers are being coded for */ TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ @@ -21129,6 +21339,13 @@ struct Parse { Returning *pReturning; /* The RETURNING clause */ } d; } u1; + AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters. Only + ** valid if Parse.usesAinc is true */ +#ifndef SQLITE_OMIT_SHARED_CACHE + TableLock *aTableLock; /* Required table locks for shared-cache mode. Only + ** valid if Parse.nTableLock>0 */ +#endif + /************************************************************************ ** Above is constant between recursions. Below is reset before and after @@ -21139,6 +21356,7 @@ struct Parse { Token sLastToken; /* The last token parsed */ ynVar nVar; /* Number of '?' variables seen in the SQL so far */ + u64 aVnbmc[SQLITE_VNBMC]; /* Varible Number Bitmap Cache */ u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */ u8 explain; /* True if the EXPLAIN flag is found on the query */ u8 eParseMode; /* PARSE_MODE_XXX constant */ @@ -21422,7 +21640,7 @@ typedef struct { #define INITFLAG_AlterRename 0x0001 /* Reparse after a RENAME */ #define INITFLAG_AlterDrop 0x0002 /* Reparse after a DROP COLUMN */ #define INITFLAG_AlterAdd 0x0003 /* Reparse after an ADD COLUMN */ -#define INITFLAG_AlterDropCons 0x0004 /* Reparse after an ADD COLUMN */ +#define INITFLAG_AlterDropCons 0x0004 /* Reparse after a DROP CONSTRAINT */ /* Tuning parameters are set using SQLITE_TESTCTRL_TUNE and are controlled ** on debug-builds of the CLI using ".testctrl tune ID VALUE". Tuning @@ -21783,6 +22001,57 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprLis /* ** Assuming zIn points to the first byte of a UTF-8 character, ** advance zIn to point to the first byte of the next UTF-8 character. +** +** # Dividing malformed UTF-8 into characters (tag-20260418-01) +** +** If a text input is malformed UTF-8, SQLite does not make any guarantees +** about how the bytes are divided up into characters. The system promises +** to not overflow an array or cause other memory errors when presented +** with malformed UTF-8. And it promises to preserve the specific +** sequence of bytes as long as no conversion occur. But beyond that, +** there are no guarantees. Results can vary from one version to the +** next. +** +** The SQLITE_SKIP_UTF8 macro below is one technique for dividing UTF-8 +** into characters. The length() and substr() SQL functions use a +** different technique when searching across multiple characters, a +** technique that exchanges a subtraction for comparison of z and results +** in faster machine code on some compilers and architectures. The code +** in substr() to skip over p1 characters goes something like this: +** +** for( ; p1>0; p1--){ +** // vvvv--- tag-20260418-01 +** if( (u8)(z[0]-1)<(0x80-1) ){ +** z++; +** }else if( z[0]==0 ){ +** break; +** }else{ +** do{ z++; }while( (z[0]&0xc0)==0x80 ); +** } +** } +** +** In valid UTF-8, multibyte characters always begin with a byte with the +** two most significant bits set and that is followed by one or more bytes +** for which the two most significant bits are 10. In other words: +** +** First byte: (BYTE & 0xc0)==0xc0 +** Following bytes: (BYTE & 0xc0)==0x80 +** +** What to do if the input byte sequence contain a "following byte" that +** is not preceded by a "first byte"? How many characters are in the +** byte sequence: 0x61 0x81 0x82 0x7a? 3 or 4 or something else? +** +** If you use the macro below, the answer will be 4. If you use the code +** snippet demonstrated at tag-20260418-01, then answer is 3. If you +** use a variant of tag-20260418-01 where the constant of comparison is +** 0xc0-1 instead of 0x80-1 then the answer is again 4. The key point is +** that because the input is malformed UTF-8, so is no "correct" answer. +** SQLite is free to use either value. +** +** It turns out that GCC 13.3.0 is able to generate faster code (at least +** on x86-64) if the constant at tag-20260418-01 is (0x80-1). If you make +** that constant (0xc0-1) instead, gcc 13.3.0 generates code that runs slower. +** So the (0x80-1) constant is used for substr() and length(). */ #define SQLITE_SKIP_UTF8(zIn) { \ if( (*(zIn++))>=0xc0 ){ \ @@ -22025,6 +22294,7 @@ SQLITE_PRIVATE void sqlite3DebugPrintf(const char*, ...); #endif #if defined(SQLITE_TEST) SQLITE_PRIVATE void *sqlite3TestTextToPtr(const char*); +SQLITE_PRIVATE const char *sqlite3TestPtrToText(void*); #endif #if defined(SQLITE_DEBUG) @@ -22126,6 +22396,7 @@ 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 int sqlite3ExprCanReturnSubtype(Parse*,Expr*); SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*); SQLITE_PRIVATE int sqlite3IndexHasDuplicateRootPage(Index*); SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**); @@ -22141,6 +22412,7 @@ SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3*); SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3*); SQLITE_PRIVATE void sqlite3ColumnSetExpr(Parse*,Table*,Column*,Expr*); SQLITE_PRIVATE Expr *sqlite3ColumnExpr(Table*,Column*); +SQLITE_PRIVATE Expr *sqlite3ColumnExprAuth(Table*,Column*,Parse*); SQLITE_PRIVATE void sqlite3ColumnSetColl(sqlite3*,Column*,const char*zColl); SQLITE_PRIVATE const char *sqlite3ColumnColl(Column*); SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*); @@ -22249,6 +22521,7 @@ SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*); SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3*, OnOrUsing*); SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3*, SrcList*); SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,int,int,char**); +SQLITE_PRIVATE int sqlite3IndexBloomable(const Index*,int); SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, Expr*, int, int, u8); SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int); @@ -22349,10 +22622,11 @@ SQLITE_PRIVATE int sqlite3ExprIsConstant(Parse*,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 sqlite3ExprListIsConstant(Parse *pParse, ExprList *pList, int bNoIs); #ifdef SQLITE_ENABLE_CURSOR_HINTS SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*); #endif -SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr*, int*, Parse*); +SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr*, int*, Parse*, int); SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*); SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); SQLITE_PRIVATE int sqlite3ExprIsLikeOperator(const Expr*); @@ -22504,6 +22778,7 @@ SQLITE_PRIVATE int sqlite3VListNameToNum(VList*,const char*,int); */ SQLITE_PRIVATE int sqlite3PutVarint(unsigned char*, u64); SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *, u64 *); +SQLITE_PRIVATE i64 sqlite3VarintValue(const unsigned char*); SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *, u32 *); SQLITE_PRIVATE int sqlite3VarintLen(u64 v); @@ -22519,9 +22794,6 @@ SQLITE_PRIVATE int sqlite3VarintLen(u64 v); #define putVarint32(A,B) \ (u8)(((u32)(B)<(u32)0x80)?(*(A)=(unsigned char)(B)),1:\ sqlite3PutVarint((A),(B))) -#define getVarint sqlite3GetVarint -#define putVarint sqlite3PutVarint - SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*); SQLITE_PRIVATE char *sqlite3TableAffinityStr(sqlite3*,const Table*); @@ -22557,14 +22829,23 @@ SQLITE_PRIVATE int sqlite3IsMemdb(const sqlite3_vfs*); SQLITE_PRIVATE const char *sqlite3ErrStr(int); SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse); SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); +SQLITE_PRIVATE int sqlite3BinaryCompare(void*,int,const void*,int,const void*); +#if SQLITE_USES_INLINE +static SQLITE_INLINE int sqlite3IsBinary(const CollSeq *p){ + assert( p==0 || p->xCmp!=sqlite3BinaryCompare + || strcmp(p->zName,"BINARY")==0 ); + return p==0 || p->xCmp==sqlite3BinaryCompare; +} +#else SQLITE_PRIVATE int sqlite3IsBinary(const CollSeq*); +#endif SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8); SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr); SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr); SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse*,const Expr*,const Expr*); -SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(const Parse *pParse, Expr*, const Token*, int); -SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(const Parse*,Expr*,const char*); +SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int); +SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*); SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr*); SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *); @@ -22611,6 +22892,7 @@ SQLITE_PRIVATE const unsigned char *sqlite3aGTb; SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[]; SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config; SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions; +SQLITE_PRIVATE const sqlite3_str sqlite3OomStr; #ifndef SQLITE_OMIT_WSD SQLITE_PRIVATE int sqlite3PendingByte; #endif @@ -22713,7 +22995,6 @@ SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum*, i64); SQLITE_PRIVATE int sqlite3StrAccumEnlargeIfNeeded(StrAccum*, i64); SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*); SQLITE_PRIVATE void sqlite3StrAccumSetError(StrAccum*, u8); -SQLITE_PRIVATE void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*); SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest*,int,int); SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int); SQLITE_PRIVATE void sqlite3RecordErrorByteOffset(sqlite3*,const char*); @@ -22806,10 +23087,12 @@ SQLITE_PRIVATE int sqlite3ReadOnlyShadowTables(sqlite3 *db); SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName); SQLITE_PRIVATE int sqlite3IsShadowTableOf(sqlite3*,Table*,const char*); SQLITE_PRIVATE void sqlite3MarkAllShadowTablesOf(sqlite3*, Table*); +SQLITE_PRIVATE void sqlite3VtabEponymousTableClearAll(sqlite3*); #else # define sqlite3ShadowTableName(A,B) 0 # define sqlite3IsShadowTableOf(A,B,C) 0 # define sqlite3MarkAllShadowTablesOf(A,B) +# define sqlite3VtabEponymousTableClearAll(X) #endif SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse*,Module*); SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3*,Module*); @@ -22964,6 +23247,10 @@ SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse*, int); SQLITE_PRIVATE void sqlite3ExprSetErrorOffset(Expr*,int); SQLITE_PRIVATE u32 sqlite3Get4byte(const u8*); +SQLITE_PRIVATE SQLITE_OPT_INLINE u64 sqlite3Get8byte(const u8*); +#if SQLITE_BYTEORDER!=4321 +SQLITE_PRIVATE SQLITE_OPT_INLINE u64 sqlite3BSwap64(u64); +#endif SQLITE_PRIVATE void sqlite3Put4byte(u8*, u32); #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY @@ -23661,6 +23948,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_MAX_PAGE_SIZE "MAX_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_SIZE), #endif +#ifdef SQLITE_MAX_SCHEMA + "MAX_SCHEMA=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA), +#endif #ifdef SQLITE_MAX_SCHEMA_RETRY "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY), #endif @@ -24312,6 +24602,16 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { */ SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions; +/* +** This singleton is an sqlite3_str object that is returned if +** sqlite3_malloc() fails to provide space for a real one. This +** sqlite3_str object accepts no new text and always returns +** an SQLITE_NOMEM error. +*/ +SQLITE_PRIVATE const sqlite3_str sqlite3OomStr = { + 0, 0, 0, 0, 0, SQLITE_NOMEM, 0 +}; + #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) /* ** Counter used for coverage testing. Does not come into play for @@ -24945,7 +25245,9 @@ struct Vdbe { VdbeFrame *pFrame; /* Parent frame */ VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */ int nFrame; /* Number of frames in pFrame list */ - u32 expmask; /* Binding to these vars invalidates VM */ + u32 expmask; /* Binding to these vars might invalidate VM */ + u32 smimask; /* Only invalid if changing to/from small integer */ + /* Note: smimask is always a subset of expmask */ SubProgram *pProgram; /* Linked list of all sub-programs used by VM */ AuxData *pAuxData; /* Linked list of auxdata allocations */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS @@ -25013,6 +25315,17 @@ struct ValueList { SQLITE_PRIVATE const u8 sqlite3SmallTypeSizes[]; #endif +/* Input "x" is a sequence of unsigned characters that represent a +** big-endian integer. Return the equivalent native integer +*/ +#define ONE_BYTE_INT(x) ((i8)(x)[0]) +#define TWO_BYTE_INT(x) (256*(i8)((x)[0])|(x)[1]) +#define THREE_BYTE_INT(x) (65536*(i8)((x)[0])|((x)[1]<<8)|(x)[2]) +#define FOUR_BYTE_UINT(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) +#define FOUR_BYTE_U64(x) (((u64)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) +#define FOUR_BYTE_INT(x) ((int)FOUR_BYTE_UINT(x)) +#define SIX_BYTE_INT(x) (FOUR_BYTE_UINT(x+2)+4294967296LL*TWO_BYTE_INT(x)) + /* ** Function prototypes */ @@ -25847,6 +26160,7 @@ static int parseHhMmSs(const char *zDate, DateTime *p){ }else{ s = 0; } + if( h==24 && (m!=0 || s!=0 || ms!=0.0) ) return 1; p->validJD = 0; p->rawS = 0; p->validHMS = 1; @@ -25883,6 +26197,10 @@ static void computeJD(DateTime *p){ Y = 2000; /* If no YMD specified, assume 2000-Jan-01 */ M = 1; D = 1; + if( p->validHMS && p->h==24 ){ + p->h = 0; + D = 2; + } } if( Y<-4713 || Y>9999 || p->rawS ){ datetimeError(p); @@ -25921,6 +26239,10 @@ 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->validHMS && p->h==24 ){ + p->h = 0; + p->D++; + } if( p->D<=28 ){ p->nFloor = 0; }else if( (1<M) & 0x15aa ){ @@ -26381,6 +26703,49 @@ static int parseModifier( } break; } + case 'e': { + /* + ** end of day + ** end of month + ** end of year + ** + ** Move the date forwards to the last millisecond of the current + ** day, month or year. + */ + if( sqlite3_strnicmp(z, "end of ", 7)!=0 ){ + break; + } + if( !p->validJD && !p->validYMD && !p->validHMS ) break; + z += 7; + computeYMD(p); + p->validHMS = 1; + p->h = 23; + p->m = 59; + p->s = 59.999; + p->rawS = 0; + p->tz = 0; + p->validJD = 0; + if( sqlite3_stricmp(z,"month")==0 ){ + p->D = 1; + p->M++; + if( p->M>12 ){ + p->Y++; + p->M = 1; + } + computeFloor(p); + computeJD(p); + p->iJD -= (p->nFloor+1)*86400000; + clearYMD_HMS_TZ(p); + rc = 0; + }else if( sqlite3_stricmp(z,"year")==0 ){ + p->M = 12; + p->D = 31; + rc = 0; + }else if( sqlite3_stricmp(z,"day")==0 ){ + rc = 0; + } + break; + } case 'f': { /* ** floor @@ -26483,22 +26848,30 @@ static int parseModifier( case 'w': { /* ** weekday N + ** weekday -N ** - ** Move the date to the same time on the next occurrence of - ** weekday N where 0==Sunday, 1==Monday, and so forth. If the - ** date is already on the appropriate weekday, this is a no-op. + ** Move the date forward (for N>=0) or backward (for N<=-0) to the + ** same time on the next/previous occurrence of weekday abs(N) + ** where 0==Sunday, 1==Monday, and so forth. If the date is already + ** on the appropriate weekday, this is a no-op. */ if( sqlite3_strnicmp(z, "weekday ", 8)==0 - && sqlite3AtoF(&z[8], &r)>0 - && r>=0.0 && r<7.0 && (n=(int)r)==r ){ + && sqlite3AtoF(&z[8], &r)>0 + && r>=-6.0 && r<=6.0 + && sqlite3RealSameAsInt(r,(i64)(n=(int)r)) + ){ sqlite3_int64 Z; computeYMD_HMS(p); p->tz = 0; p->validJD = 0; computeJD(p); Z = ((p->iJD + 129600000)/86400000) % 7; - if( Z>n ) Z -= 7; - p->iJD += (n - Z)*86400000; + if( n<0 ) n = -n; + if( Z!=n ){ + if( Z>n ) Z -= 7; + p->iJD += (n - Z)*86400000; + if( strchr(z+8,'-')!=0 ) p->iJD -= 7*86400000; + } clearYMD_HMS_TZ(p); rc = 0; } @@ -26506,7 +26879,9 @@ static int parseModifier( } case 's': { /* - ** start of TTTTT + ** start of day + ** start of month + ** start of year ** ** Move the date backwards to the beginning of the current day, ** or month or year. @@ -27030,38 +27405,38 @@ static void strftimeFunc( size_t i,j; sqlite3 *db; const char *zFmt; - sqlite3_str sRes; + sqlite3_str *pRes; if( argc==0 ) return; zFmt = (const char*)sqlite3_value_text(argv[0]); if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return; db = sqlite3_context_db_handle(context); - sqlite3StrAccumInit(&sRes, 0, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); + pRes = sqlite3_str_new(db); 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); + sqlite3_str_appendf(pRes, "%06.3f", s); break; } case 'F': { - sqlite3_str_appendf(&sRes, "%04d-%02d-%02d", x.Y, x.M, x.D); + sqlite3_str_appendf(pRes, "%04d-%02d-%02d", x.Y, x.M, x.D); break; } case 'G': /* Fall thru */ @@ -27073,15 +27448,15 @@ static void strftimeFunc( y.validYMD = 0; computeYMD(&y); if( cf=='g' ){ - sqlite3_str_appendf(&sRes, "%02d", y.Y%100); + sqlite3_str_appendf(pRes, "%02d", y.Y%100); }else{ - sqlite3_str_appendf(&sRes, "%04d", y.Y); + sqlite3_str_appendf(pRes, "%04d", y.Y); } break; } case 'H': case 'k': { - sqlite3_str_appendf(&sRes, cf=='H' ? "%02d" : "%2d", x.h); + sqlite3_str_appendf(pRes, cf=='H' ? "%02d" : "%2d", x.h); break; } case 'I': /* Fall thru */ @@ -27089,65 +27464,65 @@ static void strftimeFunc( int h = x.h; if( h>12 ) h -= 12; if( h==0 ) h = 12; - sqlite3_str_appendf(&sRes, cf=='I' ? "%02d" : "%2d", h); + sqlite3_str_appendf(pRes, 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); + sqlite3_str_appendf(pRes,"%03d",daysAfterJan01(&x)+1); break; } case 'J': { /* Julian day number. (Non-standard) */ - sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0); + sqlite3_str_appendf(pRes,"%.16g",x.iJD/86400000.0); break; } case 'm': { - sqlite3_str_appendf(&sRes,"%02d",x.M); + sqlite3_str_appendf(pRes,"%02d",x.M); break; } case 'M': { - sqlite3_str_appendf(&sRes,"%02d",x.m); + sqlite3_str_appendf(pRes,"%02d",x.m); break; } case 'p': /* Fall thru */ case 'P': { if( x.h>=12 ){ - sqlite3_str_append(&sRes, cf=='p' ? "PM" : "pm", 2); + sqlite3_str_append(pRes, cf=='p' ? "PM" : "pm", 2); }else{ - sqlite3_str_append(&sRes, cf=='p' ? "AM" : "am", 2); + sqlite3_str_append(pRes, cf=='p' ? "AM" : "am", 2); } break; } case 'R': { - sqlite3_str_appendf(&sRes, "%02d:%02d", x.h, x.m); + sqlite3_str_appendf(pRes, "%02d:%02d", x.h, x.m); break; } case 's': { if( x.useSubsec ){ - sqlite3_str_appendf(&sRes,"%.3f", + sqlite3_str_appendf(pRes,"%.3f", (x.iJD - 21086676*(i64)10000000)/1000.0); }else{ i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000); - sqlite3_str_appendf(&sRes,"%lld",iS); + sqlite3_str_appendf(pRes,"%lld",iS); } break; } case 'S': { - sqlite3_str_appendf(&sRes,"%02d",(int)x.s); + sqlite3_str_appendf(pRes,"%02d",(int)x.s); break; } case 'T': { - sqlite3_str_appendf(&sRes,"%02d:%02d:%02d", x.h, x.m, (int)x.s); + sqlite3_str_appendf(pRes,"%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); + sqlite3_str_appendchar(pRes, 1, c); break; } case 'U': { /* Week num. 00-53. First Sun of the year is week 01 */ - sqlite3_str_appendf(&sRes,"%02d", + sqlite3_str_appendf(pRes,"%02d", (daysAfterJan01(&x)-daysAfterSunday(&x)+7)/7); break; } @@ -27158,30 +27533,30 @@ static void strftimeFunc( y.iJD += (3 - daysAfterMonday(&x))*86400000; y.validYMD = 0; computeYMD(&y); - sqlite3_str_appendf(&sRes,"%02d", daysAfterJan01(&y)/7+1); + sqlite3_str_appendf(pRes,"%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", + sqlite3_str_appendf(pRes,"%02d", (daysAfterJan01(&x)-daysAfterMonday(&x)+7)/7); break; } case 'Y': { - sqlite3_str_appendf(&sRes,"%04d",x.Y); + sqlite3_str_appendf(pRes,"%04d",x.Y); break; } case '%': { - sqlite3_str_appendchar(&sRes, 1, '%'); + sqlite3_str_appendchar(pRes, 1, '%'); break; } default: { - sqlite3_str_reset(&sRes); + sqlite3_str_free(pRes); return; } } } - if( j0 +# define ALIGN128 __attribute__((aligned(128))) +#else +# define ALIGN128 +#endif + /* -** Each recursive mutex is an instance of the following structure. +** Each SQLite mutex is an instance of the following structure. +** */ struct sqlite3_mutex { pthread_mutex_t mutex; /* Mutex controlling the lock */ @@ -30905,19 +31287,31 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; } ** the same type number. */ static sqlite3_mutex *pthreadMutexAlloc(int iType){ - static sqlite3_mutex staticMutexes[] = { - SQLITE3_MUTEX_INITIALIZER(2), - SQLITE3_MUTEX_INITIALIZER(3), - SQLITE3_MUTEX_INITIALIZER(4), - SQLITE3_MUTEX_INITIALIZER(5), - SQLITE3_MUTEX_INITIALIZER(6), - SQLITE3_MUTEX_INITIALIZER(7), - SQLITE3_MUTEX_INITIALIZER(8), - SQLITE3_MUTEX_INITIALIZER(9), - SQLITE3_MUTEX_INITIALIZER(10), - SQLITE3_MUTEX_INITIALIZER(11), - SQLITE3_MUTEX_INITIALIZER(12), - SQLITE3_MUTEX_INITIALIZER(13) + /* Static mutexes - those with IDs of 2 or more... + ** + ** The ALIGN128 macro attempts to force 128-byte alignment on mutexes, + ** so that adjacent mutex objects are always on different cache lines + ** in the CPU. This is CPU-dependent, of course, but 128-byte alignment + ** seems to work well for all contemporary processors. Experiments show + ** that 64 works just as well most of the time, but the internet says + ** that 128-byte alignment works better. + */ + static ALIGN128 union staticMutex { + sqlite3_mutex m; + char aSpacer[128]; + } aMutex[] = { + { .m = SQLITE3_MUTEX_INITIALIZER(2) }, + { .m = SQLITE3_MUTEX_INITIALIZER(3) }, + { .m = SQLITE3_MUTEX_INITIALIZER(4) }, + { .m = SQLITE3_MUTEX_INITIALIZER(5) }, + { .m = SQLITE3_MUTEX_INITIALIZER(6) }, + { .m = SQLITE3_MUTEX_INITIALIZER(7) }, + { .m = SQLITE3_MUTEX_INITIALIZER(8) }, + { .m = SQLITE3_MUTEX_INITIALIZER(9) }, + { .m = SQLITE3_MUTEX_INITIALIZER(10) }, + { .m = SQLITE3_MUTEX_INITIALIZER(11) }, + { .m = SQLITE3_MUTEX_INITIALIZER(12) }, + { .m = SQLITE3_MUTEX_INITIALIZER(13) }, }; sqlite3_mutex *p; switch( iType ){ @@ -30954,12 +31348,12 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){ } default: { #ifdef SQLITE_ENABLE_API_ARMOR - if( iType-2<0 || iType-2>=ArraySize(staticMutexes) ){ + if( iType-2<0 || iType-2>=ArraySize(aMutex) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif - p = &staticMutexes[iType-2]; + p = &aMutex[iType-2].m; break; } } @@ -31204,53 +31598,11 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ # include /* amalgamator: dontcache */ #endif -/* -** Determine if we are dealing with Windows NT. -** -** We ought to be able to determine if we are compiling for Windows 9x or -** Windows NT using the _WIN32_WINNT macro as follows: -** -** #if defined(_WIN32_WINNT) -** # define SQLITE_OS_WINNT 1 -** #else -** # define SQLITE_OS_WINNT 0 -** #endif -** -** However, Visual Studio 2005 does not set _WIN32_WINNT by default, as -** it ought to, so the above test does not work. We'll just assume that -** everything is Windows NT unless the programmer explicitly says otherwise -** by setting SQLITE_OS_WINNT to 0. -*/ -#if SQLITE_OS_WIN && !defined(SQLITE_OS_WINNT) -# define SQLITE_OS_WINNT 1 -#endif - -/* -** Determine if we are dealing with Windows CE - which has a much reduced -** API. -*/ -#if defined(_WIN32_WCE) -# define SQLITE_OS_WINCE 1 -#else -# define SQLITE_OS_WINCE 0 -#endif - -/* -** For WinCE, some API function parameters do not appear to be declared as -** volatile. -*/ -#if SQLITE_OS_WINCE -# define SQLITE_WIN32_VOLATILE -#else -# define SQLITE_WIN32_VOLATILE volatile -#endif - /* ** For some Windows sub-platforms, the _beginthreadex() / _endthreadex() ** functions are not available (e.g. those not using MSVC, Cygwin, etc). */ -#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && \ - SQLITE_THREADSAFE>0 && !defined(__CYGWIN__) +#if SQLITE_OS_WIN && SQLITE_THREADSAFE>0 && !defined(__CYGWIN__) # define SQLITE_OS_WIN_THREADS 1 #else # define SQLITE_OS_WIN_THREADS 0 @@ -31268,11 +31620,32 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ */ #ifdef SQLITE_MUTEX_W32 +#if MSVC_VERSION>0 +# define ALIGN128 __declspec(align(128)) +#else +# define ALIGN128 +#endif + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4324) +#endif /* _MSC_VER */ + /* -** Each recursive mutex is an instance of the following structure. +** Each SQLite mutex is an instance of the following structure. +** +** The ALIGN128 macro attempts to force 128-byte alignment on mutexes, +** so that adjacent mutex objects are always on different cache lines +** in the CPU. This is CPU-dependent, of course, but 128-byte alignment +** seems to work well for all contemporary processors. Experiments show +** that 64 works just as well most of the time, but the internet says +** that 128-byte alignment works better. */ struct sqlite3_mutex { - CRITICAL_SECTION mutex; /* Mutex controlling the lock */ + union { + CRITICAL_SECTION cs; /* The CRITICAL_SECTION mutex. id==1 */ + SRWLOCK srwl; /* The Slim reader/writer lock. id!=1 */ + } u; int id; /* Mutex type */ #ifdef SQLITE_DEBUG volatile int nRef; /* Number of entrances */ @@ -31280,20 +31653,9 @@ struct sqlite3_mutex { volatile LONG trace; /* True to trace changes */ #endif }; - -/* -** These are the initializer values used when declaring a "static" mutex -** on Win32. It should be noted that all mutexes require initialization -** on the Win32 platform. -*/ -#define SQLITE_W32_MUTEX_INITIALIZER { 0 } - -#ifdef SQLITE_DEBUG -#define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id, \ - 0L, (DWORD)0, 0 } -#else -#define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id } -#endif +#ifdef _MSC_VER +#pragma warning(pop) +#endif /* _MSC_VER */ #ifdef SQLITE_DEBUG /* @@ -31304,13 +31666,8 @@ static int winMutexHeld(sqlite3_mutex *p){ return p->nRef!=0 && p->owner==GetCurrentThreadId(); } -static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){ - return p->nRef==0 || p->owner!=tid; -} - static int winMutexNotheld(sqlite3_mutex *p){ - DWORD tid = GetCurrentThreadId(); - return winMutexNotheld2(p, tid); + return p->nRef==0 || p->owner!=GetCurrentThreadId(); } #endif @@ -31332,41 +31689,42 @@ SQLITE_PRIVATE void sqlite3MemoryBarrier(void){ } /* -** Initialize and deinitialize the mutex subsystem. +** Static mutexes. +** +** The ALIGN128 macro on the static mutex array forces 128-byte alignment +** on the mutexes so that adjacent mutex objects are always on different +** cache lines in the CPU. This is CPU-dependent, of course, but 128-byte +** alignment seems to work well for all contemporary processors. +** Experiments show that 64 works just as well most of the time, but +** the internet says that 128-byte alignment works better. */ -static sqlite3_mutex winMutex_staticMutexes[] = { - SQLITE3_MUTEX_INITIALIZER(2), - SQLITE3_MUTEX_INITIALIZER(3), - SQLITE3_MUTEX_INITIALIZER(4), - SQLITE3_MUTEX_INITIALIZER(5), - SQLITE3_MUTEX_INITIALIZER(6), - SQLITE3_MUTEX_INITIALIZER(7), - SQLITE3_MUTEX_INITIALIZER(8), - SQLITE3_MUTEX_INITIALIZER(9), - SQLITE3_MUTEX_INITIALIZER(10), - SQLITE3_MUTEX_INITIALIZER(11), - SQLITE3_MUTEX_INITIALIZER(12), - SQLITE3_MUTEX_INITIALIZER(13) -}; - +static ALIGN128 union staticMutexes { + sqlite3_mutex m; + char spacer[128]; +} aWindowsMutex[12]; static int winMutex_isInit = 0; -static int winMutex_isNt = -1; /* <0 means "need to query" */ /* As the winMutexInit() and winMutexEnd() functions are called as part ** of the sqlite3_initialize() and sqlite3_shutdown() processing, the ** "interlocked" magic used here is probably not strictly necessary. */ -static LONG SQLITE_WIN32_VOLATILE winMutex_lock = 0; +static LONG volatile winMutex_lock = 0; -SQLITE_API int sqlite3_win32_is_nt(void); /* os_win.c */ SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */ static int winMutexInit(void){ /* The first to increment to 1 does actual initialization */ if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){ int i; - for(i=0; iid = i+2; + InitializeSRWLock(&p->u.srwl); +#ifdef SQLITE_DEBUG + p->nRef = 0; + p->owner = 0; + p->trace = 0; +#endif } winMutex_isInit = 1; }else{ @@ -31384,10 +31742,6 @@ static int winMutexEnd(void){ ** (which should be the last to shutdown.) */ if( InterlockedCompareExchange(&winMutex_lock, 0, 1)==1 ){ if( winMutex_isInit==1 ){ - int i; - for(i=0; itrace = 1; #endif #endif - InitializeCriticalSection(&p->mutex); + if( iType==SQLITE_MUTEX_RECURSIVE ){ + InitializeCriticalSection(&p->u.cs); + }else{ + InitializeSRWLock(&p->u.srwl); + } } break; } default: { #ifdef SQLITE_ENABLE_API_ARMOR - if( iType-2<0 || iType-2>=ArraySize(winMutex_staticMutexes) ){ + if( iType-2<0 || iType-2>=ArraySize(aWindowsMutex) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif - p = &winMutex_staticMutexes[iType-2]; + p = &aWindowsMutex[iType-2].m; #ifdef SQLITE_DEBUG #ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC InterlockedCompareExchange(&p->trace, 1, 0); @@ -31489,8 +31847,10 @@ static sqlite3_mutex *winMutexAlloc(int iType){ static void winMutexFree(sqlite3_mutex *p){ assert( p ); assert( p->nRef==0 && p->owner==0 ); - if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ){ - DeleteCriticalSection(&p->mutex); + if( p->id==SQLITE_MUTEX_FAST ){ + sqlite3_free(p); + }else if( p->id==SQLITE_MUTEX_RECURSIVE ){ + DeleteCriticalSection(&p->u.cs); sqlite3_free(p); }else{ #ifdef SQLITE_ENABLE_API_ARMOR @@ -31511,67 +31871,56 @@ static void winMutexFree(sqlite3_mutex *p){ ** more than once, the behavior is undefined. */ static void winMutexEnter(sqlite3_mutex *p){ -#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) - DWORD tid = GetCurrentThreadId(); -#endif -#ifdef SQLITE_DEBUG - assert( p ); - assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) ); -#else assert( p ); +#ifdef SQLITE_DEBUG + assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld(p) ); #endif assert( winMutex_isInit==1 ); - EnterCriticalSection(&p->mutex); + if( p->id==SQLITE_MUTEX_RECURSIVE ){ + EnterCriticalSection(&p->u.cs); + }else{ + AcquireSRWLockExclusive(&p->u.srwl); + } #ifdef SQLITE_DEBUG assert( p->nRef>0 || p->owner==0 ); - p->owner = tid; + p->owner = GetCurrentThreadId(); p->nRef++; if( p->trace ){ OSTRACE(("ENTER-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n", - tid, p->id, p, p->trace, p->nRef)); + GetCurrentThreadId(), p->id, p, p->trace, p->nRef)); } #endif } static int winMutexTry(sqlite3_mutex *p){ -#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) - DWORD tid = GetCurrentThreadId(); -#endif int rc = SQLITE_BUSY; assert( p ); - assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) ); + assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld(p) ); /* - ** The sqlite3_mutex_try() routine is very rarely used, and when it - ** is used it is merely an optimization. So it is OK for it to always + ** The sqlite3_mutex_try() routine is seldom used, and when it is + ** used it is merely an optimization. So it is OK for it to always ** fail. - ** - ** The TryEnterCriticalSection() interface is only available on WinNT. - ** And some windows compilers complain if you try to use it without - ** first doing some #defines that prevent SQLite from building on Win98. - ** For that reason, we will omit this optimization for now. See - ** ticket #2685. */ -#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400 - assert( winMutex_isInit==1 ); - assert( winMutex_isNt>=-1 && winMutex_isNt<=1 ); - if( winMutex_isNt<0 ){ - winMutex_isNt = sqlite3_win32_is_nt(); + if( p->id==SQLITE_MUTEX_RECURSIVE ){ + rc = TryEnterCriticalSection(&p->u.cs); + }else{ + rc = TryAcquireSRWLockExclusive(&p->u.srwl); } - assert( winMutex_isNt==0 || winMutex_isNt==1 ); - if( winMutex_isNt && TryEnterCriticalSection(&p->mutex) ){ + if( rc ){ #ifdef SQLITE_DEBUG - p->owner = tid; + p->owner = GetCurrentThreadId(); p->nRef++; #endif rc = SQLITE_OK; + }else{ + rc = SQLITE_BUSY; } -#else - UNUSED_PARAMETER(p); -#endif #ifdef SQLITE_DEBUG if( p->trace ){ - OSTRACE(("TRY-MUTEX tid=%lu, mutex(%d)=%p (%d), owner=%lu, nRef=%d, rc=%s\n", - tid, p->id, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc))); + OSTRACE(( + "TRY-MUTEX tid=%lu, mutex(%d)=%p (%d), owner=%lu, nRef=%d, rc=%s\n", + GetCurrentThreadId(), p->id, p, p->trace, p->owner, p->nRef, + sqlite3ErrName(rc))); } #endif return rc; @@ -31584,23 +31933,24 @@ static int winMutexTry(sqlite3_mutex *p){ ** is not currently allocated. SQLite will never do either. */ static void winMutexLeave(sqlite3_mutex *p){ -#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) - DWORD tid = GetCurrentThreadId(); -#endif assert( p ); #ifdef SQLITE_DEBUG assert( p->nRef>0 ); - assert( p->owner==tid ); + assert( p->owner==GetCurrentThreadId() ); p->nRef--; if( p->nRef==0 ) p->owner = 0; assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE ); #endif assert( winMutex_isInit==1 ); - LeaveCriticalSection(&p->mutex); + if( p->id==SQLITE_MUTEX_RECURSIVE ){ + LeaveCriticalSection(&p->u.cs); + }else{ + ReleaseSRWLockExclusive(&p->u.srwl); + } #ifdef SQLITE_DEBUG if( p->trace ){ OSTRACE(("LEAVE-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n", - tid, p->id, p, p->trace, p->nRef)); + GetCurrentThreadId(), p->id, p, p->trace, p->nRef)); } #endif } @@ -32572,8 +32922,10 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){ #define etESCAPE_w 14 /* %w -> Strings with '\"' doubled */ #define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ #define etDECIMAL 16 /* %d or %u, but not %x, %o */ +#define etESCAPE_j 17 /* %j -> JSON string literal w/o "..." */ +#define etESCAPE_J 18 /* %J -> JSON string literal with "..." */ -#define etINVALID 17 /* Any unrecognized conversion type */ +#define etINVALID 19 /* Any unrecognized conversion type */ /* @@ -32603,20 +32955,20 @@ typedef struct et_info { /* Information about each format field */ /* ** The table is searched by hash. In the case of %C where C is the character -** and that character has ASCII value j, then the hash is j%23. +** and that character has ASCII value j, then the hash is j%25. ** ** The order of the entries in fmtinfo[] and the hash chain was entered ** manually, but based on the output of the following TCL script: */ #if 0 /***** Beginning of script ******/ -foreach c {d s g z q Q w c o u x X f e E G i n % p T S r} { +foreach c {d s g z q Q w c o u x X f e E G i n % p T S r J j} { scan $c %c x set n($c) $x } set mx [llength [array names n]] puts "count: $mx" -set mx 27 +set mx 25 puts "*********** mx=$mx ************" for {set r 0} {$r<$mx} {incr r} { puts -nonewline [format %2d: $r] @@ -32628,31 +32980,34 @@ for {set r 0} {$r<$mx} {incr r} { #endif /***** End of script ********/ static const char aDigits[] = "0123456789ABCDEF0123456789abcdef"; +static const char aHex[] = "0123456789abcdef"; static const char aPrefix[] = "-x0\000X0"; -static const et_info fmtinfo[23] = { - /* 0 */ { 's', 0, 4, etSTRING, 0, 0, 1 }, - /* 1 */ { 'E', 0, 1, etEXP, 14, 0, 0 }, /* Hash: 0 */ - /* 2 */ { 'u', 10, 0, etDECIMAL, 0, 0, 3 }, - /* 3 */ { 'G', 0, 1, etGENERIC, 14, 0, 0 }, /* Hash: 2 */ - /* 4 */ { 'w', 0, 4, etESCAPE_w, 0, 0, 0 }, - /* 5 */ { 'x', 16, 0, etRADIX, 16, 1, 0 }, - /* 6 */ { 'c', 0, 0, etCHARX, 0, 0, 0 }, /* Hash: 7 */ - /* 7 */ { 'z', 0, 4, etDYNSTRING, 0, 0, 6 }, - /* 8 */ { 'd', 10, 1, etDECIMAL, 0, 0, 0 }, - /* 9 */ { 'e', 0, 1, etEXP, 30, 0, 0 }, - /* 10 */ { 'f', 0, 1, etFLOAT, 0, 0, 0 }, - /* 11 */ { 'g', 0, 1, etGENERIC, 30, 0, 0 }, - /* 12 */ { 'Q', 0, 4, etESCAPE_Q, 0, 0, 0 }, - /* 13 */ { 'i', 10, 1, etDECIMAL, 0, 0, 0 }, - /* 14 */ { '%', 0, 0, etPERCENT, 0, 0, 16 }, - /* 15 */ { 'T', 0, 0, etTOKEN, 0, 0, 0 }, - /* 16 */ { 'S', 0, 0, etSRCITEM, 0, 0, 0 }, /* Hash: 14 */ - /* 17 */ { 'X', 16, 0, etRADIX, 0, 4, 0 }, /* Hash: 19 */ - /* 18 */ { 'n', 0, 0, etSIZE, 0, 0, 0 }, - /* 19 */ { 'o', 8, 0, etRADIX, 0, 2, 17 }, - /* 20 */ { 'p', 16, 0, etPOINTER, 0, 1, 0 }, - /* 21 */ { 'q', 0, 4, etESCAPE_q, 0, 0, 0 }, - /* 22 */ { 'r', 10, 1, etORDINAL, 0, 0, 0 } +static const et_info fmtinfo[25] = { + /* 0 */ { 'd', 10, 1, etDECIMAL, 0, 0, 0 }, + /* 1 */ { 'e', 0, 1, etEXP, 30, 0, 0 }, + /* 2 */ { 'f', 0, 1, etFLOAT, 0, 0, 0 }, + /* 3 */ { 'g', 0, 1, etGENERIC, 30, 0, 0 }, + /* 4 */ { 'j', 0, 0, etESCAPE_j, 0, 0, 0 }, /* Hash: 6 */ + /* 5 */ { 'i', 10, 1, etDECIMAL, 0, 0, 0 }, + /* 6 */ { 'Q', 0, 4, etESCAPE_Q, 0, 0, 4 }, + /* 7 */ { 'p', 16, 0, etPOINTER, 0, 1, 0 }, /* Hash: 12 */ + /* 8 */ { 'S', 0, 0, etSRCITEM, 0, 0, 0 }, + /* 9 */ { 'T', 0, 0, etTOKEN, 0, 0, 0 }, + /* 10 */ { 'n', 0, 0, etSIZE, 0, 0, 0 }, + /* 11 */ { 'o', 8, 0, etRADIX, 0, 2, 0 }, + /* 12 */ { '%', 0, 0, etPERCENT, 0, 0, 7 }, + /* 13 */ { 'q', 0, 4, etESCAPE_q, 0, 0, 16 }, + /* 14 */ { 'r', 10, 1, etORDINAL, 0, 0, 0 }, + /* 15 */ { 's', 0, 4, etSTRING, 0, 0, 0 }, + /* 16 */ { 'X', 16, 0, etRADIX, 0, 4, 0 }, /* Hash: 13 */ + /* 17 */ { 'u', 10, 0, etDECIMAL, 0, 0, 0 }, + /* 18 */ { 'w', 0, 4, etESCAPE_w, 0, 0, 0 }, /* Hash: 19 */ + /* 19 */ { 'E', 0, 1, etEXP, 14, 0, 18 }, + /* 20 */ { 'x', 16, 0, etRADIX, 16, 1, 0 }, + /* 21 */ { 'G', 0, 1, etGENERIC, 14, 0, 0 }, + /* 22 */ { 'z', 0, 4, etDYNSTRING, 0, 0, 0 }, + /* 23 */ { 'J', 0, 0, etESCAPE_J, 0, 0, 0 }, /* Hash: 24 */ + /* 24 */ { 'c', 0, 0, etCHARX, 0, 0, 23 } }; /* Additional Notes: @@ -32720,12 +33075,23 @@ static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){ #define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */ /* -** Hard limit on the precision of floating-point conversions. +** Hard limit on the precision of floating-point conversions to +** the minimum of SQLITE_PRINTF_PRECISION_LIMIT and 100 million. */ -#ifndef SQLITE_PRINTF_PRECISION_LIMIT +#ifdef SQLITE_PRINTF_PRECISION_LIMIT +# if SQLITE_PRINTF_PRECISION_LIMIT<100000000 +# define SQLITE_FP_PRECISION_LIMIT SQLITE_PRINTF_PRECISION_LIMIT +# else +# define SQLITE_FP_PRECISION_LIMIT 100000000 +# endif +#else # define SQLITE_FP_PRECISION_LIMIT 100000000 #endif +/* Forward reference */ +static void sqlite3StrAppend64(sqlite3_str *p, const char *z, i64 N); +static void sqlite3StrAppendchar64(sqlite3_str *p, i64 N, char c); + /* ** Render a string given by "fmt" into the StrAccum object. */ @@ -32736,10 +33102,10 @@ SQLITE_API void sqlite3_str_vappendf( ){ int c; /* Next character in the format string */ char *bufpt; /* Pointer to the conversion buffer */ - int precision; /* Precision of the current field */ - int length; /* Length of the field */ + i64 precision; /* Precision of the current field */ + i64 length; /* Length of the field */ int idx; /* A general purpose loop counter */ - int width; /* Width of the current field */ + i64 width; /* Width of the current field */ etByte flag_leftjustify; /* True if "-" flag is present */ etByte flag_prefix; /* '+' or ' ' or 0 for prefix */ etByte flag_alternateform; /* True if "#" flag is present */ @@ -32787,7 +33153,7 @@ SQLITE_API void sqlite3_str_vappendf( fmt = bufpt + strlen(bufpt); } #endif - sqlite3_str_append(pAccum, bufpt, (int)(fmt - bufpt)); + sqlite3StrAppend64(pAccum, bufpt, fmt - bufpt); if( *fmt==0 ) break; } if( (c=(*++fmt))==0 ){ @@ -32913,8 +33279,8 @@ SQLITE_API void sqlite3_str_vappendf( } #else /* Fast hash-table lookup */ - assert( ArraySize(fmtinfo)==23 ); - idx = ((unsigned)c) % 23; + assert( ArraySize(fmtinfo)==25 ); + idx = ((unsigned)c) % 25; if( fmtinfo[idx].fmttype==c || fmtinfo[idx = fmtinfo[idx].iNxt].fmttype==c ){ @@ -33033,22 +33399,23 @@ SQLITE_API void sqlite3_str_vappendf( longvalue = longvalue/base; }while( longvalue>0 ); } - length = (int)(&zOut[nOut-1]-bufpt); + length = &zOut[nOut-1] - bufpt; if( precision>length ){ /* zero pad */ - int nn = precision-length; + i64 nn = precision-length; bufpt -= nn; memset(bufpt,'0',nn); length = precision; } if( cThousand ){ - int nn = (length - 1)/3; /* Number of "," to insert */ - int ix = (length - 1)%3 + 1; + i64 nn = (length - 1)/3; /* Number of "," to insert */ + i64 ix = (length - 1)%3 + 1; + int ii; bufpt -= nn; - for(idx=0; nn>0; idx++){ - bufpt[idx] = bufpt[idx+nn]; + for(ii=0; nn>0; ii++){ + bufpt[ii] = bufpt[ii+nn]; ix--; if( ix==0 ){ - bufpt[++idx] = cThousand; + bufpt[++ii] = cThousand; nn--; ix = 3; } @@ -33061,7 +33428,7 @@ SQLITE_API void sqlite3_str_vappendf( pre = &aPrefix[infop->prefix]; for(; (x=(*pre))!=0; pre++) *(--bufpt) = x; } - length = (int)(&zOut[nOut-1]-bufpt); + length = &zOut[nOut-1] - bufpt; break; case etFLOAT: case etEXP: @@ -33077,11 +33444,9 @@ SQLITE_API void sqlite3_str_vappendf( realvalue = va_arg(ap,double); } 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 ){ @@ -33093,8 +33458,13 @@ SQLITE_API void sqlite3_str_vappendf( sqlite3FpDecode(&s, realvalue, iRound, flag_altform2 ? 20 : 16); if( s.isSpecial ){ if( s.isSpecial==2 ){ - bufpt = flag_zeropad ? "null" : "NaN"; - length = sqlite3Strlen30(bufpt); + if( flag_zeropad ){ + bufpt = "null"; + length = 4; + }else{ + bufpt = "NaN"; + length = 3; + } break; }else if( flag_zeropad ){ s.z[0] = '9'; @@ -33110,7 +33480,7 @@ SQLITE_API void sqlite3_str_vappendf( }else{ bufpt++; } - length = sqlite3Strlen30(bufpt); + length = strlen(bufpt); break; } } @@ -33166,7 +33536,7 @@ SQLITE_API void sqlite3_str_vappendf( /* Unable to allocate space in pAccum, perhaps because it ** is coming from sqlite3_snprintf() or similar. We'll have ** to render into temporary space and the memcpy() it over. */ - bufpt = sqlite3_malloc(szBufNeeded); + bufpt = sqlite3_malloc64(szBufNeeded); if( bufpt==0 ){ sqlite3StrAccumSetError(pAccum, SQLITE_NOMEM); return; @@ -33266,7 +33636,7 @@ SQLITE_API void sqlite3_str_vappendf( *(bufpt++) = (char)(exp%10+'0'); /* 1's digit */ } - length = (int)(bufpt-zOut); + length = bufpt - zOut; assert( length <= szBufNeeded ); if( lengthnChar + length < SMXV(pAccum->nChar) ); pAccum->nChar += length; zOut[length] = 0; continue; @@ -33332,10 +33703,10 @@ SQLITE_API void sqlite3_str_vappendf( i64 nPrior = 1; width -= precision-1; if( width>1 && !flag_leftjustify ){ - sqlite3_str_appendchar(pAccum, width-1, ' '); + sqlite3StrAppendchar64(pAccum, width-1, ' '); width = 0; } - sqlite3_str_append(pAccum, buf, length); + sqlite3StrAppend64(pAccum, buf, length); precision--; while( precision > 1 ){ i64 nCopyBytes; @@ -33391,20 +33762,97 @@ SQLITE_API void sqlite3_str_vappendf( while( precision-- > 0 && z[0] ){ SQLITE_SKIP_UTF8(z); } - length = (int)(z - (unsigned char*)bufpt); + length = z - (unsigned char*)bufpt; }else{ for(length=0; length0 ){ /* Adjust width to account for extra bytes in UTF-8 characters */ - int ii = length - 1; + i64 ii = length - 1; while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++; } break; + case etESCAPE_j: /* %j: JSON string literal w/o "..." */ + case etESCAPE_J: { /* %J: Generate a JSON string literal */ + char *escarg; + i64 i, j, px, iStart; + unsigned char ch; + + if( bArgList ){ + escarg = getTextArg(pArgList); + }else{ + escarg = va_arg(ap,char*); + } + iStart = sqlite3_str_length(pAccum); + if( escarg==0 ){ + if( xtype==etESCAPE_J ) sqlite3_str_append(pAccum, "null", 4); + }else{ + if( xtype==etESCAPE_J ) sqlite3_str_append(pAccum, "\"", 1); + px = precision; + testcase( px==0 ); + if( px<0 ){ + px = 0x7fffffff; + }else if( flag_altform2 ){ + /* Convert precision from code-points to bytes */ + for(i=0; i0x1f ){ + sqlite3_str_appendchar(pAccum, 1, ch); + }else if( ((1u<>4]); + sqlite3_str_appendchar(pAccum, 1, aHex[ch&0xf]); + } + } + } + if( j0 && sqlite3_str_errcode(pAccum)==SQLITE_OK ){ + sqlite3_int64 n = sqlite3_str_length(pAccum) - iStart; + sqlite3_int64 len = n; + char *zz; + if( flag_altform2 && n>0 ){ + zz = sqlite3_str_value(pAccum); + for(i=iStart; zz[i]; i++){ + if( (zz[i]&0xc0)==0x80 ) len--; + } + } + if( width>len ){ + sqlite3_int64 sp = width-len; + assert( sp>0 && sp<0x7fffffff ); + sqlite3StrAppendchar64(pAccum, (int)sp, ' '); + if( !flag_leftjustify + && n>0 + && sqlite3_str_errcode(pAccum)==0 + ){ + zz = sqlite3_str_value(pAccum); + zz += iStart; + memmove(zz+sp, zz, n); + memset(zz, ' ', sp); + } + } + } + continue; + } case etESCAPE_q: /* %q: Escape ' characters */ case etESCAPE_Q: /* %Q: Escape ' and enclose in '...' */ case etESCAPE_w: { /* %w: Escape " characters */ @@ -33496,7 +33944,7 @@ SQLITE_API void sqlite3_str_vappendf( bufpt[j++] = '0'; bufpt[j++] = '0'; bufpt[j++] = ch>=0x10 ? '1' : '0'; - bufpt[j++] = "0123456789abcdef"[ch&0xf]; + bufpt[j++] = aHex[ch&0xf]; } } }else{ @@ -33583,11 +34031,11 @@ SQLITE_API void sqlite3_str_vappendf( */ width -= length; if( width>0 ){ - if( !flag_leftjustify ) sqlite3_str_appendchar(pAccum, width, ' '); - sqlite3_str_append(pAccum, bufpt, length); - if( flag_leftjustify ) sqlite3_str_appendchar(pAccum, width, ' '); + if( !flag_leftjustify ) sqlite3StrAppendchar64(pAccum, width, ' '); + sqlite3StrAppend64(pAccum, bufpt, length); + if( flag_leftjustify ) sqlite3StrAppendchar64(pAccum, width, ' '); }else{ - sqlite3_str_append(pAccum, bufpt, length); + sqlite3StrAppend64(pAccum, bufpt, length); } if( zExtra ){ @@ -33626,10 +34074,13 @@ SQLITE_PRIVATE void sqlite3RecordErrorByteOffset(sqlite3 *db, const char *z){ ** as the error offset. */ SQLITE_PRIVATE void sqlite3RecordErrorOffsetOfExpr(sqlite3 *db, const Expr *pExpr){ - while( pExpr - && (ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) || pExpr->w.iOfst<=0) - ){ - pExpr = pExpr->pLeft; + while( pExpr ){ + if( ExprHasProperty(pExpr, EP_Reduced|EP_TokenOnly) ) return; + if( ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) || pExpr->w.iOfst<=0 ){ + pExpr = pExpr->pLeft; + }else{ + break; + } } if( pExpr==0 ) return; if( ExprHasProperty(pExpr, EP_FromDDL) ) return; @@ -33707,6 +34158,13 @@ SQLITE_API void sqlite3_str_appendchar(sqlite3_str *p, int N, char c){ } while( (N--)>0 ) p->zText[p->nChar++] = c; } +static void sqlite3StrAppendchar64(sqlite3_str *p, i64 N, char c){ + testcase( p->nChar + N > 0x7fffffff ); + if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){ + return; + } + while( (N--)>0 ) p->zText[p->nChar++] = c; +} /* ** The StrAccum "p" is not large enough to accept N new bytes of z[]. @@ -33718,6 +34176,7 @@ SQLITE_API void sqlite3_str_appendchar(sqlite3_str *p, int N, char c){ */ static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){ N = sqlite3StrAccumEnlarge(p, N); + assert( z!=0 || N==0 ); if( N>0 ){ memcpy(&p->zText[p->nChar], z, N); p->nChar += N; @@ -33741,6 +34200,20 @@ SQLITE_API void sqlite3_str_append(sqlite3_str *p, const char *z, int N){ memcpy(&p->zText[p->nChar-N], z, N); } } +static void sqlite3StrAppend64(sqlite3_str *p, const char *z, i64 N){ + assert( z!=0 || N==0 ); + assert( p->zText!=0 || p->nChar==0 || p->accError ); + assert( N>=0 ); + assert( p->accError==0 || p->nAlloc==0 || p->mxAlloc==0 ); + if( p->nChar+N >= (i64)p->nAlloc ){ + enlargeAndAppend(p,z,N); + }else if( N ){ + assert( p->zText ); + p->nChar += N; + memcpy(&p->zText[p->nChar-N], z, N); + } +} + /* ** Append the complete text of zero-terminated string z[] to the p string. @@ -33778,37 +34251,11 @@ SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){ return p->zText; } -/* -** Use the content of the StrAccum passed as the second argument -** as the result of an SQL function. -*/ -SQLITE_PRIVATE void sqlite3ResultStrAccum(sqlite3_context *pCtx, StrAccum *p){ - if( p->accError ){ - sqlite3_result_error_code(pCtx, p->accError); - sqlite3_str_reset(p); - }else if( isMalloced(p) ){ - sqlite3_result_text(pCtx, p->zText, p->nChar, SQLITE_DYNAMIC); - }else{ - sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC); - sqlite3_str_reset(p); - } -} - -/* -** This singleton is an sqlite3_str object that is returned if -** sqlite3_malloc() fails to provide space for a real one. This -** sqlite3_str object accepts no new text and always returns -** an SQLITE_NOMEM error. -*/ -static sqlite3_str sqlite3OomStr = { - 0, 0, 0, 0, 0, SQLITE_NOMEM, 0 -}; - /* Finalize a string created using sqlite3_str_new(). */ SQLITE_API char *sqlite3_str_finish(sqlite3_str *p){ char *z; - if( p!=0 && p!=&sqlite3OomStr ){ + if( p!=0 && p!=(sqlite3_str*)&sqlite3OomStr ){ z = sqlite3StrAccumFinish(p); sqlite3_free(p); }else{ @@ -33849,6 +34296,8 @@ SQLITE_API void sqlite3_str_reset(StrAccum *p){ if( isMalloced(p) ){ sqlite3DbFree(p->db, p->zText); p->printfFlags &= ~SQLITE_PRINTF_MALLOCED; + }else if( p==(sqlite3_str*)&sqlite3OomStr ){ + return; } p->nAlloc = 0; p->nChar = 0; @@ -33860,7 +34309,7 @@ SQLITE_API void sqlite3_str_reset(StrAccum *p){ ** of its content, all in one call. */ SQLITE_API void sqlite3_str_free(sqlite3_str *p){ - if( p!=0 && p!=&sqlite3OomStr ){ + if( p!=0 && p!=(sqlite3_str*)&sqlite3OomStr ){ sqlite3_str_reset(p); sqlite3_free(p); } @@ -33897,7 +34346,7 @@ SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3 *db){ sqlite3StrAccumInit(p, 0, 0, 0, db ? db->aLimit[SQLITE_LIMIT_LENGTH] : SQLITE_MAX_LENGTH); }else{ - p = &sqlite3OomStr; + p = (sqlite3_str*)&sqlite3OomStr; } return p; } @@ -34790,6 +35239,10 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken); break; } + case TK_ASTERISK: { + sqlite3TreeViewLine(pView,"ASKTERISK"); + break; + } #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ @@ -36116,9 +36569,7 @@ SQLITE_PRIVATE int sqlite3AppendOneUtf8Character(char *zOut, u32 v){ while( zIn=0xD800 && i<=0xDFFF ) t = 0xFFFD; - if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD; assert( c==t ); assert( (z-zBuf)==n ); } @@ -36567,8 +37015,15 @@ SQLITE_PRIVATE void sqlite3UtfSelfTest(void){ /* #include */ #ifndef SQLITE_OMIT_FLOATING_POINT #include + +/* Work around a bug in older Microsoft compilers +** Forum post 2026-04-10T06:33:11z */ +#if !defined(INFINITY) && defined(_MSC_VER) +# define INFINITY HUGE_VAL #endif +#endif /* SQLITE_OMIT_FLOATING_POINT */ + /* ** Calls to sqlite3FaultSim() are used to simulate a failure during testing, ** or to bypass normal error detection during testing in order to let @@ -37331,7 +37786,7 @@ static double sqlite3Fp10Convert2(u64 d, int p){ u64 pwr10h, x, hi, lo, sticky, u, m; double r; if( pPOWERSOF10_LAST ) return INFINITY; + if( p>POWERSOF10_LAST ) return (double)INFINITY; b = 64 - countLeadingZeros(d); lp = pwr10to2(p); e = 53 - b - lp; @@ -37361,7 +37816,7 @@ static double sqlite3Fp10Convert2(u64 d, int p){ e -= adj; } m = (u + 1 + ((u>>2)&1)) >> 2; - if( e<=(-972) ) return INFINITY; + if( e<=(-972) ) return (double)INFINITY; if((m & U64_BIT(52)) != 0){ m = (m & ~U64_BIT(52)) | ((u64)(1075-e)<<52); } @@ -37530,7 +37985,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *zIn, double *pResult){ } return 0xfffffff0 | mState; #else - return sqlite3Atoi64(z, pResult, strlen(z), SQLITE_UTF8)==0; + return sqlite3Atoi64(zIn, pResult, strlen(zIn), SQLITE_UTF8)==0; #endif /* SQLITE_OMIT_FLOATING_POINT */ } @@ -38088,7 +38543,7 @@ SQLITE_PRIVATE int sqlite3GetUInt32(const char *z, u32 *pI){ int i; for(i=0; sqlite3Isdigit(z[i]); i++){ v = v*10 + z[i] - '0'; - if( v>4294967296LL ){ *pI = 0; return 0; } + if( v>4294967295LL ){ *pI = 0; return 0; } } if( i==0 || z[i]!=0 ){ *pI = 0; return 0; } *pI = (u32)v; @@ -38161,171 +38616,83 @@ SQLITE_PRIVATE int sqlite3PutVarint(unsigned char *p, u64 v){ return putVarint64(p,v); } -/* -** Bitmasks used by sqlite3GetVarint(). These precomputed constants -** are defined here rather than simply putting the constant expressions -** inline in order to work around bugs in the RVT compiler. -** -** SLOT_2_0 A mask for (0x7f<<14) | 0x7f -** -** SLOT_4_2_0 A mask for (0x7f<<28) | SLOT_2_0 -*/ -#define SLOT_2_0 0x001fc07f -#define SLOT_4_2_0 0xf01fc07f - - /* ** Read a 64-bit variable-length integer from memory starting at p[0]. ** Return the number of bytes read. The value is stored in *v. */ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){ - u32 a,b,s; - - if( ((signed char*)p)[0]>=0 ){ - *v = *p; - return 1; - } - if( ((signed char*)p)[1]>=0 ){ - *v = ((u32)(p[0]&0x7f)<<7) | p[1]; - return 2; - } - - /* Verify that constants are precomputed correctly */ - assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) ); - assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) ); - - a = ((u32)p[0])<<14; - b = p[1]; - p += 2; - a |= *p; - /* a: p0<<14 | p2 (unmasked) */ - if (!(a&0x80)) - { - a &= SLOT_2_0; - b &= 0x7f; - b = b<<7; - a |= b; - *v = a; - return 3; - } - - /* CSE1 from below */ - a &= SLOT_2_0; - p++; - b = b<<14; - b |= *p; - /* b: p1<<14 | p3 (unmasked) */ - if (!(b&0x80)) - { - b &= SLOT_2_0; - /* moved CSE1 up */ - /* a &= (0x7f<<14)|(0x7f); */ - a = a<<7; - a |= b; - *v = a; - return 4; - } - - /* a: p0<<14 | p2 (masked) */ - /* b: p1<<14 | p3 (unmasked) */ - /* 1:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ - /* moved CSE1 up */ - /* a &= (0x7f<<14)|(0x7f); */ - b &= SLOT_2_0; - s = a; - /* s: p0<<14 | p2 (masked) */ - - p++; - a = a<<14; - a |= *p; - /* a: p0<<28 | p2<<14 | p4 (unmasked) */ - if (!(a&0x80)) - { - /* we can skip these cause they were (effectively) done above - ** while calculating s */ - /* a &= (0x7f<<28)|(0x7f<<14)|(0x7f); */ - /* b &= (0x7f<<14)|(0x7f); */ - b = b<<7; - a |= b; - s = s>>18; - *v = ((u64)s)<<32 | a; - return 5; - } - - /* 2:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ - s = s<<7; - s |= b; - /* s: p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ - - p++; - b = b<<14; - b |= *p; - /* b: p1<<28 | p3<<14 | p5 (unmasked) */ - if (!(b&0x80)) - { - /* we can skip this cause it was (effectively) done above in calc'ing s */ - /* b &= (0x7f<<28)|(0x7f<<14)|(0x7f); */ - a &= SLOT_2_0; - a = a<<7; - a |= b; - s = s>>18; - *v = ((u64)s)<<32 | a; - return 6; - } - - p++; - a = a<<14; - a |= *p; - /* a: p2<<28 | p4<<14 | p6 (unmasked) */ - if (!(a&0x80)) - { - a &= SLOT_4_2_0; - b &= SLOT_2_0; - b = b<<7; - a |= b; - s = s>>11; - *v = ((u64)s)<<32 | a; - return 7; + u64 iKey = p[0]; + const u8 *pStart = p; + if( iKey>=0x80 ){ + u8 x; + iKey = (iKey<<7) ^ (x = *++p); + if( x>=0x80 ){ + iKey = (iKey<<7) ^ (x = *++p); + if( x>=0x80 ){ + iKey = (iKey<<7) ^ 0x10204000 ^ (x = *++p); + if( x>=0x80 ){ + iKey = (iKey<<7) ^ 0x4000 ^ (x = *++p); + if( x>=0x80 ){ + iKey = (iKey<<7) ^ 0x4000 ^ (x = *++p); + if( x>=0x80 ){ + iKey = (iKey<<7) ^ 0x4000 ^ (x = *++p); + if( x>=0x80 ){ + iKey = (iKey<<7) ^ 0x4000 ^ (x = *++p); + if( x>=0x80 ){ + iKey = (iKey<<8) ^ 0x8000 ^ (*++p); + } + } + } + } + } + }else{ + iKey ^= 0x204000; + } + }else{ + iKey ^= 0x4000; + } } + *v = iKey; + return (u8)(p - pStart) + 1; +} - /* CSE2 from below */ - a &= SLOT_2_0; - p++; - b = b<<14; - b |= *p; - /* b: p3<<28 | p5<<14 | p7 (unmasked) */ - if (!(b&0x80)) - { - b &= SLOT_4_2_0; - /* moved CSE2 up */ - /* a &= (0x7f<<14)|(0x7f); */ - a = a<<7; - a |= b; - s = s>>4; - *v = ((u64)s)<<32 | a; - return 8; +/* +** Return the value of a variable-length integer without computing +** its length. This is an optimization on sqlite3GetVarint() for the +** cases when the return value of sqlite3GetVarint() is not needed. +*/ +SQLITE_PRIVATE i64 sqlite3VarintValue(const unsigned char *p){ + u64 iKey = p[0]; + if( iKey>=0x80 ){ + u8 x; + iKey = (iKey<<7) ^ (x = *++p); + if( x>=0x80 ){ + iKey = (iKey<<7) ^ (x = *++p); + if( x>=0x80 ){ + iKey = (iKey<<7) ^ 0x10204000 ^ (x = *++p); + if( x>=0x80 ){ + iKey = (iKey<<7) ^ 0x4000 ^ (x = *++p); + if( x>=0x80 ){ + iKey = (iKey<<7) ^ 0x4000 ^ (x = *++p); + if( x>=0x80 ){ + iKey = (iKey<<7) ^ 0x4000 ^ (x = *++p); + if( x>=0x80 ){ + iKey = (iKey<<7) ^ 0x4000 ^ (x = *++p); + if( x>=0x80 ){ + iKey = (iKey<<8) ^ 0x8000 ^ (*++p); + } + } + } + } + } + }else{ + iKey ^= 0x204000; + } + }else{ + iKey ^= 0x4000; + } } - - p++; - a = a<<15; - a |= *p; - /* a: p4<<29 | p6<<15 | p8 (unmasked) */ - - /* moved CSE2 up */ - /* a &= (0x7f<<29)|(0x7f<<15)|(0xff); */ - b &= SLOT_2_0; - b = b<<8; - a |= b; - - s = s<<4; - b = p[-4]; - b &= 0x7f; - b = b>>3; - s |= b; - - *v = ((u64)s)<<32 | a; - - return 9; + return *(i64*)&iKey; } /* @@ -38380,7 +38747,7 @@ SQLITE_PRIVATE int sqlite3VarintLen(u64 v){ /* -** Read or write a four-byte big-endian integer value. +** Read an unsigned 32-bit integer from an unaligned big-endian array of bytes. */ SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){ #if SQLITE_BYTEORDER==4321 @@ -38396,10 +38763,14 @@ SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){ memcpy(&x,p,4); return _byteswap_ulong(x); #else + /* Test this limb using -DSQLITE_BYTEORDER=0 */ testcase( p[0]&0x80 ); return ((unsigned)p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; #endif } + +/* Write an unsigned 32-bit integer into an unaligned big-endian array of bytes. +*/ SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){ #if SQLITE_BYTEORDER==4321 memcpy(p,&v,4); @@ -38410,6 +38781,7 @@ SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){ u32 x = _byteswap_ulong(v); memcpy(p,&x,4); #else + /* Test this limb using -DSQLITE_BYTEORDER=0 */ p[0] = (u8)(v>>24); p[1] = (u8)(v>>16); p[2] = (u8)(v>>8); @@ -38417,7 +38789,58 @@ SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){ #endif } +/* +** Read an unsigned 64-bit integer from an unaligned big-endian byte array. +*/ +SQLITE_PRIVATE SQLITE_OPT_INLINE u64 sqlite3Get8byte(const u8 *p){ +#if SQLITE_BYTEORDER==4321 + u64 x; + memcpy(&x,p,8); + return x; +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 + u64 x; + memcpy(&x,p,8); + return __builtin_bswap64(x); +#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 + u64 x; + memcpy(&x,p,8); + return _byteswap_uint64(x); +#else + /* Test this limb using -DSQLITE_BYTEORDER=0 */ + testcase( p[0]&0x80 ); + return (u64)( + (((u64)p[0]) << 56) + + (((u64)p[1]) << 48) + + (((u64)p[2]) << 40) + + (((u64)p[3]) << 32) + + (((u64)p[4]) << 24) + + (((u64)p[5]) << 16) + + (((u64)p[6]) << 8) + + (((u64)p[7]) << 0) + ); +#endif +} +#if SQLITE_BYTEORDER!=4321 /* Only used for little-endian machines */ +/* +** Byte-swap a 64-bit unsigned integer. +*/ +SQLITE_PRIVATE SQLITE_OPT_INLINE u64 sqlite3BSwap64(u64 x){ +#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 + return __builtin_bswap64(x); +#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 + return _byteswap_uint64(x); +#else + /* Test this limb using -DSQLITE_BYTEORDER=0 */ + x = (x << 32) | (x >> 32); + x = ((x & UINT64_C(0x0000ffff0000ffff)) << 16) | + ((x & UINT64_C(0xffff0000ffff0000)) >> 16); + x = ((x & UINT64_C(0x00ff00ff00ff00ff)) << 8) | + ((x & UINT64_C(0xff00ff00ff00ff00)) >> 8); + return x; +#endif +} +#endif /* SQLITE_BYTEORDER!=4321 */ /* ** Translate a single byte of Hex into an integer. @@ -39117,32 +39540,32 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 22 */ "SeekLE" OpHelp("key=r[P3@P4]"), /* 23 */ "SeekGE" OpHelp("key=r[P3@P4]"), /* 24 */ "SeekGT" OpHelp("key=r[P3@P4]"), - /* 25 */ "IfNotOpen" OpHelp("if( !csr[P1] ) goto P2"), - /* 26 */ "IfNoHope" OpHelp("key=r[P3@P4]"), - /* 27 */ "NoConflict" OpHelp("key=r[P3@P4]"), - /* 28 */ "NotFound" OpHelp("key=r[P3@P4]"), - /* 29 */ "Found" OpHelp("key=r[P3@P4]"), - /* 30 */ "SeekRowid" OpHelp("intkey=r[P3]"), - /* 31 */ "NotExists" OpHelp("intkey=r[P3]"), - /* 32 */ "Last" OpHelp(""), - /* 33 */ "IfSizeBetween" OpHelp(""), - /* 34 */ "SorterSort" OpHelp(""), - /* 35 */ "Sort" OpHelp(""), - /* 36 */ "Rewind" OpHelp(""), - /* 37 */ "IfEmpty" OpHelp("if( empty(P1) ) goto P2"), - /* 38 */ "SorterNext" OpHelp(""), - /* 39 */ "Prev" OpHelp(""), - /* 40 */ "Next" OpHelp(""), - /* 41 */ "IdxLE" OpHelp("key=r[P3@P4]"), - /* 42 */ "IdxGT" OpHelp("key=r[P3@P4]"), + /* 25 */ "IfNoHope" OpHelp("key=r[P3@P4]"), + /* 26 */ "NoConflict" OpHelp("key=r[P3@P4]"), + /* 27 */ "NotFound" OpHelp("key=r[P3@P4]"), + /* 28 */ "Found" OpHelp("key=r[P3@P4]"), + /* 29 */ "SeekRowid" OpHelp("intkey=r[P3]"), + /* 30 */ "NotExists" OpHelp("intkey=r[P3]"), + /* 31 */ "Last" OpHelp(""), + /* 32 */ "IfSizeBetween" OpHelp(""), + /* 33 */ "SorterSort" OpHelp(""), + /* 34 */ "Sort" OpHelp(""), + /* 35 */ "Rewind" OpHelp(""), + /* 36 */ "IfEmpty" OpHelp("if( empty(P1) ) goto P2"), + /* 37 */ "SorterNext" OpHelp(""), + /* 38 */ "Prev" OpHelp(""), + /* 39 */ "Next" OpHelp(""), + /* 40 */ "IdxLE" OpHelp("key=r[P3@P4]"), + /* 41 */ "IdxGT" OpHelp("key=r[P3@P4]"), + /* 42 */ "IdxLT" OpHelp("key=r[P3@P4]"), /* 43 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), /* 44 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), - /* 45 */ "IdxLT" OpHelp("key=r[P3@P4]"), - /* 46 */ "IdxGE" OpHelp("key=r[P3@P4]"), - /* 47 */ "IFindKey" OpHelp(""), - /* 48 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), - /* 49 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), - /* 50 */ "Program" OpHelp(""), + /* 45 */ "IdxGE" OpHelp("key=r[P3@P4]"), + /* 46 */ "IFindKey" OpHelp(""), + /* 47 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), + /* 48 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), + /* 49 */ "Program" OpHelp(""), + /* 50 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), /* 51 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), /* 52 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), /* 53 */ "Ne" OpHelp("IF r[P3]!=r[P1]"), @@ -39152,49 +39575,49 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 57 */ "Lt" OpHelp("IF r[P3]=r[P1]"), /* 59 */ "ElseEq" OpHelp(""), - /* 60 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), - /* 61 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), - /* 62 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), - /* 63 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), - /* 64 */ "IncrVacuum" OpHelp(""), - /* 65 */ "VNext" OpHelp(""), - /* 66 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"), - /* 67 */ "PureFunc" OpHelp("r[P3]=func(r[P2@NP])"), - /* 68 */ "Function" OpHelp("r[P3]=func(r[P2@NP])"), - /* 69 */ "Return" OpHelp(""), - /* 70 */ "EndCoroutine" OpHelp(""), - /* 71 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), - /* 72 */ "Halt" OpHelp(""), - /* 73 */ "Integer" OpHelp("r[P2]=P1"), - /* 74 */ "Int64" OpHelp("r[P2]=P4"), - /* 75 */ "String" OpHelp("r[P2]='P4' (len=P1)"), - /* 76 */ "BeginSubrtn" OpHelp("r[P2]=NULL"), - /* 77 */ "Null" OpHelp("r[P2..P3]=NULL"), - /* 78 */ "SoftNull" OpHelp("r[P1]=NULL"), - /* 79 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), - /* 80 */ "Variable" OpHelp("r[P2]=parameter(P1)"), - /* 81 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), - /* 82 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), - /* 83 */ "SCopy" OpHelp("r[P2]=r[P1]"), - /* 84 */ "IntCopy" OpHelp("r[P2]=r[P1]"), - /* 85 */ "FkCheck" OpHelp(""), - /* 86 */ "ResultRow" OpHelp("output=r[P1@P2]"), - /* 87 */ "CollSeq" OpHelp(""), - /* 88 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), - /* 89 */ "RealAffinity" OpHelp(""), - /* 90 */ "Cast" OpHelp("affinity(r[P1])"), - /* 91 */ "Permutation" OpHelp(""), - /* 92 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), - /* 93 */ "IsTrue" OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"), - /* 94 */ "ZeroOrNull" OpHelp("r[P2] = 0 OR NULL"), - /* 95 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"), - /* 96 */ "Column" OpHelp("r[P3]=PX cursor P1 column P2"), - /* 97 */ "TypeCheck" OpHelp("typecheck(r[P1@P2])"), - /* 98 */ "Affinity" OpHelp("affinity(r[P1@P2])"), - /* 99 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), - /* 100 */ "Count" OpHelp("r[P2]=count()"), - /* 101 */ "ReadCookie" OpHelp(""), - /* 102 */ "SetCookie" OpHelp(""), + /* 60 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), + /* 61 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), + /* 62 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), + /* 63 */ "IncrVacuum" OpHelp(""), + /* 64 */ "VNext" OpHelp(""), + /* 65 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"), + /* 66 */ "PureFunc" OpHelp("r[P3]=func(r[P2@NP])"), + /* 67 */ "Function" OpHelp("r[P3]=func(r[P2@NP])"), + /* 68 */ "Return" OpHelp(""), + /* 69 */ "EndCoroutine" OpHelp(""), + /* 70 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), + /* 71 */ "Halt" OpHelp(""), + /* 72 */ "Integer" OpHelp("r[P2]=P1"), + /* 73 */ "Int64" OpHelp("r[P2]=PINT13"), + /* 74 */ "String" OpHelp("r[P2]='P4' (len=P1)"), + /* 75 */ "BeginSubrtn" OpHelp("r[P2]=NULL"), + /* 76 */ "Null" OpHelp("r[P2..P3]=NULL"), + /* 77 */ "SoftNull" OpHelp("r[P1]=NULL"), + /* 78 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), + /* 79 */ "Variable" OpHelp("r[P2]=parameter(P1)"), + /* 80 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), + /* 81 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), + /* 82 */ "SCopy" OpHelp("r[P2]=r[P1]"), + /* 83 */ "IntCopy" OpHelp("r[P2]=r[P1]"), + /* 84 */ "FkCheck" OpHelp(""), + /* 85 */ "ResultRow" OpHelp("output=r[P1@P2]"), + /* 86 */ "CollSeq" OpHelp(""), + /* 87 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), + /* 88 */ "RealAffinity" OpHelp(""), + /* 89 */ "Cast" OpHelp("affinity(r[P1])"), + /* 90 */ "Permutation" OpHelp(""), + /* 91 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), + /* 92 */ "IsTrue" OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"), + /* 93 */ "ZeroOrNull" OpHelp("r[P2] = 0 OR NULL"), + /* 94 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"), + /* 95 */ "Column" OpHelp("r[P3]=PX cursor P1 column P2"), + /* 96 */ "TypeCheck" OpHelp("typecheck(r[P1@P2])"), + /* 97 */ "Affinity" OpHelp("affinity(r[P1@P2])"), + /* 98 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), + /* 99 */ "Count" OpHelp("r[P2]=count()"), + /* 100 */ "ReadCookie" OpHelp(""), + /* 101 */ "SetCookie" OpHelp(""), + /* 102 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), /* 103 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), /* 104 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), /* 105 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), - /* 163 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"), - /* 164 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 165 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 166 */ "AggValue" OpHelp("r[P3]=value N=P2"), - /* 167 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), - /* 168 */ "Expire" OpHelp(""), - /* 169 */ "CursorLock" OpHelp(""), - /* 170 */ "CursorUnlock" OpHelp(""), - /* 171 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), - /* 172 */ "VBegin" OpHelp(""), - /* 173 */ "VCreate" OpHelp(""), - /* 174 */ "VDestroy" OpHelp(""), - /* 175 */ "VOpen" OpHelp(""), - /* 176 */ "VCheck" OpHelp(""), - /* 177 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"), - /* 178 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), - /* 179 */ "VRename" OpHelp(""), - /* 180 */ "Pagecount" OpHelp(""), - /* 181 */ "MaxPgcnt" OpHelp(""), - /* 182 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"), - /* 183 */ "GetSubtype" OpHelp("r[P2] = r[P1].subtype"), - /* 184 */ "SetSubtype" OpHelp("r[P2].subtype = r[P1]"), - /* 185 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"), - /* 186 */ "Trace" OpHelp(""), - /* 187 */ "CursorHint" OpHelp(""), - /* 188 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), - /* 189 */ "Noop" OpHelp(""), - /* 190 */ "Explain" OpHelp(""), - /* 191 */ "Abortable" OpHelp(""), + /* 119 */ "OpenEphemeral" OpHelp("nColumn=P2"), + /* 120 */ "SorterOpen" OpHelp(""), + /* 121 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), + /* 122 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), + /* 123 */ "Close" OpHelp(""), + /* 124 */ "ColumnsUsed" OpHelp("Cursor P1 uses columns PHEX23"), + /* 125 */ "SeekScan" OpHelp("Scan-ahead up to P1 rows"), + /* 126 */ "SeekHit" OpHelp("set P2<=seekHit<=P3"), + /* 127 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), + /* 128 */ "NewRowid" OpHelp("r[P2]=rowid"), + /* 129 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), + /* 130 */ "RowCell" OpHelp(""), + /* 131 */ "Delete" OpHelp(""), + /* 132 */ "ResetCount" OpHelp(""), + /* 133 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), + /* 134 */ "SorterData" OpHelp("r[P2]=data"), + /* 135 */ "RowData" OpHelp("r[P2]=data"), + /* 136 */ "Rowid" OpHelp("r[P2]=PX rowid of P1"), + /* 137 */ "NullRow" OpHelp(""), + /* 138 */ "SeekEnd" OpHelp(""), + /* 139 */ "IdxInsert" OpHelp("key=r[P2]"), + /* 140 */ "SorterInsert" OpHelp("key=r[P2]"), + /* 141 */ "IdxDelete" OpHelp("key=r[P2@P5]"), + /* 142 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"), + /* 143 */ "IdxRowid" OpHelp("r[P2]=rowid"), + /* 144 */ "FinishSeek" OpHelp(""), + /* 145 */ "Destroy" OpHelp(""), + /* 146 */ "Clear" OpHelp(""), + /* 147 */ "ResetSorter" OpHelp(""), + /* 148 */ "CreateBtree" OpHelp("r[P2]=root iDb=P1 flags=P3"), + /* 149 */ "SqlExec" OpHelp(""), + /* 150 */ "ParseSchema" OpHelp(""), + /* 151 */ "LoadAnalysis" OpHelp(""), + /* 152 */ "DropTable" OpHelp(""), + /* 153 */ "DropIndex" OpHelp(""), + /* 154 */ "Real" OpHelp("r[P2]=PDBL13"), + /* 155 */ "DropTrigger" OpHelp(""), + /* 156 */ "IntegrityCk" OpHelp(""), + /* 157 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), + /* 158 */ "Param" OpHelp(""), + /* 159 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), + /* 160 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), + /* 161 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), + /* 162 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"), + /* 163 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 164 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 165 */ "AggValue" OpHelp("r[P3]=value N=P2"), + /* 166 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), + /* 167 */ "Expire" OpHelp(""), + /* 168 */ "CursorLock" OpHelp(""), + /* 169 */ "CursorUnlock" OpHelp(""), + /* 170 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), + /* 171 */ "VBegin" OpHelp(""), + /* 172 */ "VCreate" OpHelp(""), + /* 173 */ "VDestroy" OpHelp(""), + /* 174 */ "VOpen" OpHelp(""), + /* 175 */ "VCheck" OpHelp(""), + /* 176 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"), + /* 177 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), + /* 178 */ "VRename" OpHelp(""), + /* 179 */ "Pagecount" OpHelp(""), + /* 180 */ "MaxPgcnt" OpHelp(""), + /* 181 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"), + /* 182 */ "GetSubtype" OpHelp("r[P2] = r[P1].subtype"), + /* 183 */ "SetSubtype" OpHelp("r[P2].subtype = r[P1]"), + /* 184 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"), + /* 185 */ "Trace" OpHelp(""), + /* 186 */ "CursorHint" OpHelp(""), + /* 187 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), + /* 188 */ "Noop" OpHelp(""), + /* 189 */ "Explain" OpHelp(""), + /* 190 */ "Abortable" OpHelp(""), }; return azName[i]; } @@ -39306,6 +39728,22 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ ** This file contains an experimental VFS layer that operates on a ** Key/Value storage engine where both keys and values must be pure ** text. +** +** DEBUG AND TEST +** +** For testing on Unix, compile using: +** +** make clean sqlite3d CFLAGS='-DSQLITE_OS_KV_OPTIONAL' +** +** Then start up a shell using something like: +** +** ./sqlite3d 'file:dbname?vfs=kvvfs' +** +** Each K/V entry is stored in a separate file in the working +** directory that has a name like "kvvfs-dbname-*". Due to limitations +** on the key size, the name of the database must be very short - just +** a few characters. If the database name is too long, the VFS will +** malfunction and you will get SQLITE_CORRUPT errors. */ /* #include */ #if SQLITE_OS_KV || (SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)) @@ -39759,12 +40197,14 @@ int kvvfsDecode(const char *a, char *aOut, int nOut){ memset(&aOut[j], 0, n); j += n; if( c==0 || mult==1 ) break; /* progress stalled if mult==1 */ - }else{ + }else if( j='a' && c<='z' ){ + sqlite3_free(pFile->aJrnl); + pFile->aJrnl = 0; + pFile->nJrnl = 0; + while( (c = zTxt[i])>='a' && c<='z' ){ n += (c - 'a')*mult; mult *= 26; + ++i; + } + if( ' '!=zTxt[i++] ){ + /* Malformed input */ + return; } - sqlite3_free(pFile->aJrnl); pFile->aJrnl = sqlite3_malloc64( n ); if( pFile->aJrnl==0 ){ - pFile->nJrnl = 0; return; } pFile->nJrnl = n; @@ -40189,6 +40635,18 @@ static int kvvfsOpen( pFile->base.pMethods = &kvvfs_db_io_methods; } if( !pFile->zClass ){ +#ifdef SQLITE_WASM + if( strlen(zName) >= (KVRECORD_KEY_SZ + - 6 /* "kvvfs-" */ + - 11 /* "-NNNNNNNNNNN" */) ){ + return SQLITE_CANTOPEN; + } +#else + if( 0!=strcmp(zName, "local") && 0!=strcmp(zName, "session") ){ + /* Historical naming restriction which journaling depends on. */ + return SQLITE_CANTOPEN; + } +#endif pFile->zClass = zName; } pFile->aData = sqlite3_malloc64(SQLITE_KVOS_SZ); @@ -45950,7 +46408,6 @@ static void unixRemapfile( const char *zErr = "mmap"; int h = pFd->h; /* File descriptor open on db file */ u8 *pOrig = (u8 *)pFd->pMapRegion; /* Pointer to current file mapping */ - i64 nOrig = pFd->mmapSizeActual; /* Size of pOrig region in bytes */ u8 *pNew = 0; /* Location of new mapping */ int flags = PROT_READ; /* Flags to pass to mmap() */ @@ -45968,21 +46425,12 @@ static void unixRemapfile( if( pOrig ){ #if HAVE_MREMAP i64 nReuse = pFd->mmapSize; + pNew = osMremap(pOrig, nReuse, nNew, MREMAP_MAYMOVE); + zErr = "mremap"; #else const int szSyspage = osGetpagesize(); i64 nReuse = (pFd->mmapSize & ~(szSyspage-1)); -#endif u8 *pReq = &pOrig[nReuse]; - - /* Unmap any pages of the existing mapping that cannot be reused. */ - if( nReuse!=nOrig ){ - osMunmap(pReq, nOrig-nReuse); - } - -#if HAVE_MREMAP - pNew = osMremap(pOrig, nReuse, nNew, MREMAP_MAYMOVE); - zErr = "mremap"; -#else pNew = osMmap(pReq, nNew-nReuse, flags, MAP_SHARED, h, nReuse); if( pNew!=MAP_FAILED ){ if( pNew!=pReq ){ @@ -46617,36 +47065,29 @@ static int fillInUnixFile( return rc; } -/* -** Directories to consider for temp files. -*/ -static const char *azTempDirs[] = { - 0, - 0, - "/var/tmp", - "/usr/tmp", - "/tmp", - "." -}; - -/* -** Initialize first two members of azTempDirs[] array. -*/ -static void unixTempFileInit(void){ - azTempDirs[0] = getenv("SQLITE_TMPDIR"); - azTempDirs[1] = getenv("TMPDIR"); -} - /* ** Return the name of a directory in which to put temporary files. ** If no suitable temporary file directory can be found, return NULL. +** +** The return value might be a string obtained from getenv() and so +** the return value should not be used after any call to setenv() or +** putenv() as that value might have been freed. */ static const char *unixTempFileDir(void){ - unsigned int i = 0; + unsigned int i; struct stat buf; - const char *zDir = sqlite3_temp_directory; + const char *zDir; - while(1){ + for(i=0; i<7; i++){ + switch( i ){ + case 0: zDir = sqlite3_temp_directory; break; + case 1: zDir = getenv("SQLITE_TMPDIR"); break; + case 2: zDir = getenv("TMPDIR"); break; + case 3: zDir = "/var/tmp"; break; + case 4: zDir = "/usr/tmp"; break; + case 5: zDir = "/tmp"; break; + default: zDir = "."; break; + } if( zDir!=0 #if OS_VXWORKS && zDir[0]=='/' @@ -46657,8 +47098,6 @@ static const char *unixTempFileDir(void){ ){ return zDir; } - if( i>=sizeof(azTempDirs)/sizeof(azTempDirs[0]) ) break; - zDir = azTempDirs[i++]; } return 0; } @@ -47007,7 +47446,22 @@ static int unixOpen( }else if( !zName ){ /* If zName is NULL, the upper layer is requesting a temp file. */ - assert(isDelete && !isNewJrnl); + assert( isDelete ); + assert( !isNewJrnl ); + assert( isExclusive ); + assert( isReadWrite ); +#if defined(__linux__) && defined(O_TMPFILE) + /* On systems that support O_TMPFILE, use that flag to create a more + ** secure temporary file that cannot be accessed by other processes + */ + zName = unixTempFileDir(); + if( zName + && (fd = robust_open(zName, O_RDWR|O_EXCL|O_TMPFILE, 0600))>=0 + ){ + rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags|UNIXFILE_NOLOCK); + goto open_finished; + } +#endif rc = unixGetTempname(pVfs->mxPathname, zTmpname); if( rc!=SQLITE_OK ){ return rc; @@ -48926,9 +49380,6 @@ SQLITE_API int sqlite3_os_init(void){ assert( UNIX_SHM_DMS==128 ); /* Byte offset of the deadman-switch */ #endif - /* Initialize temp file dir array. */ - unixTempFileInit(); - return SQLITE_OK; } @@ -48978,86 +49429,6 @@ SQLITE_API int sqlite3_os_end(void){ */ /* #include "os_win.h" */ -/* -** Compiling and using WAL mode requires several APIs that are only -** available in Windows platforms based on the NT kernel. -*/ -#if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_WAL) -# error "WAL mode requires support from the Windows NT kernel, compile\ - with SQLITE_OMIT_WAL." -#endif - -#if !SQLITE_OS_WINNT && SQLITE_MAX_MMAP_SIZE>0 -# error "Memory mapped files require support from the Windows NT kernel,\ - compile with SQLITE_MAX_MMAP_SIZE=0." -#endif - -/* -** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions -** based on the sub-platform)? -*/ -#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_ANSI) -# define SQLITE_WIN32_HAS_ANSI -#endif - -/* -** Are most of the Win32 Unicode APIs available (i.e. with certain exceptions -** based on the sub-platform)? -*/ -#if (SQLITE_OS_WINCE || SQLITE_OS_WINNT) && \ - !defined(SQLITE_WIN32_NO_WIDE) -# define SQLITE_WIN32_HAS_WIDE -#endif - -/* -** Make sure at least one set of Win32 APIs is available. -*/ -#if !defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_WIN32_HAS_WIDE) -# error "At least one of SQLITE_WIN32_HAS_ANSI and SQLITE_WIN32_HAS_WIDE\ - must be defined." -#endif - -/* -** Define the required Windows SDK version constants if they are not -** already available. -*/ -#ifndef NTDDI_WIN8 -# define NTDDI_WIN8 0x06020000 -#endif - -#ifndef NTDDI_WINBLUE -# define NTDDI_WINBLUE 0x06030000 -#endif - -#ifndef NTDDI_WINTHRESHOLD -# define NTDDI_WINTHRESHOLD 0x06040000 -#endif - -/* -** Check to see if the GetVersionEx[AW] functions are deprecated on the -** target system. GetVersionEx was first deprecated in Win8.1. -*/ -#ifndef SQLITE_WIN32_GETVERSIONEX -# if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINBLUE -# define SQLITE_WIN32_GETVERSIONEX 0 /* GetVersionEx() is deprecated */ -# else -# define SQLITE_WIN32_GETVERSIONEX 1 /* GetVersionEx() is current */ -# endif -#endif - -/* -** Check to see if the CreateFileMappingA function is supported on the -** target system. It is unavailable when using "mincore.lib" on Win10. -** When compiling for Windows 10, always assume "mincore.lib" is in use. -*/ -#ifndef SQLITE_WIN32_CREATEFILEMAPPINGA -# if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINTHRESHOLD -# define SQLITE_WIN32_CREATEFILEMAPPINGA 0 -# else -# define SQLITE_WIN32_CREATEFILEMAPPINGA 1 -# endif -#endif - /* ** This constant should already be defined (in the "WinDef.h" SDK file). */ @@ -49137,35 +49508,7 @@ SQLITE_API int sqlite3_os_end(void){ #endif /* -** Do we need to manually define the Win32 file mapping APIs for use with WAL -** mode or memory mapped files (e.g. these APIs are available in the Windows -** CE SDK; however, they are not present in the header file)? -*/ -#if SQLITE_WIN32_FILEMAPPING_API && \ - (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) - -#if defined(SQLITE_WIN32_HAS_ANSI) -WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE, LPSECURITY_ATTRIBUTES, \ - DWORD, DWORD, DWORD, LPCSTR); -#endif /* defined(SQLITE_WIN32_HAS_ANSI) */ - -#if defined(SQLITE_WIN32_HAS_WIDE) -WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE, LPSECURITY_ATTRIBUTES, \ - DWORD, DWORD, DWORD, LPCWSTR); -#endif /* defined(SQLITE_WIN32_HAS_WIDE) */ - -WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T); - -/* -** These file mapping APIs are common to both Win32 and WinRT. -*/ - -WINBASEAPI BOOL WINAPI FlushViewOfFile(LPCVOID, SIZE_T); -WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID); -#endif /* SQLITE_WIN32_FILEMAPPING_API */ - -/* -** Some Microsoft compilers lack this definition. +** Some older Microsoft compilers lack the following definition. */ #ifndef INVALID_FILE_ATTRIBUTES # define INVALID_FILE_ATTRIBUTES ((DWORD)-1) @@ -49185,19 +49528,6 @@ typedef struct winShm winShm; /* A connection to shared-memory */ typedef struct winShmNode winShmNode; /* A region of shared-memory */ #endif -/* -** WinCE lacks native support for file locking so we have to fake it -** with some code of our own. -*/ -#if SQLITE_OS_WINCE -typedef struct winceLock { - int nReaders; /* Number of reader locks obtained */ - BOOL bPending; /* Indicates a pending lock has been obtained */ - BOOL bReserved; /* Indicates a reserved lock has been obtained */ - BOOL bExclusive; /* Indicates an exclusive lock has been obtained */ -} winceLock; -#endif - /* ** The winFile structure is a subclass of sqlite3_file* specific to the win32 ** portability layer. @@ -49216,13 +49546,6 @@ struct winFile { #endif const char *zPath; /* Full pathname of this file */ int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */ -#if SQLITE_OS_WINCE - LPWSTR zDeleteOnClose; /* Name of file to delete when closing */ - HANDLE hMutex; /* Mutex used to control access to shared lock */ - HANDLE hShared; /* Shared memory segment used for locking */ - winceLock local; /* Locks obtained by this instance of winFile */ - winceLock *shared; /* Global shared lock memory for the file */ -#endif #if SQLITE_MAX_MMAP_SIZE>0 int nFetchOut; /* Number of outstanding xFetch references */ HANDLE hMap; /* Handle for accessing memory mapping */ @@ -49419,36 +49742,10 @@ static void winMemShutdown(void *pAppData); SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void); #endif /* SQLITE_WIN32_MALLOC */ -/* -** The following variable is (normally) set once and never changes -** thereafter. It records whether the operating system is Win9x -** or WinNT. -** -** 0: Operating system unknown. -** 1: Operating system is Win9x. -** 2: Operating system is WinNT. -** -** In order to facilitate testing on a WinNT system, the test fixture -** can manually set this value to 1 to emulate Win98 behavior. -*/ -#ifdef SQLITE_TEST -SQLITE_API LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0; -#else -static LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0; -#endif - #ifndef SYSCALL # define SYSCALL sqlite3_syscall_ptr #endif -/* -** This function is not available on Windows CE or WinRT. - */ - -#if SQLITE_OS_WINCE -# define osAreFileApisANSI() 1 -#endif - /* ** Many system calls are accessed through pointer-to-functions so that ** they may be overridden at runtime to facilitate fault injection during @@ -49460,503 +49757,246 @@ static struct win_syscall { sqlite3_syscall_ptr pCurrent; /* Current value of the system call */ sqlite3_syscall_ptr pDefault; /* Default value */ } aSyscall[] = { -#if !SQLITE_OS_WINCE { "AreFileApisANSI", (SYSCALL)AreFileApisANSI, 0 }, -#else - { "AreFileApisANSI", (SYSCALL)0, 0 }, -#endif - -#ifndef osAreFileApisANSI #define osAreFileApisANSI ((BOOL(WINAPI*)(VOID))aSyscall[0].pCurrent) -#endif - -#if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE) - { "CharLowerW", (SYSCALL)CharLowerW, 0 }, -#else - { "CharLowerW", (SYSCALL)0, 0 }, -#endif - -#define osCharLowerW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[1].pCurrent) - -#if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE) - { "CharUpperW", (SYSCALL)CharUpperW, 0 }, -#else - { "CharUpperW", (SYSCALL)0, 0 }, -#endif - -#define osCharUpperW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[2].pCurrent) { "CloseHandle", (SYSCALL)CloseHandle, 0 }, +#define osCloseHandle ((BOOL(WINAPI*)(HANDLE))aSyscall[1].pCurrent) -#define osCloseHandle ((BOOL(WINAPI*)(HANDLE))aSyscall[3].pCurrent) - -#if defined(SQLITE_WIN32_HAS_ANSI) - { "CreateFileA", (SYSCALL)CreateFileA, 0 }, -#else - { "CreateFileA", (SYSCALL)0, 0 }, -#endif - -#define osCreateFileA ((HANDLE(WINAPI*)(LPCSTR,DWORD,DWORD, \ - LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[4].pCurrent) -#if defined(SQLITE_WIN32_HAS_WIDE) { "CreateFileW", (SYSCALL)CreateFileW, 0 }, -#else - { "CreateFileW", (SYSCALL)0, 0 }, -#endif - #define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \ - LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent) + LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[2].pCurrent) -#if defined(SQLITE_WIN32_HAS_ANSI) && \ - (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) && \ - SQLITE_WIN32_CREATEFILEMAPPINGA - { "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 }, +#if defined(SQLITE_UWP) + { "CreateFileMappingFromApp",(SYSCALL)CreateFileMappingFromApp,0 }, #else - { "CreateFileMappingA", (SYSCALL)0, 0 }, + { "CreateFileMappingFromApp",(SYSCALL)0, 0 }, #endif +#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE,\ + PSECURITY_ATTRIBUTES, \ + ULONG,ULONG64,PCWSTR))aSyscall[3].pCurrent) -#define osCreateFileMappingA ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \ - DWORD,DWORD,DWORD,LPCSTR))aSyscall[6].pCurrent) - -#if (SQLITE_OS_WINCE || defined(SQLITE_WIN32_HAS_WIDE)) && \ - (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) +#if !defined(SQLITE_UWP) { "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 }, #else { "CreateFileMappingW", (SYSCALL)0, 0 }, #endif - #define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \ - DWORD,DWORD,DWORD,LPCWSTR))aSyscall[7].pCurrent) - -#if defined(SQLITE_WIN32_HAS_WIDE) - { "CreateMutexW", (SYSCALL)CreateMutexW, 0 }, -#else - { "CreateMutexW", (SYSCALL)0, 0 }, -#endif - -#define osCreateMutexW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,BOOL, \ - LPCWSTR))aSyscall[8].pCurrent) - -#if defined(SQLITE_WIN32_HAS_ANSI) - { "DeleteFileA", (SYSCALL)DeleteFileA, 0 }, -#else - { "DeleteFileA", (SYSCALL)0, 0 }, -#endif + DWORD,DWORD,DWORD,LPCWSTR))aSyscall[4].pCurrent) -#define osDeleteFileA ((BOOL(WINAPI*)(LPCSTR))aSyscall[9].pCurrent) - -#if defined(SQLITE_WIN32_HAS_WIDE) { "DeleteFileW", (SYSCALL)DeleteFileW, 0 }, -#else - { "DeleteFileW", (SYSCALL)0, 0 }, -#endif - -#define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[10].pCurrent) - -#if SQLITE_OS_WINCE - { "FileTimeToLocalFileTime", (SYSCALL)FileTimeToLocalFileTime, 0 }, -#else - { "FileTimeToLocalFileTime", (SYSCALL)0, 0 }, -#endif - -#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(const FILETIME*, \ - LPFILETIME))aSyscall[11].pCurrent) - -#if SQLITE_OS_WINCE - { "FileTimeToSystemTime", (SYSCALL)FileTimeToSystemTime, 0 }, -#else - { "FileTimeToSystemTime", (SYSCALL)0, 0 }, -#endif - -#define osFileTimeToSystemTime ((BOOL(WINAPI*)(const FILETIME*, \ - LPSYSTEMTIME))aSyscall[12].pCurrent) +#define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[5].pCurrent) { "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 }, +#define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[6].pCurrent) -#define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[13].pCurrent) - -#if defined(SQLITE_WIN32_HAS_ANSI) - { "FormatMessageA", (SYSCALL)FormatMessageA, 0 }, -#else - { "FormatMessageA", (SYSCALL)0, 0 }, -#endif - -#define osFormatMessageA ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPSTR, \ - DWORD,va_list*))aSyscall[14].pCurrent) - -#if defined(SQLITE_WIN32_HAS_WIDE) { "FormatMessageW", (SYSCALL)FormatMessageW, 0 }, -#else - { "FormatMessageW", (SYSCALL)0, 0 }, -#endif - #define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \ - DWORD,va_list*))aSyscall[15].pCurrent) + DWORD,va_list*))aSyscall[7].pCurrent) -#if !defined(SQLITE_OMIT_LOAD_EXTENSION) +#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_UWP) { "FreeLibrary", (SYSCALL)FreeLibrary, 0 }, #else { "FreeLibrary", (SYSCALL)0, 0 }, #endif -#define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[16].pCurrent) +#define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[8].pCurrent) { "GetCurrentProcessId", (SYSCALL)GetCurrentProcessId, 0 }, +#define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[9].pCurrent) -#define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[17].pCurrent) - -#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI) - { "GetDiskFreeSpaceA", (SYSCALL)GetDiskFreeSpaceA, 0 }, -#else - { "GetDiskFreeSpaceA", (SYSCALL)0, 0 }, -#endif - -#define osGetDiskFreeSpaceA ((BOOL(WINAPI*)(LPCSTR,LPDWORD,LPDWORD,LPDWORD, \ - LPDWORD))aSyscall[18].pCurrent) - -#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE) - { "GetDiskFreeSpaceW", (SYSCALL)GetDiskFreeSpaceW, 0 }, -#else - { "GetDiskFreeSpaceW", (SYSCALL)0, 0 }, -#endif - -#define osGetDiskFreeSpaceW ((BOOL(WINAPI*)(LPCWSTR,LPDWORD,LPDWORD,LPDWORD, \ - LPDWORD))aSyscall[19].pCurrent) - -#if defined(SQLITE_WIN32_HAS_ANSI) - { "GetFileAttributesA", (SYSCALL)GetFileAttributesA, 0 }, -#else - { "GetFileAttributesA", (SYSCALL)0, 0 }, -#endif - -#define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[20].pCurrent) - -#if defined(SQLITE_WIN32_HAS_WIDE) { "GetFileAttributesW", (SYSCALL)GetFileAttributesW, 0 }, -#else - { "GetFileAttributesW", (SYSCALL)0, 0 }, -#endif - -#define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[21].pCurrent) +#define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[10].pCurrent) -#if defined(SQLITE_WIN32_HAS_WIDE) { "GetFileAttributesExW", (SYSCALL)GetFileAttributesExW, 0 }, -#else - { "GetFileAttributesExW", (SYSCALL)0, 0 }, -#endif - #define osGetFileAttributesExW ((BOOL(WINAPI*)(LPCWSTR,GET_FILEEX_INFO_LEVELS, \ - LPVOID))aSyscall[22].pCurrent) - - { "GetFileSize", (SYSCALL)GetFileSize, 0 }, - -#define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[23].pCurrent) + LPVOID))aSyscall[11].pCurrent) -#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI) - { "GetFullPathNameA", (SYSCALL)GetFullPathNameA, 0 }, -#else - { "GetFullPathNameA", (SYSCALL)0, 0 }, -#endif - -#define osGetFullPathNameA ((DWORD(WINAPI*)(LPCSTR,DWORD,LPSTR, \ - LPSTR*))aSyscall[24].pCurrent) + { "GetFileSizeEx", (SYSCALL)GetFileSizeEx, 0 }, +#define osGetFileSizeEx ((BOOL(WINAPI*)(HANDLE, \ + PLARGE_INTEGER))aSyscall[12].pCurrent) -#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE) { "GetFullPathNameW", (SYSCALL)GetFullPathNameW, 0 }, -#else - { "GetFullPathNameW", (SYSCALL)0, 0 }, -#endif - #define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \ - LPWSTR*))aSyscall[25].pCurrent) + LPWSTR*))aSyscall[13].pCurrent) -/* -** For GetLastError(), MSDN says: -** -** Minimum supported client: Windows XP [desktop apps | UWP apps] -** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps] -*/ { "GetLastError", (SYSCALL)GetLastError, 0 }, +#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[14].pCurrent) -#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent) - -#if !defined(SQLITE_OMIT_LOAD_EXTENSION) -#if SQLITE_OS_WINCE - /* The GetProcAddressA() routine is only available on Windows CE. */ - { "GetProcAddressA", (SYSCALL)GetProcAddressA, 0 }, -#else - /* All other Windows platforms expect GetProcAddress() to take - ** an ANSI string regardless of the _UNICODE setting */ +#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_UWP) { "GetProcAddressA", (SYSCALL)GetProcAddress, 0 }, -#endif #else { "GetProcAddressA", (SYSCALL)0, 0 }, #endif - #define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \ - LPCSTR))aSyscall[27].pCurrent) + LPCSTR))aSyscall[15].pCurrent) { "GetSystemInfo", (SYSCALL)GetSystemInfo, 0 }, -#define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[28].pCurrent) +#define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[16].pCurrent) - { "GetSystemTime", (SYSCALL)GetSystemTime, 0 }, -#define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[29].pCurrent) - -#if !SQLITE_OS_WINCE { "GetSystemTimeAsFileTime", (SYSCALL)GetSystemTimeAsFileTime, 0 }, -#else - { "GetSystemTimeAsFileTime", (SYSCALL)0, 0 }, -#endif - #define osGetSystemTimeAsFileTime ((VOID(WINAPI*)( \ - LPFILETIME))aSyscall[30].pCurrent) - -#if defined(SQLITE_WIN32_HAS_ANSI) - { "GetTempPathA", (SYSCALL)GetTempPathA, 0 }, -#else - { "GetTempPathA", (SYSCALL)0, 0 }, -#endif - -#define osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[31].pCurrent) + LPFILETIME))aSyscall[17].pCurrent) -#if defined(SQLITE_WIN32_HAS_WIDE) - { "GetTempPathW", (SYSCALL)GetTempPathW, 0 }, -#else +#ifdef SQLITE_UWP { "GetTempPathW", (SYSCALL)0, 0 }, -#endif - -#define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[32].pCurrent) - - { "GetTickCount", (SYSCALL)GetTickCount, 0 }, - -#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent) - -#if defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_GETVERSIONEX - { "GetVersionExA", (SYSCALL)GetVersionExA, 0 }, #else - { "GetVersionExA", (SYSCALL)0, 0 }, + { "GetTempPathW", (SYSCALL)GetTempPathW, 0 }, #endif +#define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[18].pCurrent) -#define osGetVersionExA ((BOOL(WINAPI*)( \ - LPOSVERSIONINFOA))aSyscall[34].pCurrent) + { "GetTickCount64", (SYSCALL)GetTickCount64, 0 }, +#define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[19].pCurrent) -#if defined(SQLITE_WIN32_HAS_WIDE) && \ - SQLITE_WIN32_GETVERSIONEX - { "GetVersionExW", (SYSCALL)GetVersionExW, 0 }, +#ifdef SQLITE_UWP + { "HeapAlloc", (SYSCALL)0, 0 }, #else - { "GetVersionExW", (SYSCALL)0, 0 }, -#endif - -#define osGetVersionExW ((BOOL(WINAPI*)( \ - LPOSVERSIONINFOW))aSyscall[35].pCurrent) - { "HeapAlloc", (SYSCALL)HeapAlloc, 0 }, - +#endif #define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \ - SIZE_T))aSyscall[36].pCurrent) + SIZE_T))aSyscall[20].pCurrent) +#ifdef SQLITE_UWP + { "HeapCreate", (SYSCALL)0, 0 }, +#else { "HeapCreate", (SYSCALL)HeapCreate, 0 }, - +#endif #define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \ - SIZE_T))aSyscall[37].pCurrent) + SIZE_T))aSyscall[21].pCurrent) +#ifdef SQLITE_UWP + { "HeapDestroy", (SYSCALL)0, 0 }, +#else { "HeapDestroy", (SYSCALL)HeapDestroy, 0 }, +#endif +#define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[22].pCurrent) -#define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[38].pCurrent) - +#ifdef SQLITE_UWP + { "HeapFree", (SYSCALL)0, 0 }, +#else { "HeapFree", (SYSCALL)HeapFree, 0 }, +#endif +#define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[23].pCurrent) -#define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[39].pCurrent) - +#ifdef SQLITE_UWP + { "HeapReAlloc", (SYSCALL)0, 0 }, +#else { "HeapReAlloc", (SYSCALL)HeapReAlloc, 0 }, - +#endif #define osHeapReAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD,LPVOID, \ - SIZE_T))aSyscall[40].pCurrent) + SIZE_T))aSyscall[24].pCurrent) +#ifdef SQLITE_UWP + { "HeapSize", (SYSCALL)0, 0 }, +#else { "HeapSize", (SYSCALL)HeapSize, 0 }, - +#endif #define osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \ - LPCVOID))aSyscall[41].pCurrent) + LPCVOID))aSyscall[25].pCurrent) +#ifdef SQLITE_UWP + { "HeapValidate", (SYSCALL)0, 0 }, +#else { "HeapValidate", (SYSCALL)HeapValidate, 0 }, - +#endif #define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \ - LPCVOID))aSyscall[42].pCurrent) + LPCVOID))aSyscall[26].pCurrent) -#if !SQLITE_OS_WINCE - { "HeapCompact", (SYSCALL)HeapCompact, 0 }, -#else +#ifdef SQLITE_UWP { "HeapCompact", (SYSCALL)0, 0 }, -#endif - -#define osHeapCompact ((UINT(WINAPI*)(HANDLE,DWORD))aSyscall[43].pCurrent) - -#if defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_OMIT_LOAD_EXTENSION) - { "LoadLibraryA", (SYSCALL)LoadLibraryA, 0 }, #else - { "LoadLibraryA", (SYSCALL)0, 0 }, + { "HeapCompact", (SYSCALL)HeapCompact, 0 }, #endif +#define osHeapCompact ((UINT(WINAPI*)(HANDLE,DWORD))aSyscall[27].pCurrent) -#define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[44].pCurrent) -#if defined(SQLITE_WIN32_HAS_WIDE) && \ - !defined(SQLITE_OMIT_LOAD_EXTENSION) +#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_UWP) { "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 }, #else { "LoadLibraryW", (SYSCALL)0, 0 }, #endif - -#define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[45].pCurrent) +#define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[28].pCurrent) { "LocalFree", (SYSCALL)LocalFree, 0 }, +#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[29].pCurrent) -#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[46].pCurrent) - -#if !SQLITE_OS_WINCE - { "LockFile", (SYSCALL)LockFile, 0 }, -#else - { "LockFile", (SYSCALL)0, 0 }, -#endif - -#if !defined(osLockFile) && defined(SQLITE_WIN32_HAS_ANSI) -#define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ - DWORD))aSyscall[47].pCurrent) -#endif - -#if !SQLITE_OS_WINCE { "LockFileEx", (SYSCALL)LockFileEx, 0 }, -#else - { "LockFileEx", (SYSCALL)0, 0 }, -#endif - -#ifndef osLockFileEx #define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \ - LPOVERLAPPED))aSyscall[48].pCurrent) -#endif + LPOVERLAPPED))aSyscall[30].pCurrent) -#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 +#if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \ + && !defined(SQLITE_UWP) { "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 }, #else { "MapViewOfFile", (SYSCALL)0, 0 }, #endif - #define osMapViewOfFile ((LPVOID(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ - SIZE_T))aSyscall[49].pCurrent) + SIZE_T))aSyscall[31].pCurrent) - { "MultiByteToWideChar", (SYSCALL)MultiByteToWideChar, 0 }, +#if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \ + && defined(SQLITE_UWP) + { "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 }, +#else + { "MapViewOfFileFromApp", (SYSCALL)0, 0 }, +#endif +#define osMapViewOfFileFromApp ((LPVOID(WINAPI*)(HANDLE,ULONG,ULONG64, \ + SIZE_T))aSyscall[32].pCurrent) + { "MultiByteToWideChar", (SYSCALL)MultiByteToWideChar, 0 }, #define osMultiByteToWideChar ((int(WINAPI*)(UINT,DWORD,LPCSTR,int,LPWSTR, \ - int))aSyscall[50].pCurrent) + int))aSyscall[33].pCurrent) { "QueryPerformanceCounter", (SYSCALL)QueryPerformanceCounter, 0 }, - #define osQueryPerformanceCounter ((BOOL(WINAPI*)( \ - LARGE_INTEGER*))aSyscall[51].pCurrent) + LARGE_INTEGER*))aSyscall[34].pCurrent) { "ReadFile", (SYSCALL)ReadFile, 0 }, - #define osReadFile ((BOOL(WINAPI*)(HANDLE,LPVOID,DWORD,LPDWORD, \ - LPOVERLAPPED))aSyscall[52].pCurrent) + LPOVERLAPPED))aSyscall[35].pCurrent) { "SetEndOfFile", (SYSCALL)SetEndOfFile, 0 }, +#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[36].pCurrent) -#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[53].pCurrent) - - { "SetFilePointer", (SYSCALL)SetFilePointer, 0 }, - -#define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \ - DWORD))aSyscall[54].pCurrent) + { "SetFilePointerEx", (SYSCALL)SetFilePointerEx, 0 }, +#define osSetFilePointerEx ((BOOL(WINAPI*)(HANDLE,LARGE_INTEGER,\ + PLARGE_INTEGER,DWORD))aSyscall[37].pCurrent) { "Sleep", (SYSCALL)Sleep, 0 }, +#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[38].pCurrent) -#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[55].pCurrent) - - { "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 }, - -#define osSystemTimeToFileTime ((BOOL(WINAPI*)(const SYSTEMTIME*, \ - LPFILETIME))aSyscall[56].pCurrent) - -#if !SQLITE_OS_WINCE - { "UnlockFile", (SYSCALL)UnlockFile, 0 }, -#else - { "UnlockFile", (SYSCALL)0, 0 }, -#endif - -#if !defined(osUnlockFile) && defined(SQLITE_WIN32_HAS_ANSI) -#define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ - DWORD))aSyscall[57].pCurrent) -#endif - -#if !SQLITE_OS_WINCE { "UnlockFileEx", (SYSCALL)UnlockFileEx, 0 }, -#else - { "UnlockFileEx", (SYSCALL)0, 0 }, -#endif - #define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ - LPOVERLAPPED))aSyscall[58].pCurrent) + LPOVERLAPPED))aSyscall[39].pCurrent) -#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 { "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 }, #else { "UnmapViewOfFile", (SYSCALL)0, 0 }, #endif - -#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[59].pCurrent) +#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[40].pCurrent) { "WideCharToMultiByte", (SYSCALL)WideCharToMultiByte, 0 }, - #define osWideCharToMultiByte ((int(WINAPI*)(UINT,DWORD,LPCWSTR,int,LPSTR,int, \ - LPCSTR,LPBOOL))aSyscall[60].pCurrent) + LPCSTR,LPBOOL))aSyscall[41].pCurrent) { "WriteFile", (SYSCALL)WriteFile, 0 }, - #define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \ - LPOVERLAPPED))aSyscall[61].pCurrent) + LPOVERLAPPED))aSyscall[42].pCurrent) -/* -** For WaitForSingleObject(), MSDN says: -** -** Minimum supported client: Windows XP [desktop apps | UWP apps] -** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps] -*/ { "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 }, - #define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \ - DWORD))aSyscall[62].pCurrent) + DWORD))aSyscall[43].pCurrent) -#if !SQLITE_OS_WINCE { "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 }, -#else - { "WaitForSingleObjectEx", (SYSCALL)0, 0 }, -#endif - #define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \ - BOOL))aSyscall[63].pCurrent) + BOOL))aSyscall[44].pCurrent) - { "GetNativeSystemInfo", (SYSCALL)0, 0 }, - /* ^^^^^^^^^^^^^^^^^^^----------------^------- placeholder only */ - -#if defined(SQLITE_WIN32_HAS_ANSI) { "OutputDebugStringA", (SYSCALL)OutputDebugStringA, 0 }, -#else - { "OutputDebugStringA", (SYSCALL)0, 0 }, -#endif - -#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[65].pCurrent) - -#if defined(SQLITE_WIN32_HAS_WIDE) - { "OutputDebugStringW", (SYSCALL)OutputDebugStringW, 0 }, -#else - { "OutputDebugStringW", (SYSCALL)0, 0 }, -#endif - -#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[66].pCurrent) +#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[45].pCurrent) { "GetProcessHeap", (SYSCALL)GetProcessHeap, 0 }, - -#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[67].pCurrent) +#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[46].pCurrent) /* ** NOTE: On some sub-platforms, the InterlockedCompareExchange "function" @@ -49965,131 +50005,96 @@ static struct win_syscall { */ #if defined(InterlockedCompareExchange) { "InterlockedCompareExchange", (SYSCALL)0, 0 }, - #define osInterlockedCompareExchange InterlockedCompareExchange #else { "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 }, - -#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG \ - SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[68].pCurrent) +#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG volatile*,\ + LONG,LONG))aSyscall[47].pCurrent) #endif /* defined(InterlockedCompareExchange) */ -#if !SQLITE_OS_WINCE && SQLITE_WIN32_USE_UUID +#if SQLITE_WIN32_USE_UUID { "UuidCreate", (SYSCALL)UuidCreate, 0 }, #else { "UuidCreate", (SYSCALL)0, 0 }, #endif +#define osUuidCreate ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[48].pCurrent) -#define osUuidCreate ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[69].pCurrent) - -#if !SQLITE_OS_WINCE && SQLITE_WIN32_USE_UUID +#if SQLITE_WIN32_USE_UUID { "UuidCreateSequential", (SYSCALL)UuidCreateSequential, 0 }, #else { "UuidCreateSequential", (SYSCALL)0, 0 }, #endif - #define osUuidCreateSequential \ - ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[70].pCurrent) + ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[49].pCurrent) #if !defined(SQLITE_NO_SYNC) && SQLITE_MAX_MMAP_SIZE>0 { "FlushViewOfFile", (SYSCALL)FlushViewOfFile, 0 }, #else { "FlushViewOfFile", (SYSCALL)0, 0 }, #endif - #define osFlushViewOfFile \ - ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[71].pCurrent) + ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[50].pCurrent) -/* -** If SQLITE_ENABLE_SETLK_TIMEOUT is defined, we require CreateEvent() -** to implement blocking locks with timeouts. MSDN says: -** -** Minimum supported client: Windows XP [desktop apps | UWP apps] -** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps] -*/ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT { "CreateEvent", (SYSCALL)CreateEvent, 0 }, #else { "CreateEvent", (SYSCALL)0, 0 }, #endif +#define osCreateEvent ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,BOOL, \ + BOOL,LPCSTR))aSyscall[51].pCurrent) -#define osCreateEvent ( \ - (HANDLE(WINAPI*) (LPSECURITY_ATTRIBUTES,BOOL,BOOL,LPCSTR)) \ - aSyscall[72].pCurrent \ -) - -/* -** If SQLITE_ENABLE_SETLK_TIMEOUT is defined, we require CancelIo() -** for the case where a timeout expires and a lock request must be -** cancelled. -** -** Minimum supported client: Windows XP [desktop apps | UWP apps] -** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps] -*/ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT { "CancelIo", (SYSCALL)CancelIo, 0 }, #else { "CancelIo", (SYSCALL)0, 0 }, #endif - -#define osCancelIo ((BOOL(WINAPI*)(HANDLE))aSyscall[73].pCurrent) - -#if defined(SQLITE_WIN32_HAS_WIDE) && defined(_WIN32) - { "GetModuleHandleW", (SYSCALL)GetModuleHandleW, 0 }, -#else - { "GetModuleHandleW", (SYSCALL)0, 0 }, -#endif - -#define osGetModuleHandleW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[74].pCurrent) +#define osCancelIo ((BOOL(WINAPI*)(HANDLE))aSyscall[52].pCurrent) #ifndef _WIN32 { "getenv", (SYSCALL)getenv, 0 }, #else { "getenv", (SYSCALL)0, 0 }, #endif - -#define osGetenv ((const char *(*)(const char *))aSyscall[75].pCurrent) +#define osGetenv ((const char *(*)(const char *))aSyscall[53].pCurrent) #ifndef _WIN32 { "getcwd", (SYSCALL)getcwd, 0 }, #else { "getcwd", (SYSCALL)0, 0 }, #endif - -#define osGetcwd ((char*(*)(char*,size_t))aSyscall[76].pCurrent) +#define osGetcwd ((char*(*)(char*,size_t))aSyscall[54].pCurrent) #ifndef _WIN32 { "readlink", (SYSCALL)readlink, 0 }, #else { "readlink", (SYSCALL)0, 0 }, #endif - -#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[77].pCurrent) +#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[55].pCurrent) #ifndef _WIN32 { "lstat", (SYSCALL)lstat, 0 }, #else { "lstat", (SYSCALL)0, 0 }, #endif - -#define osLstat ((int(*)(const char*,struct stat*))aSyscall[78].pCurrent) +#define osLstat ((int(*)(const char*,struct stat*))aSyscall[56].pCurrent) #ifndef _WIN32 { "__errno", (SYSCALL)__errno, 0 }, #else { "__errno", (SYSCALL)0, 0 }, #endif - -#define osErrno (*((int*(*)(void))aSyscall[79].pCurrent)()) +#define osErrno (*((int*(*)(void))aSyscall[57].pCurrent)()) #ifndef _WIN32 { "cygwin_conv_path", (SYSCALL)cygwin_conv_path, 0 }, #else { "cygwin_conv_path", (SYSCALL)0, 0 }, #endif - #define osCygwin_conv_path ((size_t(*)(unsigned int, \ - const void *, void *, size_t))aSyscall[80].pCurrent) + const void *, void *, size_t))aSyscall[58].pCurrent) + + { "GetDriveTypeW", (SYSCALL)GetDriveTypeW, 0 }, +#define osGetDriveTypeW ((UINT(WINAPI*)(LPCWSTR))aSyscall[59].pCurrent) }; /* End of the overrideable system calls */ @@ -50177,6 +50182,9 @@ static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){ } #ifdef SQLITE_WIN32_MALLOC +#ifdef SQLITE_UWP +# error SQLITE_WIN32_MALLOC is incompatible with SQLITE_UWP +#endif /* ** If a Win32 native heap has been configured, this function will attempt to ** compact it. Upon success, SQLITE_OK will be returned. Upon failure, one @@ -50196,7 +50204,6 @@ SQLITE_API int sqlite3_win32_compact_heap(LPUINT pnLargest){ #if defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif -#if !SQLITE_OS_WINCE if( (nLargest=osHeapCompact(hHeap, SQLITE_WIN32_HEAP_FLAGS))==0 ){ DWORD lastErrno = osGetLastError(); if( lastErrno==NO_ERROR ){ @@ -50209,11 +50216,6 @@ SQLITE_API int sqlite3_win32_compact_heap(LPUINT pnLargest){ rc = SQLITE_ERROR; } } -#else - sqlite3_log(SQLITE_NOTFOUND, "failed to HeapCompact, heap=%p", - (void*)hHeap); - rc = SQLITE_NOTFOUND; -#endif if( pnLargest ) *pnLargest = nLargest; return rc; } @@ -50267,9 +50269,8 @@ SQLITE_API int sqlite3_win32_reset_heap(){ #ifdef _WIN32 /* ** This function outputs the specified (ANSI) string to the Win32 debugger -** (if available). +** (if available). Undocumented. Might go away at any moment. */ - SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){ char zDbgBuf[SQLITE_WIN32_DBG_BUF_SIZE]; int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /* may be negative. */ @@ -50281,7 +50282,6 @@ SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){ return; } #endif -#if defined(SQLITE_WIN32_HAS_ANSI) if( nMin>0 ){ memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE); memcpy(zDbgBuf, zBuf, nMin); @@ -50289,32 +50289,13 @@ SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){ }else{ osOutputDebugStringA(zBuf); } -#elif defined(SQLITE_WIN32_HAS_WIDE) - memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE); - if ( osMultiByteToWideChar( - osAreFileApisANSI() ? CP_ACP : CP_OEMCP, 0, zBuf, - nMin, (LPWSTR)zDbgBuf, SQLITE_WIN32_DBG_BUF_SIZE/sizeof(WCHAR))<=0 ){ - return; - } - osOutputDebugStringW((LPCWSTR)zDbgBuf); -#else - if( nMin>0 ){ - memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE); - memcpy(zDbgBuf, zBuf, nMin); - fprintf(stderr, "%s", zDbgBuf); - }else{ - fprintf(stderr, "%s", zBuf); - } -#endif } -#endif /* _WIN32 */ SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){ osSleep(milliseconds); } -#if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINCE && \ - SQLITE_THREADSAFE>0 +#if SQLITE_MAX_WORKER_THREADS>0 && SQLITE_THREADSAFE>0 SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){ DWORD rc; while( (rc = osWaitForSingleObjectEx(hObject, INFINITE, @@ -50322,63 +50303,7 @@ SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){ return rc; } #endif - -/* -** Return true (non-zero) if we are running under WinNT, Win2K, WinXP, -** or WinCE. Return false (zero) for Win95, Win98, or WinME. -** -** Here is an interesting observation: Win95, Win98, and WinME lack -** the LockFileEx() API. But we can still statically link against that -** API as long as we don't call it when running Win95/98/ME. A call to -** this routine is used to determine if the host is Win95/98/ME or -** WinNT/2K/XP so that we will know whether or not we can safely call -** the LockFileEx() API. -*/ - -#if !SQLITE_WIN32_GETVERSIONEX -# define osIsNT() (1) -#elif SQLITE_OS_WINCE || !defined(SQLITE_WIN32_HAS_ANSI) -# define osIsNT() (1) -#elif !defined(SQLITE_WIN32_HAS_WIDE) -# define osIsNT() (0) -#else -# define osIsNT() ((sqlite3_os_type==2) || sqlite3_win32_is_nt()) -#endif - -/* -** This function determines if the machine is running a version of Windows -** based on the NT kernel. -*/ -SQLITE_API int sqlite3_win32_is_nt(void){ -#if SQLITE_WIN32_GETVERSIONEX - if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){ -#if defined(SQLITE_WIN32_HAS_ANSI) - OSVERSIONINFOA sInfo; - sInfo.dwOSVersionInfoSize = sizeof(sInfo); - osGetVersionExA(&sInfo); - osInterlockedCompareExchange(&sqlite3_os_type, - (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); -#elif defined(SQLITE_WIN32_HAS_WIDE) - OSVERSIONINFOW sInfo; - sInfo.dwOSVersionInfoSize = sizeof(sInfo); - osGetVersionExW(&sInfo); - osInterlockedCompareExchange(&sqlite3_os_type, - (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); -#endif - } - return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; -#elif SQLITE_TEST - return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2 - || osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 - ; -#else - /* - ** NOTE: All sub-platforms where the GetVersionEx[AW] functions are - ** deprecated are always assumed to be based on the NT kernel. - */ - return 1; -#endif -} +#endif /* _WIN32 */ #ifdef SQLITE_WIN32_MALLOC /* @@ -50639,6 +50564,7 @@ static char *winUnicodeToUtf8(LPCWSTR zWideText){ return zText; } +#ifdef _WIN32 /* ** Convert an ANSI string to Microsoft Unicode, using the ANSI or OEM ** code page. @@ -50668,7 +50594,6 @@ static LPWSTR winMbcsToUnicode(const char *zText, int useAnsi){ return zMbcsText; } -#ifdef _WIN32 /* ** Convert a Microsoft Unicode string to a multi-byte character string, ** using the ANSI or OEM code page. @@ -50696,7 +50621,6 @@ static char *winUnicodeToMbcs(LPCWSTR zWideText, int useAnsi){ } return zText; } -#endif /* _WIN32 */ /* ** Convert a multi-byte character string to UTF-8. @@ -50716,7 +50640,6 @@ static char *winMbcsToUtf8(const char *zText, int useAnsi){ return zTextUtf8; } -#ifdef _WIN32 /* ** Convert a UTF-8 string to a multi-byte character string. ** @@ -50766,7 +50689,6 @@ SQLITE_API char *sqlite3_win32_unicode_to_utf8(LPCWSTR zWideText){ #endif return winUnicodeToUtf8(zWideText); } -#endif /* _WIN32 */ /* ** This is a public wrapper for the winMbcsToUtf8() function. @@ -50784,7 +50706,6 @@ SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zText){ return winMbcsToUtf8(zText, osAreFileApisANSI()); } -#ifdef _WIN32 /* ** This is a public wrapper for the winMbcsToUtf8() function. */ @@ -50923,49 +50844,24 @@ static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){ */ DWORD dwLen = 0; char *zOut = 0; - - if( osIsNT() ){ - LPWSTR zTempWide = NULL; - dwLen = osFormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - lastErrno, - 0, - (LPWSTR) &zTempWide, - 0, - 0); - if( dwLen > 0 ){ - /* allocate a buffer and convert to UTF8 */ - sqlite3BeginBenignMalloc(); - zOut = winUnicodeToUtf8(zTempWide); - sqlite3EndBenignMalloc(); - /* free the system buffer allocated by FormatMessage */ - osLocalFree(zTempWide); - } - } -#ifdef SQLITE_WIN32_HAS_ANSI - else{ - char *zTemp = NULL; - dwLen = osFormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - lastErrno, - 0, - (LPSTR) &zTemp, - 0, - 0); - if( dwLen > 0 ){ - /* allocate a buffer and convert to UTF8 */ - sqlite3BeginBenignMalloc(); - zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI()); - sqlite3EndBenignMalloc(); - /* free the system buffer allocated by FormatMessage */ - osLocalFree(zTemp); - } + LPWSTR zTempWide = NULL; + dwLen = osFormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + lastErrno, + 0, + (LPWSTR) &zTempWide, + 0, + 0); + if( dwLen > 0 ){ + /* allocate a buffer and convert to UTF8 */ + sqlite3BeginBenignMalloc(); + zOut = winUnicodeToUtf8(zTempWide); + sqlite3EndBenignMalloc(); + /* free the system buffer allocated by FormatMessage */ + osLocalFree(zTempWide); } -#endif if( 0 == dwLen ){ sqlite3_snprintf(nBuf, zBuf, "OsError 0x%lx (%lu)", lastErrno, lastErrno); }else{ @@ -51072,13 +50968,13 @@ static int winRetryIoerr(int *pnRetry, DWORD *pError){ return 0; } if( winIoerrCanRetry1(e) ){ - sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry)); + osSleep(winIoerrRetryDelay*(1+*pnRetry)); ++*pnRetry; return 1; } #if defined(winIoerrCanRetry2) else if( winIoerrCanRetry2(e) ){ - sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry)); + osSleep(winIoerrRetryDelay*(1+*pnRetry)); ++*pnRetry; return 1; } @@ -51101,323 +50997,6 @@ static void winLogIoerr(int nRetry, int lineno){ } } -/* -** This #if does not rely on the SQLITE_OS_WINCE define because the -** corresponding section in "date.c" cannot use it. -*/ -#if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \ - (!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API) -/* -** The MSVC CRT on Windows CE may not have a localtime() function. -** So define a substitute. -*/ -/* # include */ -struct tm *__cdecl localtime(const time_t *t) -{ - static struct tm y; - FILETIME uTm, lTm; - SYSTEMTIME pTm; - sqlite3_int64 t64; - t64 = *t; - t64 = (t64 + 11644473600)*10000000; - uTm.dwLowDateTime = (DWORD)(t64 & 0xFFFFFFFF); - uTm.dwHighDateTime= (DWORD)(t64 >> 32); - osFileTimeToLocalFileTime(&uTm,&lTm); - osFileTimeToSystemTime(&lTm,&pTm); - y.tm_year = pTm.wYear - 1900; - y.tm_mon = pTm.wMonth - 1; - y.tm_wday = pTm.wDayOfWeek; - y.tm_mday = pTm.wDay; - y.tm_hour = pTm.wHour; - y.tm_min = pTm.wMinute; - y.tm_sec = pTm.wSecond; - return &y; -} -#endif - -#if SQLITE_OS_WINCE -/************************************************************************* -** This section contains code for WinCE only. -*/ -#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)] - -/* -** Acquire a lock on the handle h -*/ -static void winceMutexAcquire(HANDLE h){ - DWORD dwErr; - do { - dwErr = osWaitForSingleObject(h, INFINITE); - } while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED); -} -/* -** Release a lock acquired by winceMutexAcquire() -*/ -#define winceMutexRelease(h) ReleaseMutex(h) - -/* -** Create the mutex and shared memory used for locking in the file -** descriptor pFile -*/ -static int winceCreateLock(const char *zFilename, winFile *pFile){ - LPWSTR zTok; - LPWSTR zName; - DWORD lastErrno; - BOOL bLogged = FALSE; - BOOL bInit = TRUE; - - zName = winUtf8ToUnicode(zFilename); - if( zName==0 ){ - /* out of memory */ - return SQLITE_IOERR_NOMEM_BKPT; - } - - /* Initialize the local lockdata */ - memset(&pFile->local, 0, sizeof(pFile->local)); - - /* Replace the backslashes from the filename and lowercase it - ** to derive a mutex name. */ - zTok = osCharLowerW(zName); - for (;*zTok;zTok++){ - if (*zTok == '\\') *zTok = '_'; - } - - /* Create/open the named mutex */ - pFile->hMutex = osCreateMutexW(NULL, FALSE, zName); - if (!pFile->hMutex){ - pFile->lastErrno = osGetLastError(); - sqlite3_free(zName); - return winLogError(SQLITE_IOERR, pFile->lastErrno, - "winceCreateLock1", zFilename); - } - - /* Acquire the mutex before continuing */ - winceMutexAcquire(pFile->hMutex); - - /* Since the names of named mutexes, semaphores, file mappings etc are - ** case-sensitive, take advantage of that by uppercasing the mutex name - ** and using that as the shared filemapping name. - */ - osCharUpperW(zName); - pFile->hShared = osCreateFileMappingW(INVALID_HANDLE_VALUE, NULL, - PAGE_READWRITE, 0, sizeof(winceLock), - zName); - - /* Set a flag that indicates we're the first to create the memory so it - ** must be zero-initialized */ - lastErrno = osGetLastError(); - if (lastErrno == ERROR_ALREADY_EXISTS){ - bInit = FALSE; - } - - sqlite3_free(zName); - - /* If we succeeded in making the shared memory handle, map it. */ - if( pFile->hShared ){ - pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared, - FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock)); - /* If mapping failed, close the shared memory handle and erase it */ - if( !pFile->shared ){ - pFile->lastErrno = osGetLastError(); - winLogError(SQLITE_IOERR, pFile->lastErrno, - "winceCreateLock2", zFilename); - bLogged = TRUE; - osCloseHandle(pFile->hShared); - pFile->hShared = NULL; - } - } - - /* If shared memory could not be created, then close the mutex and fail */ - if( pFile->hShared==NULL ){ - if( !bLogged ){ - pFile->lastErrno = lastErrno; - winLogError(SQLITE_IOERR, pFile->lastErrno, - "winceCreateLock3", zFilename); - bLogged = TRUE; - } - winceMutexRelease(pFile->hMutex); - osCloseHandle(pFile->hMutex); - pFile->hMutex = NULL; - return SQLITE_IOERR; - } - - /* Initialize the shared memory if we're supposed to */ - if( bInit ){ - memset(pFile->shared, 0, sizeof(winceLock)); - } - - winceMutexRelease(pFile->hMutex); - return SQLITE_OK; -} - -/* -** Destroy the part of winFile that deals with wince locks -*/ -static void winceDestroyLock(winFile *pFile){ - if (pFile->hMutex){ - /* Acquire the mutex */ - winceMutexAcquire(pFile->hMutex); - - /* The following blocks should probably assert in debug mode, but they - are to cleanup in case any locks remained open */ - if (pFile->local.nReaders){ - pFile->shared->nReaders --; - } - if (pFile->local.bReserved){ - pFile->shared->bReserved = FALSE; - } - if (pFile->local.bPending){ - pFile->shared->bPending = FALSE; - } - if (pFile->local.bExclusive){ - pFile->shared->bExclusive = FALSE; - } - - /* De-reference and close our copy of the shared memory handle */ - osUnmapViewOfFile(pFile->shared); - osCloseHandle(pFile->hShared); - - /* Done with the mutex */ - winceMutexRelease(pFile->hMutex); - osCloseHandle(pFile->hMutex); - pFile->hMutex = NULL; - } -} - -/* -** An implementation of the LockFile() API of Windows for CE -*/ -static BOOL winceLockFile( - LPHANDLE phFile, - DWORD dwFileOffsetLow, - DWORD dwFileOffsetHigh, - DWORD nNumberOfBytesToLockLow, - DWORD nNumberOfBytesToLockHigh -){ - winFile *pFile = HANDLE_TO_WINFILE(phFile); - BOOL bReturn = FALSE; - - UNUSED_PARAMETER(dwFileOffsetHigh); - UNUSED_PARAMETER(nNumberOfBytesToLockHigh); - - if (!pFile->hMutex) return TRUE; - winceMutexAcquire(pFile->hMutex); - - /* Wanting an exclusive lock? */ - if (dwFileOffsetLow == (DWORD)SHARED_FIRST - && nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){ - if (pFile->shared->nReaders == 0 && pFile->shared->bExclusive == 0){ - pFile->shared->bExclusive = TRUE; - pFile->local.bExclusive = TRUE; - bReturn = TRUE; - } - } - - /* Want a read-only lock? */ - else if (dwFileOffsetLow == (DWORD)SHARED_FIRST && - nNumberOfBytesToLockLow == 1){ - if (pFile->shared->bExclusive == 0){ - pFile->local.nReaders ++; - if (pFile->local.nReaders == 1){ - pFile->shared->nReaders ++; - } - bReturn = TRUE; - } - } - - /* Want a pending lock? */ - else if (dwFileOffsetLow == (DWORD)PENDING_BYTE - && nNumberOfBytesToLockLow == 1){ - /* If no pending lock has been acquired, then acquire it */ - if (pFile->shared->bPending == 0) { - pFile->shared->bPending = TRUE; - pFile->local.bPending = TRUE; - bReturn = TRUE; - } - } - - /* Want a reserved lock? */ - else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE - && nNumberOfBytesToLockLow == 1){ - if (pFile->shared->bReserved == 0) { - pFile->shared->bReserved = TRUE; - pFile->local.bReserved = TRUE; - bReturn = TRUE; - } - } - - winceMutexRelease(pFile->hMutex); - return bReturn; -} - -/* -** An implementation of the UnlockFile API of Windows for CE -*/ -static BOOL winceUnlockFile( - LPHANDLE phFile, - DWORD dwFileOffsetLow, - DWORD dwFileOffsetHigh, - DWORD nNumberOfBytesToUnlockLow, - DWORD nNumberOfBytesToUnlockHigh -){ - winFile *pFile = HANDLE_TO_WINFILE(phFile); - BOOL bReturn = FALSE; - - UNUSED_PARAMETER(dwFileOffsetHigh); - UNUSED_PARAMETER(nNumberOfBytesToUnlockHigh); - - if (!pFile->hMutex) return TRUE; - winceMutexAcquire(pFile->hMutex); - - /* Releasing a reader lock or an exclusive lock */ - if (dwFileOffsetLow == (DWORD)SHARED_FIRST){ - /* Did we have an exclusive lock? */ - if (pFile->local.bExclusive){ - assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE); - pFile->local.bExclusive = FALSE; - pFile->shared->bExclusive = FALSE; - bReturn = TRUE; - } - - /* Did we just have a reader lock? */ - else if (pFile->local.nReaders){ - assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE - || nNumberOfBytesToUnlockLow == 1); - pFile->local.nReaders --; - if (pFile->local.nReaders == 0) - { - pFile->shared->nReaders --; - } - bReturn = TRUE; - } - } - - /* Releasing a pending lock */ - else if (dwFileOffsetLow == (DWORD)PENDING_BYTE - && nNumberOfBytesToUnlockLow == 1){ - if (pFile->local.bPending){ - pFile->local.bPending = FALSE; - pFile->shared->bPending = FALSE; - bReturn = TRUE; - } - } - /* Releasing a reserved lock */ - else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE - && nNumberOfBytesToUnlockLow == 1){ - if (pFile->local.bReserved) { - pFile->local.bReserved = FALSE; - pFile->shared->bReserved = FALSE; - bReturn = TRUE; - } - } - - winceMutexRelease(pFile->hMutex); - return bReturn; -} -/* -** End of the special code for wince -*****************************************************************************/ -#endif /* SQLITE_OS_WINCE */ /* ** Lock a file region. @@ -51430,27 +51009,11 @@ static BOOL winLockFile( DWORD numBytesLow, DWORD numBytesHigh ){ -#if SQLITE_OS_WINCE - /* - ** NOTE: Windows CE is handled differently here due its lack of the Win32 - ** API LockFile. - */ - return winceLockFile(phFile, offsetLow, offsetHigh, - numBytesLow, numBytesHigh); -#else - if( osIsNT() ){ - OVERLAPPED ovlp; - memset(&ovlp, 0, sizeof(OVERLAPPED)); - ovlp.Offset = offsetLow; - ovlp.OffsetHigh = offsetHigh; - return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp); -#ifdef SQLITE_WIN32_HAS_ANSI - }else{ - return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow, - numBytesHigh); -#endif - } -#endif + OVERLAPPED ovlp; + memset(&ovlp, 0, sizeof(OVERLAPPED)); + ovlp.Offset = offsetLow; + ovlp.OffsetHigh = offsetHigh; + return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp); } #ifndef SQLITE_OMIT_WAL @@ -51474,63 +51037,56 @@ static int winHandleLockTimeout( DWORD flags = LOCKFILE_FAIL_IMMEDIATELY | (bExcl?LOCKFILE_EXCLUSIVE_LOCK:0); int rc = SQLITE_OK; BOOL ret; + OVERLAPPED ovlp; + memset(&ovlp, 0, sizeof(OVERLAPPED)); + ovlp.Offset = offset; - if( !osIsNT() ){ - ret = winLockFile(&hFile, flags, offset, 0, nByte, 0); - }else{ - OVERLAPPED ovlp; - memset(&ovlp, 0, sizeof(OVERLAPPED)); - ovlp.Offset = offset; - -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT - if( nMs!=0 ){ - flags &= ~LOCKFILE_FAIL_IMMEDIATELY; - } - ovlp.hEvent = osCreateEvent(NULL, TRUE, FALSE, NULL); - if( ovlp.hEvent==NULL ){ - return SQLITE_IOERR_LOCK; - } +#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) + if( nMs!=0 ){ + flags &= ~LOCKFILE_FAIL_IMMEDIATELY; + } + ovlp.hEvent = osCreateEvent(NULL, TRUE, FALSE, NULL); + if( ovlp.hEvent==NULL ){ + return SQLITE_IOERR_LOCK; + } #endif - - ret = osLockFileEx(hFile, flags, 0, nByte, 0, &ovlp); - -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT - /* If SQLITE_ENABLE_SETLK_TIMEOUT is defined, then the file-handle was - ** opened with FILE_FLAG_OVERHEAD specified. In this case, the call to - ** LockFileEx() may fail because the request is still pending. This can - ** happen even if LOCKFILE_FAIL_IMMEDIATELY was specified. - ** - ** If nMs is 0, then LOCKFILE_FAIL_IMMEDIATELY was set in the flags - ** passed to LockFileEx(). In this case, if the operation is pending, - ** block indefinitely until it is finished. - ** - ** Otherwise, wait for up to nMs ms for the operation to finish. nMs - ** may be set to INFINITE. - */ - if( !ret && GetLastError()==ERROR_IO_PENDING ){ - DWORD nDelay = (nMs==0 ? INFINITE : nMs); - DWORD res = osWaitForSingleObject(ovlp.hEvent, nDelay); - if( res==WAIT_OBJECT_0 ){ - ret = TRUE; - }else if( res==WAIT_TIMEOUT ){ + ret = osLockFileEx(hFile, flags, 0, nByte, 0, &ovlp); +#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) + /* If SQLITE_ENABLE_SETLK_TIMEOUT is defined, then the file-handle was + ** opened with FILE_FLAG_OVERHEAD specified. In this case, the call to + ** LockFileEx() may fail because the request is still pending. This can + ** happen even if LOCKFILE_FAIL_IMMEDIATELY was specified. + ** + ** If nMs is 0, then LOCKFILE_FAIL_IMMEDIATELY was set in the flags + ** passed to LockFileEx(). In this case, if the operation is pending, + ** block indefinitely until it is finished. + ** + ** Otherwise, wait for up to nMs ms for the operation to finish. nMs + ** may be set to INFINITE. + */ + if( !ret && GetLastError()==ERROR_IO_PENDING ){ + DWORD nDelay = (nMs==0 ? INFINITE : nMs); + DWORD res = osWaitForSingleObject(ovlp.hEvent, nDelay); + if( res==WAIT_OBJECT_0 ){ + ret = TRUE; + }else if( res==WAIT_TIMEOUT ){ #if SQLITE_ENABLE_SETLK_TIMEOUT==1 - rc = SQLITE_BUSY_TIMEOUT; + rc = SQLITE_BUSY_TIMEOUT; #else - rc = SQLITE_BUSY; + rc = SQLITE_BUSY; #endif - }else{ - /* Some other error has occurred */ - rc = SQLITE_IOERR_LOCK; - } - - /* If it is still pending, cancel the LockFileEx() call. */ - osCancelIo(hFile); + }else{ + /* Some other error has occurred */ + rc = SQLITE_IOERR_LOCK; } - osCloseHandle(ovlp.hEvent); -#endif + /* If it is still pending, cancel the LockFileEx() call. */ + osCancelIo(hFile); } + osCloseHandle(ovlp.hEvent); +#endif /* defined(SQLITE_ENABLE_SETLK_TIMEOUT) */ + if( rc==SQLITE_OK && !ret ){ rc = SQLITE_BUSY; } @@ -51548,27 +51104,11 @@ static BOOL winUnlockFile( DWORD numBytesLow, DWORD numBytesHigh ){ -#if SQLITE_OS_WINCE - /* - ** NOTE: Windows CE is handled differently here due its lack of the Win32 - ** API UnlockFile. - */ - return winceUnlockFile(phFile, offsetLow, offsetHigh, - numBytesLow, numBytesHigh); -#else - if( osIsNT() ){ - OVERLAPPED ovlp; - memset(&ovlp, 0, sizeof(OVERLAPPED)); - ovlp.Offset = offsetLow; - ovlp.OffsetHigh = offsetHigh; - return osUnlockFileEx(*phFile, 0, numBytesLow, numBytesHigh, &ovlp); -#ifdef SQLITE_WIN32_HAS_ANSI - }else{ - return osUnlockFile(*phFile, offsetLow, offsetHigh, numBytesLow, - numBytesHigh); -#endif - } -#endif + OVERLAPPED ovlp; + memset(&ovlp, 0, sizeof(OVERLAPPED)); + ovlp.Offset = offsetLow; + ovlp.OffsetHigh = offsetHigh; + return osUnlockFileEx(*phFile, 0, numBytesLow, numBytesHigh, &ovlp); } #ifndef SQLITE_OMIT_WAL @@ -51601,27 +51141,11 @@ static int winHandleUnlock(HANDLE h, int iOff, int nByte){ */ static int winHandleSeek(HANDLE h, sqlite3_int64 iOffset){ int rc = SQLITE_OK; /* Return value */ + LARGE_INTEGER x; /* The offset */ - LONG upperBits; /* Most sig. 32 bits of new offset */ - LONG lowerBits; /* Least sig. 32 bits of new offset */ - DWORD dwRet; /* Value returned by SetFilePointer() */ - - upperBits = (LONG)((iOffset>>32) & 0x7fffffff); - lowerBits = (LONG)(iOffset & 0xffffffff); - - dwRet = osSetFilePointer(h, lowerBits, &upperBits, FILE_BEGIN); - - /* API oddity: If successful, SetFilePointer() returns a dword - ** containing the lower 32-bits of the new file-offset. Or, if it fails, - ** it returns INVALID_SET_FILE_POINTER. However according to MSDN, - ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine - ** whether an error has actually occurred, it is also necessary to call - ** GetLastError(). */ - if( dwRet==INVALID_SET_FILE_POINTER ){ - DWORD lastErrno = osGetLastError(); - if( lastErrno!=NO_ERROR ){ - rc = SQLITE_IOERR_SEEK; - } + x.QuadPart = iOffset; + if( osSetFilePointerEx(h, x, 0, FILE_BEGIN)==0 ){ + rc = SQLITE_IOERR_SEEK; } OSTRACE(("SEEK file=%p, offset=%lld rc=%s\n", h, iOffset,sqlite3ErrName(rc))); return rc; @@ -51680,27 +51204,7 @@ static int winClose(sqlite3_file *id){ do{ rc = osCloseHandle(pFile->h); /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */ - }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) ); -#if SQLITE_OS_WINCE -#define WINCE_DELETION_ATTEMPTS 3 - { - winVfsAppData *pAppData = (winVfsAppData*)pFile->pVfs->pAppData; - if( pAppData==NULL || !pAppData->bNoLock ){ - winceDestroyLock(pFile); - } - } - if( pFile->zDeleteOnClose ){ - int cnt = 0; - while( - osDeleteFileW(pFile->zDeleteOnClose)==0 - && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff - && cnt++ < WINCE_DELETION_ATTEMPTS - ){ - sqlite3_win32_sleep(100); /* Wait a little before trying again */ - } - sqlite3_free(pFile->zDeleteOnClose); - } -#endif + }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (osSleep(100), 1) ); if( rc ){ pFile->h = NULL; } @@ -51723,7 +51227,7 @@ static int winRead( int amt, /* Number of bytes to read */ sqlite3_int64 offset /* Begin reading at this offset */ ){ -#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) +#if !defined(SQLITE_WIN32_NO_OVERLAPPED) OVERLAPPED overlapped; /* The offset for ReadFile. */ #endif winFile *pFile = (winFile*)id; /* file handle */ @@ -51757,7 +51261,7 @@ static int winRead( } #endif -#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED) +#if defined(SQLITE_WIN32_NO_OVERLAPPED) if( winSeekFile(pFile, offset) ){ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n", osGetCurrentProcessId(), pFile, pFile->h)); @@ -51835,13 +51339,13 @@ static int winWrite( } #endif -#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED) +#if defined(SQLITE_WIN32_NO_OVERLAPPED) rc = winSeekFile(pFile, offset); if( rc==0 ){ #else { #endif -#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) +#if !defined(SQLITE_WIN32_NO_OVERLAPPED) OVERLAPPED overlapped; /* The offset for WriteFile. */ #endif u8 *aRem = (u8 *)pBuf; /* Data yet to be written */ @@ -51849,14 +51353,14 @@ static int winWrite( DWORD nWrite; /* Bytes written by each WriteFile() call */ DWORD lastErrno = NO_ERROR; /* Value returned by GetLastError() */ -#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) +#if !defined(SQLITE_WIN32_NO_OVERLAPPED) memset(&overlapped, 0, sizeof(OVERLAPPED)); overlapped.Offset = (LONG)(offset & 0xffffffff); overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff); #endif while( nRem>0 ){ -#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED) +#if defined(SQLITE_WIN32_NO_OVERLAPPED) if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){ #else if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){ @@ -51869,7 +51373,7 @@ static int winWrite( lastErrno = osGetLastError(); break; } -#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) +#if !defined(SQLITE_WIN32_NO_OVERLAPPED) offset += nWrite; overlapped.Offset = (LONG)(offset & 0xffffffff); overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff); @@ -51924,14 +51428,13 @@ static int winHandleTruncate(HANDLE h, sqlite3_int64 nByte){ */ static int winHandleSize(HANDLE h, sqlite3_int64 *pnByte){ int rc = SQLITE_OK; - DWORD upperBits = 0; - DWORD lowerBits = 0; - + LARGE_INTEGER x; assert( pnByte ); - lowerBits = osGetFileSize(h, &upperBits); - *pnByte = (((sqlite3_int64)upperBits)<<32) + lowerBits; - if( lowerBits==INVALID_FILE_SIZE && osGetLastError()!=NO_ERROR ){ + if( osGetFileSizeEx(h, &x)==0 ){ rc = SQLITE_IOERR_FSTAT; + *pnByte = 0; + }else{ + *pnByte = x.QuadPart; } return rc; } @@ -52132,17 +51635,14 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ SimulateIOError(return SQLITE_IOERR_FSTAT); OSTRACE(("SIZE file=%p, pSize=%p\n", pFile->h, pSize)); { - DWORD upperBits; - DWORD lowerBits; - DWORD lastErrno; - - lowerBits = osGetFileSize(pFile->h, &upperBits); - *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits; - if( (lowerBits == INVALID_FILE_SIZE) - && ((lastErrno = osGetLastError())!=NO_ERROR) ){ - pFile->lastErrno = lastErrno; + LARGE_INTEGER x; + if( osGetFileSizeEx(pFile->h, &x)==0 ){ + *pSize = 0; + pFile->lastErrno = osGetLastError(); rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno, "winFileSize", pFile->zPath); + }else{ + *pSize = x.QuadPart; } } OSTRACE(("SIZE file=%p, pSize=%p, *pSize=%lld, rc=%s\n", @@ -52190,27 +51690,8 @@ static int winGetReadLock(winFile *pFile, int bBlock){ int res; DWORD mask = ~(bBlock ? LOCKFILE_FAIL_IMMEDIATELY : 0); OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype)); - if( osIsNT() ){ -#if SQLITE_OS_WINCE - /* - ** NOTE: Windows CE is handled differently here due its lack of the Win32 - ** API LockFileEx. - */ - res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0); -#else - res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS&mask, SHARED_FIRST, 0, - SHARED_SIZE, 0); -#endif - } -#ifdef SQLITE_WIN32_HAS_ANSI - else{ - int lk; - sqlite3_randomness(sizeof(lk), &lk); - pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1)); - res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS&mask, - SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); - } -#endif + res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS&mask, SHARED_FIRST, 0, + SHARED_SIZE, 0); if( res == 0 ){ pFile->lastErrno = osGetLastError(); /* No need to log a failure to lock */ @@ -52226,14 +51707,7 @@ static int winUnlockReadLock(winFile *pFile){ int res; DWORD lastErrno; OSTRACE(("READ-UNLOCK file=%p, lock=%d\n", pFile->h, pFile->locktype)); - if( osIsNT() ){ - res = winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); - } -#ifdef SQLITE_WIN32_HAS_ANSI - else{ - res = winUnlockFile(&pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); - } -#endif + res = winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){ pFile->lastErrno = lastErrno; winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno, @@ -52344,7 +51818,7 @@ static int winLock(sqlite3_file *id, int locktype){ } cnt--; - if( cnt>0 ) sqlite3_win32_sleep(1); + if( cnt>0 ) osSleep(1); } gotPendingLock = res; } @@ -52553,7 +52027,7 @@ static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){ /* Forward references to VFS helper methods used for temporary files */ static int winGetTempname(sqlite3_vfs *, char **); -static int winIsDir(const void *); +static int winIsDir(LPCWSTR); static BOOL winIsLongPathPrefix(const char *); static BOOL winIsDriveLetterAndColon(const char *); @@ -52785,80 +52259,70 @@ static SYSTEM_INFO winSysInfo; ** happen when the file path >32k, in which case winUtf8ToUnicode() ** will fail too. */ -static void *winConvertFromUtf8Filename(const char *zFilename){ - void *zConverted = 0; - if( osIsNT() ){ +static LPWSTR winConvertFromUtf8Filename(const char *zFilename){ + LPWSTR zConverted = 0; #ifdef __CYGWIN__ - int nChar; - LPWSTR zWideFilename; - - if( osCygwin_conv_path && !(winIsDriveLetterAndColon(zFilename) - && winIsDirSep(zFilename[2])) ){ - i64 nByte; - int convertflag = CCP_POSIX_TO_WIN_W; - if( !strchr(zFilename, '/') ) convertflag |= CCP_RELATIVE; - nByte = (i64)osCygwin_conv_path(convertflag, - zFilename, 0, 0); - if( nByte>0 ){ - zConverted = sqlite3MallocZero(12+(u64)nByte); - if ( zConverted==0 ){ - return zConverted; - } - zWideFilename = zConverted; - /* Filenames should be prefixed, except when converted - * full path already starts with "\\?\". */ - if( osCygwin_conv_path(convertflag, zFilename, - zWideFilename+4, nByte)==0 ){ - if( (convertflag&CCP_RELATIVE) ){ - memmove(zWideFilename, zWideFilename+4, nByte); - }else if( memcmp(zWideFilename+4, L"\\\\", 4) ){ - memcpy(zWideFilename, L"\\\\?\\", 8); - }else if( zWideFilename[6]!='?' ){ - memmove(zWideFilename+6, zWideFilename+4, nByte); - memcpy(zWideFilename, L"\\\\?\\UNC", 14); - }else{ - memmove(zWideFilename, zWideFilename+4, nByte); - } - return zConverted; + int nChar; + + if( osCygwin_conv_path && !(winIsDriveLetterAndColon(zFilename) + && winIsDirSep(zFilename[2])) ){ + i64 nByte; + int convertflag = CCP_POSIX_TO_WIN_W; + if( !strchr(zFilename, '/') ) convertflag |= CCP_RELATIVE; + nByte = (i64)osCygwin_conv_path(convertflag, + zFilename, 0, 0); + if( nByte>0 ){ + zConverted = sqlite3MallocZero(12+(u64)nByte); + if ( zConverted==0 ){ + return zConverted; + } + /* Filenames should be prefixed, except when converted + * full path already starts with "\\?\". */ + if( osCygwin_conv_path(convertflag, zFilename, + zConverted+4, nByte)==0 ){ + if( (convertflag&CCP_RELATIVE) ){ + memmove(zConverted, zConverted+4, nByte); + }else if( memcmp(zConverted+4, L"\\\\", 4) ){ + memcpy(zConverted, L"\\\\?\\", 8); + }else if( zConverted[6]!='?' ){ + memmove(zConverted+6, zConverted+4, nByte); + memcpy(zConverted, L"\\\\?\\UNC", 14); + }else{ + memmove(zConverted, zConverted+4, nByte); } - sqlite3_free(zConverted); + return zConverted; } + sqlite3_free(zConverted); } - nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0); - if( nChar==0 ){ - return 0; - } - zWideFilename = sqlite3MallocZero( nChar*sizeof(WCHAR)+12 ); - if( zWideFilename==0 ){ - return 0; - } - nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, - zWideFilename, nChar); - if( nChar==0 ){ - sqlite3_free(zWideFilename); - zWideFilename = 0; - }else if( nChar>MAX_PATH - && winIsDriveLetterAndColon(zFilename) - && winIsDirSep(zFilename[2]) ){ - memmove(zWideFilename+4, zWideFilename, nChar*sizeof(WCHAR)); - zWideFilename[2] = '\\'; - memcpy(zWideFilename, L"\\\\?\\", 8); - }else if( nChar>MAX_PATH - && winIsDirSep(zFilename[0]) && winIsDirSep(zFilename[1]) - && zFilename[2] != '?' ){ - memmove(zWideFilename+6, zWideFilename, nChar*sizeof(WCHAR)); - memcpy(zWideFilename, L"\\\\?\\UNC", 14); - } - zConverted = zWideFilename; -#else - zConverted = winUtf8ToUnicode(zFilename); -#endif /* __CYGWIN__ */ } -#if defined(SQLITE_WIN32_HAS_ANSI) && defined(_WIN32) - else{ - zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI()); + nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0); + if( nChar==0 ){ + return 0; } -#endif + zConverted = sqlite3MallocZero( ((u64)nChar+6)*sizeof(WCHAR) ); + if( zConverted==0 ){ + return 0; + } + nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, + zConverted, nChar); + if( nChar==0 ){ + sqlite3_free(zConverted); + zConverted = 0; + }else if( nChar>MAX_PATH + && winIsDriveLetterAndColon(zFilename) + && winIsDirSep(zFilename[2]) ){ + memmove(zConverted+4, zConverted, nChar*sizeof(WCHAR)); + zConverted[2] = '\\'; + memcpy(zConverted, L"\\\\?\\", 8); + }else if( nChar>MAX_PATH + && winIsDirSep(zFilename[0]) && winIsDirSep(zFilename[1]) + && zFilename[2] != '?' ){ + memmove(zConverted+6, zConverted, nChar*sizeof(WCHAR)); + memcpy(zConverted, L"\\\\?\\UNC", 14); + } +#else /* if !defined(__CYGWIN__) */ + zConverted = winUtf8ToUnicode(zFilename); +#endif /* __CYGWIN__ */ /* caller will handle out of memory */ return zConverted; } @@ -53026,6 +52490,28 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){ } } +/* +** Handle h is open on the *-shm file. This function zeroes the first +** 8 bytes of the file. If SQLITE_ENABLE_SETLK_TIMEOUT is defined, h may +** have been opened with FILE_FLAG_OVERLAPPED. +*/ +static int winZeroSharedMemory(HANDLE h){ + u8 aZero[8] = {0,0,0,0,0,0,0,0}; + DWORD nWrite = 0; + OVERLAPPED ovlp; + memset(&ovlp, 0, sizeof(OVERLAPPED)); + if( !osWriteFile(h, aZero, sizeof(aZero), &nWrite, &ovlp) ){ + /* If the file was opened with FILE_FLAG_OVERLAPPED, the write may still + ** be pending. Wait for it with GetOverlappedResult(). */ + if( osGetLastError()!=ERROR_IO_PENDING + || !GetOverlappedResult(h, &ovlp, &nWrite, TRUE) + ){ + nWrite = 0; + } + } + return (nWrite==sizeof(aZero) ? SQLITE_OK : SQLITE_IOERR_WRITE); +} + /* ** The DMS lock has not yet been taken on the shm file associated with ** pShmNode. Take the lock. Truncate the *-shm file if required. @@ -53044,7 +52530,12 @@ static int winLockSharedMemory(winShmNode *pShmNode, DWORD nMs){ if( pShmNode->isReadonly ){ rc = SQLITE_READONLY_CANTINIT; }else{ - rc = winHandleTruncate(h, 0); + if( SQLITE_OK!=winHandleTruncate(h, 0) ){ + /* Sometimes the truncate operation may fail because some other + ** process is still holding an open mapping. So try to write + ** zeroes into the start of the file instead. */ + rc = winZeroSharedMemory(h); + } } /* Release the EXCLUSIVE lock acquired above. */ @@ -53077,7 +52568,7 @@ static int winHandleOpen( HANDLE *ph /* OUT: New HANDLE for file */ ){ int rc = SQLITE_OK; - void *zConverted = 0; + LPWSTR zConverted = 0; int bReadonly = *pbReadonly; HANDLE h = INVALID_HANDLE_VALUE; @@ -53105,29 +52596,14 @@ static int winHandleOpen( /* TODO: platforms. ** TODO: retry-on-ioerr. */ - if( osIsNT() ){ - h = osCreateFileW((LPCWSTR)zConverted, /* lpFileName */ - (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)), /* dwDesiredAccess */ - FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */ - NULL, /* lpSecurityAttributes */ - OPEN_ALWAYS, /* dwCreationDisposition */ - FILE_ATTRIBUTE_NORMAL|flag_overlapped, - NULL - ); - }else{ - /* Due to pre-processor directives earlier in this file, - ** SQLITE_WIN32_HAS_ANSI is always defined if osIsNT() is false. */ -#ifdef SQLITE_WIN32_HAS_ANSI - h = osCreateFileA((LPCSTR)zConverted, - (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)), /* dwDesiredAccess */ - FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */ - NULL, /* lpSecurityAttributes */ - OPEN_ALWAYS, /* dwCreationDisposition */ - FILE_ATTRIBUTE_NORMAL|flag_overlapped, - NULL - ); -#endif - } + h = osCreateFileW(zConverted, /* lpFileName */ + (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)), /* dwDesiredAccess */ + FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */ + NULL, /* lpSecurityAttributes */ + OPEN_ALWAYS, /* dwCreationDisposition */ + FILE_ATTRIBUTE_NORMAL|flag_overlapped, + NULL + ); if( h==INVALID_HANDLE_VALUE ){ if( bReadonly==0 ){ @@ -53191,7 +52667,7 @@ SQLITE_API int sqlite3_win_test_unc_locking = 0; /* ** Return true if the string passed as the only argument is likely -** to be a UNC path. Return false if note. +** to be a UNC path. Return false if not. ** ** Return true if: ** @@ -53218,6 +52694,23 @@ static int winIsUNCPath(const char *zFile){ return sqlite3_win_test_unc_locking; } +/* +** Return true if the string passed in is the name of a file on a +** remote (network-mounted) volume. +*/ +static int winIsRemoteVolume(const char *zFile){ + WCHAR zRoot[4]; + if( strncmp(zFile, "\\\\?\\",4)==0 ) zFile += 4; + if( !sqlite3Isalpha(zFile[0]) ) return 0; + if( zFile[1]!=':' ) return 0; + if( !winIsDirSep(zFile[2]) ) return 0; + zRoot[0] = (WCHAR)zFile[0]; + zRoot[1] = ':'; + zRoot[2] = '\\'; + zRoot[3] = 0; + return osGetDriveTypeW(zRoot)==DRIVE_REMOTE; +} + /* ** Open the shared-memory area associated with database file pDbFd. */ @@ -53243,7 +52736,11 @@ static int winOpenSharedMemory(winFile *pDbFd){ pNew->zFilename = (char*)&pNew[1]; pNew->hSharedShm = INVALID_HANDLE_VALUE; pNew->isUnlocked = 1; - pNew->bUseSharedLockHandle = winIsUNCPath(pDbFd->zPath); + if( winIsUNCPath(pDbFd->zPath) || winIsRemoteVolume(pDbFd->zPath) ){ + pNew->bUseSharedLockHandle = 1; + }else{ + pNew->bUseSharedLockHandle = 0; + } sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath); sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename); @@ -53599,10 +53096,10 @@ static int winShmMap( HANDLE hMap = NULL; /* file-mapping handle */ void *pMap = 0; /* Mapped memory region */ -#if defined(SQLITE_WIN32_HAS_WIDE) +#ifdef SQLITE_UWP + hMap = osCreateFileMappingFromApp(hShared, NULL, protect, nByte, NULL); +#else hMap = osCreateFileMappingW(hShared, NULL, protect, 0, nByte, NULL); -#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA - hMap = osCreateFileMappingA(hShared, NULL, protect, 0, nByte, NULL); #endif OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%lld, rc=%s\n", osGetCurrentProcessId(), pShmNode->nRegion, nByte, @@ -53610,9 +53107,15 @@ static int winShmMap( if( hMap ){ i64 iOffset = pShmNode->nRegion*szRegion; int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity; +#ifdef SQLITE_UWP + pMap = osMapViewOfFileFromApp(hMap, flags, + iOffset - iOffsetShift, (i64)szRegion + iOffsetShift + ); +#else pMap = osMapViewOfFile(hMap, flags, 0, iOffset - iOffsetShift, (i64)szRegion + iOffsetShift ); +#endif OSTRACE(("SHM-MAP-MAP pid=%lu, region=%d, offset=%d, size=%d, rc=%s\n", osGetCurrentProcessId(), pShmNode->nRegion, iOffset, szRegion, pMap ? "ok" : "failed")); @@ -53745,14 +53248,12 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ flags |= FILE_MAP_WRITE; } #endif -#if defined(SQLITE_WIN32_HAS_WIDE) +#ifdef SQLITE_UWP + pFd->hMap = osCreateFileMappingFromApp(pFd->h, NULL, protect, nMap, NULL); +#else pFd->hMap = osCreateFileMappingW(pFd->h, NULL, protect, (DWORD)((nMap>>32) & 0xffffffff), (DWORD)(nMap & 0xffffffff), NULL); -#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA - pFd->hMap = osCreateFileMappingA(pFd->h, NULL, protect, - (DWORD)((nMap>>32) & 0xffffffff), - (DWORD)(nMap & 0xffffffff), NULL); #endif if( pFd->hMap==NULL ){ pFd->lastErrno = osGetLastError(); @@ -53765,7 +53266,11 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ } assert( (nMap % winSysInfo.dwPageSize)==0 ); assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff ); +#ifdef SQLITE_UWP + pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, (SIZE_T)nMap); +#else pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap); +#endif if( pNew==NULL ){ osCloseHandle(pFd->hMap); pFd->hMap = NULL; @@ -54075,7 +53580,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ if( !azDirs[3] ) azDirs[3] = osGetenv("TEMP"); if( !azDirs[4] ) azDirs[4] = osGetenv("USERPROFILE"); for(i=0; ipAppData; -#if SQLITE_OS_WINCE - { - if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB - && ((pAppData==NULL) || !pAppData->bNoLock) - && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK - ){ - osCloseHandle(h); - sqlite3_free(zConverted); - sqlite3_free(zTmpname); - OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc))); - return rc; - } - } - if( isTemp ){ - pFile->zDeleteOnClose = zConverted; - }else -#endif - { - sqlite3_free(zConverted); - } - + sqlite3_free(zConverted); sqlite3_free(zTmpname); id->pMethods = pAppData ? pAppData->pMethod : &winIoMethod; pFile->pVfs = pVfs; @@ -54547,7 +53962,7 @@ static int winDelete( int rc; DWORD attr; DWORD lastErrno = 0; - void *zConverted; + LPWSTR zConverted; UNUSED_PARAMETER(pVfs); UNUSED_PARAMETER(syncDir); @@ -54559,62 +53974,31 @@ static int winDelete( OSTRACE(("DELETE name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename)); return SQLITE_IOERR_NOMEM_BKPT; } - if( osIsNT() ){ - do { - attr = osGetFileAttributesW(zConverted); - if ( attr==INVALID_FILE_ATTRIBUTES ){ - lastErrno = osGetLastError(); - if( lastErrno==ERROR_FILE_NOT_FOUND - || lastErrno==ERROR_PATH_NOT_FOUND ){ - rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ - }else{ - rc = SQLITE_ERROR; - } - break; - } - if ( attr&FILE_ATTRIBUTE_DIRECTORY ){ - rc = SQLITE_ERROR; /* Files only. */ - break; - } - if ( osDeleteFileW(zConverted) ){ - rc = SQLITE_OK; /* Deleted OK. */ - break; - } - if ( !winRetryIoerr(&cnt, &lastErrno) ){ - rc = SQLITE_ERROR; /* No more retries. */ - break; - } - } while(1); - } -#ifdef SQLITE_WIN32_HAS_ANSI - else{ - do { - attr = osGetFileAttributesA(zConverted); - if ( attr==INVALID_FILE_ATTRIBUTES ){ - lastErrno = osGetLastError(); - if( lastErrno==ERROR_FILE_NOT_FOUND - || lastErrno==ERROR_PATH_NOT_FOUND ){ - rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ - }else{ - rc = SQLITE_ERROR; - } - break; - } - if ( attr&FILE_ATTRIBUTE_DIRECTORY ){ - rc = SQLITE_ERROR; /* Files only. */ - break; - } - if ( osDeleteFileA(zConverted) ){ - rc = SQLITE_OK; /* Deleted OK. */ - break; - } - if ( !winRetryIoerr(&cnt, &lastErrno) ){ - rc = SQLITE_ERROR; /* No more retries. */ - break; + do { + attr = osGetFileAttributesW(zConverted); + if ( attr==INVALID_FILE_ATTRIBUTES ){ + lastErrno = osGetLastError(); + if( lastErrno==ERROR_FILE_NOT_FOUND + || lastErrno==ERROR_PATH_NOT_FOUND ){ + rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ + }else{ + rc = SQLITE_ERROR; } - } while(1); - } -#endif + break; + } + if ( attr&FILE_ATTRIBUTE_DIRECTORY ){ + rc = SQLITE_ERROR; /* Files only. */ + break; + } + if ( osDeleteFileW(zConverted) ){ + rc = SQLITE_OK; /* Deleted OK. */ + break; + } + if ( !winRetryIoerr(&cnt, &lastErrno) ){ + rc = SQLITE_ERROR; /* No more retries. */ + break; + } + } while(1); if( rc && rc!=SQLITE_IOERR_DELETE_NOENT ){ rc = winLogError(SQLITE_IOERR_DELETE, lastErrno, "winDelete", zFilename); }else{ @@ -54636,9 +54020,11 @@ static int winAccess( ){ DWORD attr; int rc = 0; + int cnt = 0; DWORD lastErrno = 0; - void *zConverted; + LPWSTR zConverted; int noRetry = 0; /* Do not use winRetryIoerr() */ + WIN32_FILE_ATTRIBUTE_DATA sAttrData; UNUSED_PARAMETER(pVfs); if( (flags & NORETRY)!=0 ){ @@ -54662,44 +54048,35 @@ static int winAccess( OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename)); return SQLITE_IOERR_NOMEM_BKPT; } - if( osIsNT() ){ - int cnt = 0; - WIN32_FILE_ATTRIBUTE_DATA sAttrData; - memset(&sAttrData, 0, sizeof(sAttrData)); - while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted, - GetFileExInfoStandard, - &sAttrData)) - && !noRetry - && winRetryIoerr(&cnt, &lastErrno) - ){ /* Loop until true */} - if( rc ){ - /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file - ** as if it does not exist. - */ - if( flags==SQLITE_ACCESS_EXISTS - && sAttrData.nFileSizeHigh==0 - && sAttrData.nFileSizeLow==0 ){ - attr = INVALID_FILE_ATTRIBUTES; - }else{ - attr = sAttrData.dwFileAttributes; - } + memset(&sAttrData, 0, sizeof(sAttrData)); + while( !(rc = osGetFileAttributesExW(zConverted, + GetFileExInfoStandard, + &sAttrData)) + && !noRetry + && winRetryIoerr(&cnt, &lastErrno) + ){ /* Loop until true */} + if( rc ){ + /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file + ** as if it does not exist. + */ + if( flags==SQLITE_ACCESS_EXISTS + && sAttrData.nFileSizeHigh==0 + && sAttrData.nFileSizeLow==0 ){ + attr = INVALID_FILE_ATTRIBUTES; }else{ - if( noRetry ) lastErrno = osGetLastError(); - winLogIoerr(cnt, __LINE__); - if( lastErrno!=ERROR_FILE_NOT_FOUND && lastErrno!=ERROR_PATH_NOT_FOUND ){ - sqlite3_free(zConverted); - return winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess", - zFilename); - }else{ - attr = INVALID_FILE_ATTRIBUTES; - } + attr = sAttrData.dwFileAttributes; + } + }else{ + if( noRetry ) lastErrno = osGetLastError(); + winLogIoerr(cnt, __LINE__); + if( lastErrno!=ERROR_FILE_NOT_FOUND && lastErrno!=ERROR_PATH_NOT_FOUND ){ + sqlite3_free(zConverted); + return winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess", + zFilename); + }else{ + attr = INVALID_FILE_ATTRIBUTES; } } -#ifdef SQLITE_WIN32_HAS_ANSI - else{ - attr = osGetFileAttributesA((char*)zConverted); - } -#endif sqlite3_free(zConverted); switch( flags ){ case SQLITE_ACCESS_READ: @@ -54853,11 +54230,9 @@ static int winFullPathnameNoMutex( int nFull, /* Size of output buffer in bytes */ char *zFull /* Output buffer */ ){ -#if !SQLITE_OS_WINCE int nByte; - void *zConverted; + LPWSTR zConverted; char *zOut; -#endif /* If this path name begins with "/X:" or "\\?\", where "X" is any ** alphabetic character, discard the initial "/" from the pathname. @@ -54874,22 +54249,23 @@ static int winFullPathnameNoMutex( zFull[nFull-1] = '\0'; if( !winIsDriveLetterAndColon(zRelative) || !winIsDirSep(zRelative[2]) ){ int rc = SQLITE_OK; - int nLink = 1; /* Number of symbolic links followed so far */ - const char *zIn = zRelative; /* Input path for each iteration of loop */ + int nLink = 1; /* Number of symbolic links followed so far */ + const char *zIn = zRelative; /* Input path for each iteration of loop */ char *zDel = 0; struct stat buf; UNUSED_PARAMETER(pVfs); do { - /* Call lstat() on path zIn. Set bLink to true if the path is a symbolic - ** link, or false otherwise. */ + /* Call lstat() on path zIn. Set bLink to true if the path + ** is a symbolic link, or false otherwise. */ int bLink = 0; if( osLstat && osReadlink ) { if( osLstat(zIn, &buf)!=0 ){ int myErrno = osErrno; if( myErrno!=ENOENT ){ - rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)myErrno, "lstat", zIn); + rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)myErrno, + "lstat", zIn); } }else{ bLink = ((buf.st_mode & 0170000) == 0120000); @@ -54906,7 +54282,8 @@ static int winFullPathnameNoMutex( if( rc==SQLITE_OK ){ nByte = osReadlink(zIn, zDel, nFull-1); if( nByte ==(DWORD)-1 ){ - rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)osErrno, "readlink", zIn); + rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)osErrno, + "readlink", zIn); }else{ if( zDel[0]!='/' ){ int n; @@ -54942,26 +54319,6 @@ static int winFullPathnameNoMutex( } #endif /* __CYGWIN__ */ -#if SQLITE_OS_WINCE && defined(_WIN32) - SimulateIOError( return SQLITE_ERROR ); - /* WinCE has no concept of a relative pathname, or so I am told. */ - /* WinRT has no way to convert a relative path to an absolute one. */ - if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ - /* - ** NOTE: We are dealing with a relative path name and the data - ** directory has been set. Therefore, use it as the basis - ** for converting the relative path name to an absolute - ** one by prepending the data directory and a backslash. - */ - sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s", - sqlite3_data_directory, winGetDirSep(), zRelative); - }else{ - sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative); - } - return SQLITE_OK; -#endif - -#if !SQLITE_OS_WINCE #if defined(_WIN32) /* 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 @@ -54985,21 +54342,21 @@ static int winFullPathnameNoMutex( if( zConverted==0 ){ return SQLITE_IOERR_NOMEM_BKPT; } - if( osIsNT() ){ + { LPWSTR zTemp; - nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0); + nByte = osGetFullPathNameW(zConverted, 0, 0, 0); if( nByte==0 ){ sqlite3_free(zConverted); return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(), "winFullPathname1", zRelative); } nByte += 3; - zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) ); + zTemp = sqlite3MallocZero( (u64)nByte*sizeof(WCHAR) ); if( zTemp==0 ){ sqlite3_free(zConverted); return SQLITE_IOERR_NOMEM_BKPT; } - nByte = osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0); + nByte = osGetFullPathNameW(zConverted, nByte, zTemp, 0); if( nByte==0 ){ sqlite3_free(zConverted); sqlite3_free(zTemp); @@ -55010,32 +54367,6 @@ static int winFullPathnameNoMutex( zOut = winUnicodeToUtf8(zTemp); sqlite3_free(zTemp); } -#ifdef SQLITE_WIN32_HAS_ANSI - else{ - char *zTemp; - nByte = osGetFullPathNameA((char*)zConverted, 0, 0, 0); - if( nByte==0 ){ - sqlite3_free(zConverted); - return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(), - "winFullPathname3", zRelative); - } - zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) + 3*sizeof(zTemp[0]) ); - if( zTemp==0 ){ - sqlite3_free(zConverted); - return SQLITE_IOERR_NOMEM_BKPT; - } - nByte = osGetFullPathNameA((char*)zConverted, nByte+3, zTemp, 0); - if( nByte==0 ){ - sqlite3_free(zConverted); - sqlite3_free(zTemp); - return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(), - "winFullPathname4", zRelative); - } - sqlite3_free(zConverted); - zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI()); - sqlite3_free(zTemp); - } -#endif if( zOut ){ #ifdef __CYGWIN__ if( memcmp(zOut, "\\\\?\\", 4) ){ @@ -55062,7 +54393,6 @@ static int winFullPathnameNoMutex( }else{ return SQLITE_IOERR_NOMEM_BKPT; } -#endif } static int winFullPathname( sqlite3_vfs *pVfs, /* Pointer to vfs object */ @@ -55085,21 +54415,14 @@ static int winFullPathname( ** within the shared library, and closing the shared library. */ static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ - HANDLE h; - void *zConverted = winConvertFromUtf8Filename(zFilename); + HANDLE h = 0; + LPWSTR zConverted = winConvertFromUtf8Filename(zFilename); UNUSED_PARAMETER(pVfs); if( zConverted==0 ){ OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); return 0; } - if( osIsNT() ){ - h = osLoadLibraryW((LPCWSTR)zConverted); - } -#ifdef SQLITE_WIN32_HAS_ANSI - else{ - h = osLoadLibraryA((char*)zConverted); - } -#endif + h = osLoadLibraryW ? osLoadLibraryW(zConverted) : 0; OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)h)); sqlite3_free(zConverted); return (void*)h; @@ -55109,16 +54432,16 @@ static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ winGetLastErrorMsg(osGetLastError(), nBuf, zBufOut); } static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){ - FARPROC proc; + FARPROC proc = 0; UNUSED_PARAMETER(pVfs); - proc = osGetProcAddressA((HANDLE)pH, zSym); + proc = osGetProcAddressA ? osGetProcAddressA((HANDLE)pH, zSym) : 0; OSTRACE(("DLSYM handle=%p, symbol=%s, address=%p\n", (void*)pH, zSym, (void*)proc)); return (void(*)(void))proc; } static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){ UNUSED_PARAMETER(pVfs); - osFreeLibrary((HANDLE)pHandle); + if( osFreeLibrary!=0 ) osFreeLibrary((HANDLE)pHandle); OSTRACE(("DLCLOSE handle=%p\n", (void*)pHandle)); } #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ @@ -55167,34 +54490,37 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ e.nXor = 0; e.i = 0; { - SYSTEMTIME x; - osGetSystemTime(&x); - xorMemory(&e, (unsigned char*)&x, sizeof(SYSTEMTIME)); + FILETIME x; + osGetSystemTimeAsFileTime(&x); + xorMemory(&e, (unsigned char*)&x, sizeof(x)); } { DWORD pid = osGetCurrentProcessId(); - xorMemory(&e, (unsigned char*)&pid, sizeof(DWORD)); + xorMemory(&e, (unsigned char*)&pid, sizeof(pid)); } { - DWORD cnt = osGetTickCount(); - xorMemory(&e, (unsigned char*)&cnt, sizeof(DWORD)); + ULONGLONG cnt = osGetTickCount64(); + xorMemory(&e, (unsigned char*)&cnt, sizeof(cnt)); } { LARGE_INTEGER i; osQueryPerformanceCounter(&i); - xorMemory(&e, (unsigned char*)&i, sizeof(LARGE_INTEGER)); + xorMemory(&e, (unsigned char*)&i, sizeof(i)); } -#if !SQLITE_OS_WINCE && SQLITE_WIN32_USE_UUID +#if SQLITE_WIN32_USE_UUID +#ifdef SQLITE_UWP +# error SQLITE_WIN32_USE_UUID is incompatible with SQLITE_UWP +#endif { UUID id; - memset(&id, 0, sizeof(UUID)); + memset(&id, 0, sizeof(id)); osUuidCreate(&id); - xorMemory(&e, (unsigned char*)&id, sizeof(UUID)); + xorMemory(&e, (unsigned char*)&id, sizeof(id)); memset(&id, 0, sizeof(UUID)); osUuidCreateSequential(&id); - xorMemory(&e, (unsigned char*)&id, sizeof(UUID)); + xorMemory(&e, (unsigned char*)&id, sizeof(id)); } -#endif /* !SQLITE_OS_WINCE && SQLITE_WIN32_USE_UUID */ +#endif /* SQLITE_WIN32_USE_UUID */ return e.nXor>nBuf ? nBuf : e.nXor; #endif /* defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS) */ } @@ -55204,7 +54530,7 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ ** Sleep for a little while. Return the amount of time slept. */ static int winSleep(sqlite3_vfs *pVfs, int microsec){ - sqlite3_win32_sleep((microsec+999)/1000); + osSleep((microsec+999)/1000); UNUSED_PARAMETER(pVfs); return ((microsec+999)/1000)*1000; } @@ -55242,17 +54568,7 @@ static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + (sqlite3_int64)294967296; -#if SQLITE_OS_WINCE - SYSTEMTIME time; - osGetSystemTime(&time); - /* if SystemTimeToFileTime() fails, it returns zero. */ - if (!osSystemTimeToFileTime(&time,&ft)){ - return SQLITE_ERROR; - } -#else osGetSystemTimeAsFileTime( &ft ); -#endif - *piNow = winFiletimeEpoch + ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) + (sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000; @@ -55346,7 +54662,6 @@ SQLITE_API int sqlite3_os_init(void){ winGetSystemCall, /* xGetSystemCall */ winNextSystemCall, /* xNextSystemCall */ }; -#if defined(SQLITE_WIN32_HAS_WIDE) static sqlite3_vfs winLongPathVfs = { 3, /* iVersion */ sizeof(winFile), /* szOsFile */ @@ -55371,7 +54686,6 @@ SQLITE_API int sqlite3_os_init(void){ winGetSystemCall, /* xGetSystemCall */ winNextSystemCall, /* xNextSystemCall */ }; -#endif static sqlite3_vfs winNolockVfs = { 3, /* iVersion */ sizeof(winFile), /* szOsFile */ @@ -55396,7 +54710,6 @@ SQLITE_API int sqlite3_os_init(void){ winGetSystemCall, /* xGetSystemCall */ winNextSystemCall, /* xNextSystemCall */ }; -#if defined(SQLITE_WIN32_HAS_WIDE) static sqlite3_vfs winLongPathNolockVfs = { 3, /* iVersion */ sizeof(winFile), /* szOsFile */ @@ -55421,16 +54734,18 @@ SQLITE_API int sqlite3_os_init(void){ winGetSystemCall, /* xGetSystemCall */ winNextSystemCall, /* xNextSystemCall */ }; -#endif /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==81 ); + assert( ArraySize(aSyscall)==60 ); assert( strcmp(aSyscall[0].zName,"AreFileApisANSI")==0 ); - assert( strcmp(aSyscall[20].zName,"GetFileAttributesA")==0 ); - assert( strcmp(aSyscall[40].zName,"HeapReAlloc")==0 ); - assert( strcmp(aSyscall[60].zName,"WideCharToMultiByte")==0 ); - assert( strcmp(aSyscall[80].zName,"cygwin_conv_path")==0 ); + assert( strcmp(aSyscall[8].zName,"FreeLibrary")==0 ); + assert( strcmp(aSyscall[16].zName,"GetSystemInfo")==0 ); + assert( strcmp(aSyscall[24].zName,"HeapReAlloc")==0 ); + assert( strcmp(aSyscall[32].zName,"MapViewOfFileFromApp")==0 ); + assert( strcmp(aSyscall[40].zName,"UnmapViewOfFile")==0 ); + assert( strcmp(aSyscall[48].zName,"UuidCreate")==0 ); + assert( strcmp(aSyscall[56].zName,"lstat")==0 ); /* get memory map allocation granularity */ memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); @@ -55439,17 +54754,9 @@ SQLITE_API int sqlite3_os_init(void){ assert( winSysInfo.dwPageSize>0 ); sqlite3_vfs_register(&winVfs, 1); - -#if defined(SQLITE_WIN32_HAS_WIDE) sqlite3_vfs_register(&winLongPathVfs, 0); -#endif - sqlite3_vfs_register(&winNolockVfs, 0); - -#if defined(SQLITE_WIN32_HAS_WIDE) sqlite3_vfs_register(&winLongPathNolockVfs, 0); -#endif - #ifndef SQLITE_OMIT_WAL winBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); #endif @@ -58392,6 +57699,7 @@ static void pcache1ResizeHash(PCache1 *p){ if( nNew<256 ){ nNew = 256; } + assert( (nNew & (nNew-1))==0 ); /* nNew is always a power of two */ pcache1LeaveMutex(p->pGroup); if( p->nHash ){ sqlite3BeginBenignMalloc(); } @@ -58403,7 +57711,7 @@ static void pcache1ResizeHash(PCache1 *p){ PgHdr1 *pPage; PgHdr1 *pNext = p->apHash[i]; while( (pPage = pNext)!=0 ){ - unsigned int h = pPage->iKey % nNew; + unsigned int h = (unsigned int)(pPage->iKey & (nNew-1)); pNext = pPage->pNext; pPage->pNext = apNew[h]; apNew[h] = pPage; @@ -58453,7 +57761,8 @@ static void pcache1RemoveFromHash(PgHdr1 *pPage, int freeFlag){ PgHdr1 **pp; assert( sqlite3_mutex_held(pCache->pGroup->mutex) ); - h = pPage->iKey % pCache->nHash; + assert( pCache->nHash>0 && (pCache->nHash & (pCache->nHash-1))==0 ); + h = pPage->iKey & (pCache->nHash-1); for(pp=&pCache->apHash[h]; (*pp)!=pPage; pp=&(*pp)->pNext); *pp = (*pp)->pNext; @@ -58498,14 +57807,14 @@ static void pcache1TruncateUnsafe( unsigned int h, iStop; assert( sqlite3_mutex_held(pCache->pGroup->mutex) ); assert( pCache->iMaxKey >= iLimit ); - assert( pCache->nHash > 0 ); + assert( pCache->nHash>0 && (pCache->nHash & (pCache->nHash-1))==0 ); if( pCache->iMaxKey - iLimit < pCache->nHash ){ /* If we are just shaving the last few pages off the end of the ** cache, then there is no point in scanning the entire hash table. ** Only scan those hash slots that might contain pages that need to ** be removed. */ - h = iLimit % pCache->nHash; - iStop = pCache->iMaxKey % pCache->nHash; + h = iLimit & (pCache->nHash-1); + iStop = pCache->iMaxKey & (pCache->nHash-1); TESTONLY( nPage = -10; ) /* Disable the pCache->nPage validity check */ }else{ /* This is the general case where many pages are being removed. @@ -58530,7 +57839,7 @@ static void pcache1TruncateUnsafe( } } if( h==iStop ) break; - h = (h+1) % pCache->nHash; + h = (h+1) & (pCache->nHash-1); } assert( nPage<0 || pCache->nPage==(unsigned)nPage ); } @@ -58742,6 +58051,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( if( pCache->nPage>=pCache->nHash ) pcache1ResizeHash(pCache); assert( pCache->nHash>0 && pCache->apHash ); + assert( (pCache->nHash & (pCache->nHash-1))==0 ); /* Step 4. Try to recycle a page. */ if( pCache->bPurgeable @@ -58770,7 +58080,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( } if( pPage ){ - unsigned int h = iKey % pCache->nHash; + unsigned int h = iKey & (pCache->nHash-1); pCache->nPage++; pPage->iKey = iKey; pPage->pNext = pCache->apHash[h]; @@ -58854,8 +58164,11 @@ static PgHdr1 *pcache1FetchNoMutex( PCache1 *pCache = (PCache1 *)p; PgHdr1 *pPage = 0; - /* Step 1: Search the hash table for an existing entry. */ - pPage = pCache->apHash[iKey % pCache->nHash]; + /* Step 1: Search the hash table for an existing entry. nHash is always + ** a power of two when the cache is in use (see pcache1ResizeHash()), so + ** the modulo reduces to a mask, avoiding a hardware divide. */ + assert( pCache->nHash>0 && (pCache->nHash & (pCache->nHash-1))==0 ); + pPage = pCache->apHash[iKey & (pCache->nHash-1u)]; while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; } /* Step 2: If the page was found in the hash table, then return it. @@ -58974,7 +58287,8 @@ static void pcache1Rekey( pcache1EnterMutex(pCache->pGroup); assert( pcache1FetchNoMutex(p, iOld, 0)==pPage ); /* pPg really is iOld */ - hOld = iOld%pCache->nHash; + assert( pCache->nHash>0 && (pCache->nHash & (pCache->nHash-1))==0 ); + hOld = iOld & (pCache->nHash-1); pp = &pCache->apHash[hOld]; while( (*pp)!=pPage ){ pp = &(*pp)->pNext; @@ -58982,7 +58296,7 @@ static void pcache1Rekey( *pp = pPage->pNext; assert( pcache1FetchNoMutex(p, iNew, 0)==0 ); /* iNew not in cache */ - hNew = iNew%pCache->nHash; + hNew = iNew & (pCache->nHash-1); pPage->iKey = iNew; pPage->pNext = pCache->apHash[hNew]; pCache->apHash[hNew] = pPage; @@ -59815,6 +59129,10 @@ SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db); SQLITE_PRIVATE int sqlite3WalSystemErrno(Wal*); #endif +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_WALSTAT) +SQLITE_PRIVATE void sqlite3WalStat(Wal*,sqlite3_str*); +#endif + #endif /* ifndef SQLITE_OMIT_WAL */ #endif /* SQLITE_WAL_H */ @@ -60502,6 +59820,7 @@ struct Pager { #ifdef SQLITE_ENABLE_SETLK_TIMEOUT sqlite3 *dbWal; #endif + sqlite3* mcDb; }; /* @@ -61080,6 +60399,41 @@ static void freeSuperJournal(char *zSuper){ } } +/* +** Check if zSuper is a valid super-journal name. There are two valid +** formats: +** +** + The 3rd and 4th last bytes of the filename are ".9", and the +** following 2 bytes are hex digits. This is a file created in 8.3 +** filenames mode. +** +** + The 3rd last byte of the filename is "9" and the filename +** contains the string "-mj" starting at the 12th last byte. +** All bytes following the "-mj" are hex digits. +** +** If the filename matches either of these patterns, return non-zero. +** Otherwise, return zero. +*/ +static int pagerIsSuperJrnlName(const char *zSuper){ + const int nSuper = sqlite3Strlen30(zSuper); + int ii; + +#ifdef SQLITE_ENABLE_8_3_NAMES + if( nSuper<4 ) return 0; + if( zSuper[nSuper-3]!='9' ) return 0; + if( sqlite3Isxdigit(zSuper[nSuper-2])==0 ) return 0; + if( sqlite3Isxdigit(zSuper[nSuper-1])==0 ) return 0; + if( zSuper[nSuper-4]=='.' ) return 1; +#endif + if( nSuper<12 ) return 0; + if( memcmp(&zSuper[nSuper-12], "-mj", 3) ) return 0; + if( zSuper[nSuper-3]!='9' ) return 0; + for(ii=nSuper-9; iisetSuper==0 ); assert( !pagerUseWal(pPager) ); + assert( zSuper==0 || pagerIsSuperJrnlName(zSuper) ); if( !zSuper || pPager->journalMode==PAGER_JOURNALMODE_MEMORY @@ -61804,7 +61161,7 @@ static int pagerFlushOnCommit(Pager *pPager, int bCommit){ ** database transaction. ** ** This routine is never called in PAGER_ERROR state. If it is called -** in PAGER_NONE or PAGER_SHARED state and the lock held is less +** in PAGER_OPEN or PAGER_READER state and the lock held is less ** exclusive than a RESERVED lock, it is a no-op. ** ** Otherwise, any active savepoints are released. @@ -62299,40 +61656,6 @@ static int pager_playback_one_page( return rc; } -/* -** Check if zSuper is a valid super-journal name. There are two valid -** formats: -** -** + The 3rd and 4th last bytes of the filename are ".9", and the -** following 2 bytes are hex digits. This is a file created in 8.3 -** filenames mode. -** -** + The 3rd last byte of the filename is "9" and the filename -** contains the string "-mj" starting at the 12th last byte. -** All bytes following the "-mj" are hex digits. -** -** If the filename matches either of these patterns, return non-zero. -** Otherwise, return zero. -*/ -static int pagerIsSuperJrnlName(const char *zSuper){ - const int nSuper = sqlite3Strlen30(zSuper); - int ii; - - if( nSuper<4 ) return 0; - if( zSuper[nSuper-3]!='9' ) return 0; -#ifdef SQLITE_ENABLE_8_3_NAMES - if( sqlite3Isxdigit(zSuper[nSuper-2])==0 ) return 0; - if( sqlite3Isxdigit(zSuper[nSuper-1])==0 ) return 0; - if( zSuper[nSuper-4]=='.' ) return 1; -#endif - if( nSuper<12 ) return 0; - if( memcmp(&zSuper[nSuper-12], "-mj", 3) ) return 0; - for(ii=nSuper-9; iipVfs, 0, pFile, vfsFlags, 0); assert( rc!=SQLITE_OK || isOpen(pFile) ); + sqlite3mcOpenTempFile(pPager, pFile); return rc; } @@ -63600,7 +62928,7 @@ SQLITE_PRIVATE void sqlite3PagerSetBusyHandler( ** ** then the pager object page size is set to *pPageSize. ** -** If the page size is changed, then this function uses sqlite3PagerMalloc() +** If the page size is changed, then this function uses sqlite3PageMalloc() ** to obtain a new Pager.pTmpSpace buffer. If this allocation attempt ** fails, SQLITE_NOMEM is returned and the page size remains unchanged. ** In all other cases, SQLITE_OK is returned. @@ -64374,6 +63702,7 @@ static int openSubJournal(Pager *pPager){ nStmtSpill = -1; } rc = sqlite3JournalOpen(pPager->pVfs, 0, pPager->sjfd, flags, nStmtSpill); + sqlite3mcOpenTempFile(pPager, pPager->sjfd); } return rc; } @@ -64791,7 +64120,15 @@ SQLITE_PRIVATE int sqlite3PagerOpen( */ if( zFilename && zFilename[0] ){ int fout = 0; /* VFS flags returned by xOpen() */ + int bImmutable = sqlite3_uri_boolean(pPager->zFilename, "immutable", 0); + if( bImmutable ){ + vfsFlags |= SQLITE_OPEN_READONLY; + vfsFlags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); + } rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout); + if( bImmutable ){ + goto act_like_temp_file; + } assert( !memDb ); pPager->memVfs = memJM = (fout&SQLITE_OPEN_MEMORY)!=0; readOnly = (fout&SQLITE_OPEN_READONLY)!=0; @@ -64831,10 +64168,9 @@ SQLITE_PRIVATE int sqlite3PagerOpen( #endif } pPager->noLock = sqlite3_uri_boolean(pPager->zFilename, "nolock", 0); - if( (iDc & SQLITE_IOCAP_IMMUTABLE)!=0 - || sqlite3_uri_boolean(pPager->zFilename, "immutable", 0) ){ - vfsFlags |= SQLITE_OPEN_READONLY; - goto act_like_temp_file; + if( (iDc & SQLITE_IOCAP_IMMUTABLE)!=0 ){ + vfsFlags |= SQLITE_OPEN_READONLY; + goto act_like_temp_file; } } }else{ @@ -64854,6 +64190,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen( pPager->eLock = EXCLUSIVE_LOCK; /* Pretend we are in EXCLUSIVE mode */ pPager->noLock = 1; /* Do no locking */ readOnly = (vfsFlags&SQLITE_OPEN_READONLY); + assert( readOnly==0 || readOnly==1 ); } /* The following call to PagerSetPagesize() serves to set the value of @@ -64947,8 +64284,8 @@ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char *zName){ /* -** This function is called after transitioning from PAGER_UNLOCK to -** PAGER_SHARED state. It tests if there is a hot journal present in +** This function is called while transitioning from PAGER_OPEN to a +** higher state. It tests if there is a hot journal present in ** the file-system for the given pager. A hot journal is one that ** needs to be played back. According to this function, a hot-journal ** file exists if the following criteria are met: @@ -65717,6 +65054,7 @@ static int pager_open_journal(Pager *pPager){ rc = sqlite3JournalOpen ( pVfs, pPager->zJournal, pPager->jfd, flags, nSpill ); + sqlite3mcOpenTempFile(pPager, pPager->jfd); } } assert( rc!=SQLITE_OK || isOpen(pPager->jfd) ); @@ -66674,6 +66012,20 @@ SQLITE_PRIVATE int sqlite3PagerRefcount(Pager *pPager){ } #endif +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_WALSTAT) +/* +** Append JSON structure elements describing the current state of +** the write-ahead log to pStr. +*/ +SQLITE_PRIVATE void sqlite3PagerWalStat(Pager *pPager, sqlite3_str *pStr){ +#ifndef SQLITE_OMIT_WAL + if( pPager->pWal ){ + sqlite3WalStat(pPager->pWal, pStr); + } +#endif +} +#endif + /* ** Return the approximate number of bytes of memory currently ** used by the pager and its associated cache. @@ -68270,10 +67622,41 @@ typedef u16 ht_slot; ** walIteratorFree() - Free an iterator. ** ** This functionality is used by the checkpoint code (see walCheckpoint()). +** +** There are two possible algorithms: +** +** WALITER-1 Load all pages mentioned in the WAL file and sort them, +** then hand them back out in sorted order as requested by +** walIteratorNext(). nPagemap==0 for this algorithm. +** +** WALITER-2 Create a map of all database file pages and record the +** last WAL file frame that updates that page. Then walk +** through the map in acsending order and return all +** non-zero entries. nPagemap is positive for this algorithm. +** +** Either algorithm should work for any database and WAL file, however +** algorithm WALITER-1 is faster and uses less memory when the database is +** larger than the WAL file and algorithm WALITER-2 is faster and uses +** less memory when the WAL file is larger than the database, modulo a +** constant of proportionality. The walIteratorInit() routine selects +** the best algorithm for each situation. WALITER-2 was added for +** SQLite 3.54.0. Prior to that, WALITER-1 was used always. +** +** For algorithm WALITER-2, nPagemap stores the number of pages in the +** database file, nSegment==1, and aSegment[0].aPgno[] is the page map array +** that is nPagemap+1 entries in length. The value of aSegment[0].aPgno[PGNO] +** is the frame number of the last (newest) entry for page PGNO in the WAL +** file, or 0 if PGNO is not in the WAL file. (Aside: There is no page +** number 0 in a well-formed database, so the memory allocation is arranged +** such that aSegment[0].aPgno[0] and aSegment[0].iZero are aliases for the +** same four bits of memory. This saves us from having to use -1 and +1 +** offsets to translate between 1-based SQLite page numbers and 0-based +** C-language index numbers. tag-20260903-1) */ struct WalIterator { u32 iPrior; /* Last result returned from the iterator */ int nSegment; /* Number of entries in aSegment[] */ + u32 nPagemap; /* Non-zero in "page-map" mode */ struct WalSegment { int iNext; /* Next slot in aIndex[] not yet returned */ ht_slot *aIndex; /* i0, i1, i2... such that aPgno[iN] ascend */ @@ -68287,6 +67670,7 @@ struct WalIterator { #define SZ_WALITERATOR(N) \ (offsetof(WalIterator,aSegment)+(N)*sizeof(struct WalSegment)) + /* ** Define the parameters of the hash tables in the wal-index file. There ** is a hash-table following every HASHTABLE_NPAGE page numbers in the @@ -69449,24 +68833,38 @@ static int walIteratorNext( u32 *piPage, /* OUT: The page number of the next page */ u32 *piFrame /* OUT: Wal frame index of next page */ ){ - u32 iMin; /* Result pgno must be greater than iMin */ u32 iRet = 0xFFFFFFFF; /* 0xffffffff is never a valid page number */ - int i; /* For looping through segments */ - - iMin = p->iPrior; - assert( iMin<0xffffffff ); - for(i=p->nSegment-1; i>=0; i--){ - struct WalSegment *pSegment = &p->aSegment[i]; - while( pSegment->iNextnEntry ){ - u32 iPg = pSegment->aPgno[pSegment->aIndex[pSegment->iNext]]; - if( iPg>iMin ){ - if( iPgiZero + pSegment->aIndex[pSegment->iNext]; - } + + if( p->nPagemap ){ + /* Algorithm WALITER-2 */ + while( p->iPriornPagemap ){ + p->iPrior++; + if( p->aSegment[0].aPgno[p->iPrior] ){ + iRet = p->iPrior; + *piFrame = p->aSegment[0].aPgno[p->iPrior]; break; } - pSegment->iNext++; + } + }else{ + /* Algorithm WALITER-1 */ + u32 iMin; /* Result pgno must be greater than iMin */ + int i; /* For looping through segments */ + + iMin = p->iPrior; + assert( iMin<0xffffffff ); + for(i=p->nSegment-1; i>=0; i--){ + struct WalSegment *pSegment = &p->aSegment[i]; + while( pSegment->iNextnEntry ){ + u32 iPg = pSegment->aPgno[pSegment->aIndex[pSegment->iNext]]; + if( iPg>iMin ){ + if( iPgiZero + pSegment->aIndex[pSegment->iNext]; + } + break; + } + pSegment->iNext++; + } } } @@ -69635,35 +69033,59 @@ static void walIteratorFree(WalIterator *p){ ** WalIterator object when it has finished with it. */ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){ + int iFirstPage; /* First 32KB *-shm page to visit */ + int iLastPage; /* Last 32KB *-shm page to visit */ + u32 iZero; /* Frame before first frame to visit */ WalIterator *p; /* Return value */ int nSegment; /* Number of segments to merge */ u32 iLast; /* Last frame in log */ sqlite3_int64 nByte; /* Number of bytes to allocate */ + sqlite3_int64 nExtra; /* Number of bytes to allocate */ int i; /* Iterator variable */ - ht_slot *aTmp; /* Temp space used by merge-sort */ + ht_slot *aTmp = 0; /* Temp space used by merge-sort */ int rc = SQLITE_OK; /* Return Code */ + int eAlg; /* Which algorithm to use. 1 or 2 */ /* This routine only runs while holding the checkpoint lock. And - ** it only runs if there is actually content in the log (mxFrame>0). - */ + ** it only runs if there is actually content in the log (mxFrame>0). */ assert( pWal->ckptLock && pWal->hdr.mxFrame>0 ); + iLast = pWal->hdr.mxFrame; + iFirstPage = walFramePage(nBackfill+1); + iLastPage = walFramePage(iLast); + iZero = iFirstPage ? (HASHTABLE_NPAGE_ONE+(iFirstPage-1)*HASHTABLE_NPAGE) : 0; + + if( (iLast-iZero)*sizeof(ht_slot)>pWal->hdr.nPage*sizeof(u32) ){ + /* Algorithm WALITER-2 */ + nSegment = 1; + eAlg = 2; + nByte = SZ_WALITERATOR(nSegment) + pWal->hdr.nPage * sizeof(u32); + nExtra = 0; + }else{ + /* Algorithm WALITER-1 */ + nSegment = iLastPage - iFirstPage + 1; + eAlg = 1; + nByte = SZ_WALITERATOR(nSegment) + (iLast-iZero)*sizeof(ht_slot); + nExtra = sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast); + } /* Allocate space for the WalIterator object. */ - nSegment = walFramePage(iLast) + 1; - nByte = SZ_WALITERATOR(nSegment) - + iLast*sizeof(ht_slot); - p = (WalIterator *)sqlite3_malloc64(nByte - + sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast) - ); + p = (WalIterator *)sqlite3_malloc64(nByte + nExtra); if( !p ){ return SQLITE_NOMEM_BKPT; } memset(p, 0, nByte); p->nSegment = nSegment; - aTmp = (ht_slot*)&(((u8*)p)[nByte]); + if( eAlg==2 ){ + p->nPagemap = pWal->hdr.nPage; + p->aSegment[0].aPgno = ((u32*)&p->aSegment[1]) - 1; + assert( (u8*)&(p->aSegment[0].aPgno[0]) == (u8*)&(p->aSegment[0].iZero) ); + /* ^-- verifies tag-20260903-1 */ + }else{ + aTmp = (ht_slot*)&(((u8*)p)[nByte]); + } SEH_FREE_ON_ERROR(0, p); - for(i=walFramePage(nBackfill+1); rc==SQLITE_OK && iaSegment[p->nSegment])[sLoc.iZero]; - sLoc.iZero++; - for(j=0; jaSegment[0].aPgno; + for(j=0; jnPagemap ){ + aPagemap[pgno] = sLoc.iZero + j + 1; + } + } + }else{ + assert( i!=iFirstPage || iZero==sLoc.iZero ); + aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[sLoc.iZero - iZero]; + sLoc.iZero++; + + for(j=0; jaSegment[i-iFirstPage].iZero = sLoc.iZero; + p->aSegment[i-iFirstPage].nEntry = nEntry; + p->aSegment[i-iFirstPage].aIndex = aIndex; + p->aSegment[i-iFirstPage].aPgno = (u32 *)sLoc.aPgno; } - walMergesort((u32 *)sLoc.aPgno, aTmp, aIndex, &nEntry); - p->aSegment[i].iZero = sLoc.iZero; - p->aSegment[i].nEntry = nEntry; - p->aSegment[i].aIndex = aIndex; - p->aSegment[i].aPgno = (u32 *)sLoc.aPgno; } } if( rc!=SQLITE_OK ){ @@ -71348,11 +70782,15 @@ SQLITE_PRIVATE int sqlite3WalReadFrame( i64 iOffset; sz = pWal->hdr.szPage; sz = (sz&0xfe00) + ((sz&0x0001)<<16); + if( nOut>sz ){ + memset(pOut+sz, 0, nOut-sz); + nOut = sz; + } testcase( sz<=32768 ); testcase( sz>=65536 ); iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE; /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */ - return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset); + return sqlite3OsRead(pWal->pWalFd, pOut, nOut, iOffset); } /* @@ -72325,6 +71763,64 @@ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){ return pWal->pWalFd; } +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_WALSTAT) +/* +** Helper function to sqlite3WalStat(). +** +** Append JSON-5 structure elements onto describing the current state +** of pWal onto the end of pStr. This function is for debugging and +** analysis only and is not included in production builds. +*/ +static void walIndexHdrStat(volatile WalIndexHdr *pHdr, sqlite3_str *pStr){ + sqlite3_str_appendf(pStr, "iVersion:%u",pHdr->iVersion); + sqlite3_str_appendf(pStr, ",iChange:%u",pHdr->iChange); + sqlite3_str_appendf(pStr, ",isInit:%u",pHdr->isInit); + sqlite3_str_appendf(pStr, ",bigEndCksum:%u",pHdr->bigEndCksum); + sqlite3_str_appendf(pStr, ",szPage:%u",pHdr->szPage); + sqlite3_str_appendf(pStr, ",mxFrame:%u",pHdr->mxFrame); + sqlite3_str_appendf(pStr, ",nPage:%u",pHdr->nPage); +#if 0 /* Not often needed. Declutter. */ + sqlite3_str_appendf(pStr, ",aFrameCksum:[0x%08x,0x%08x]", + pHdr->aFrameCksum[0], pHdr->aFrameCksum[1]); + sqlite3_str_appendf(pStr, ",aSalt:[0x%08x,0x%08x]", + pHdr->aSalt[0], pHdr->aSalt[1]); + sqlite3_str_appendf(pStr, ",aCksum:[0x%08x,0x%08x]", + pHdr->aCksum[0], pHdr->aCksum[1]); +#endif +} +#endif /* SQLITE_DEBUG || SQLITE_ENABLE_WALSTAT */ + + +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_WALSTAT) +/* +** Append JSON-5 structure elements onto describing the current state +** of pWal onto the end of pStr. This function is for debugging and +** analysis only and is not included in production builds. +*/ +SQLITE_PRIVATE void sqlite3WalStat(Wal *pWal, sqlite3_str *pStr){ + SEH_TRY { + int i; + volatile WalCkptInfo *pInfo = walCkptInfo(pWal); + volatile WalIndexHdr *pHdr = walIndexHdr(pWal); + sqlite3_str_appendf(pStr, "hdr0:{"); + walIndexHdrStat(pHdr,pStr); + sqlite3_str_appendf(pStr, "},ckpt:{"); + sqlite3_str_appendf(pStr, "nBackfill:%u",pInfo->nBackfill); + sqlite3_str_appendf(pStr, ",aReadMark:[%u", pInfo->aReadMark[0]); + for(i=1; iaReadMark[i]); + } + sqlite3_str_appendf(pStr, "],nBackfillAttempted:%u}", + pInfo->nBackfillAttempted); + + sqlite3_str_appendf(pStr, ",nWiData:%d", pWal->nWiData); + sqlite3_str_appendf(pStr, ",readLock:%d", pWal->readLock); + sqlite3_str_appendf(pStr, ",minFrame:%u", pWal->minFrame); + } + SEH_EXCEPT( ; ) +} +#endif /* SQLITE_DEBUG || SQLITE_ENABLE_WALSTAT */ + #endif /* #ifndef SQLITE_OMIT_WAL */ /************** End of wal.c *************************************************/ @@ -72888,6 +72384,9 @@ struct BtCursor { Btree *pBtree; /* The Btree to which this cursor belongs */ Pgno *aOverflow; /* Cache of overflow page locations */ void *pKey; /* Saved key that was cursor last known position */ +#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG) + BtCursor *pCursorHintTableCursor; +#endif /* All fields above are zeroed when the cursor is allocated. See ** sqlite3BtreeCursorZero(). Fields that follow must be manually ** initialized. */ @@ -73056,6 +72555,7 @@ struct IntegrityCk { 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 */ + u8 nAbove; /* Current btree recursion depth */ 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) */ @@ -73405,6 +72905,16 @@ SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){ */ /* #include "btreeInt.h" */ +/* +** Suppress false-positive compiler warnings from GCC. Warnings are +** re-enabled at the bottom of this source file. +*/ +#if defined(__GNUC__) && __GNUC__>=11 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wstringop-overread" +# pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif + /* ** The header string that appears at the beginning of every ** SQLite database. @@ -74385,24 +73895,41 @@ 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; + va_list ap; + va_start(ap, eHintType); + if( eHintType==BTREE_HINT_RANGE ){ 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); + }else if( ALWAYS(eHintType==BTREE_HINT_TABLECURSOR) ){ + BtCursor *pCsr = va_arg(ap, BtCursor*); + assert( pCur->pCursorHintTableCursor==0 + || pCur->pCursorHintTableCursor==pCsr + ); + assert( pCsr->pKeyInfo==0 || CORRUPT_DB ); + pCur->pCursorHintTableCursor = pCsr; } + va_end(ap); #endif /* SQLITE_DEBUG */ } #endif /* SQLITE_ENABLE_CURSOR_HINTS */ +#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG) +/* +** Return the pointer configured via the BTREE_HINT_TABLECURSOR hint on +** cursor pCsr. This is used from OP_DeferredSeek to assert() that the +** index cursor has been correctly configured with the table cursor. +*/ +SQLITE_PRIVATE BtCursor *sqlite3BtreeCursorHintTblCsr(BtCursor *pCsr){ + return pCsr->pCursorHintTableCursor; +} +#endif /* ** Provide flag hints to the cursor. @@ -74640,7 +74167,7 @@ static void btreeParseCellPtrNoPayload( #ifndef SQLITE_DEBUG UNUSED_PARAMETER(pPage); #endif - pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey); + pInfo->nSize = 4 + sqlite3GetVarint(&pCell[4], (u64*)&pInfo->nKey); pInfo->nPayload = 0; pInfo->nLocal = 0; pInfo->pPayload = 0; @@ -74680,7 +74207,7 @@ static void btreeParseCellPtr( /* The next block of code is equivalent to: ** - ** pIter += getVarint(pIter, (u64*)&pInfo->nKey); + ** pIter += sqlite3GetVarint(pIter, (u64*)&pInfo->nKey); ** ** The code is inlined and the loop is unrolled for performance. ** This routine is a high-runner. @@ -75528,8 +75055,11 @@ static int btreeComputeFreeSpace(MemPage *pPage){ } next = get2byte(&data[pc]); size = get2byte(&data[pc+2]); - if( size<4 ){ - /* Minimum freeblock size is 4 */ + if( size<4 && sqlite3FaultSim(422)==SQLITE_OK ){ + /* Minimum freeblock size is 4. Enable fault-sim 422 to disable this + ** check to reach interesting error states. However, disabling this + ** check can cause assertion faults due to min-heap overflow. All + ** fault-sims are for testing use only, but this one especially so. */ return SQLITE_CORRUPT_PAGE(pPage); } nFree = nFree + size; @@ -76072,6 +75602,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename, sizeof(MemPage), flags, vfsFlags, pageReinit); if( rc==SQLITE_OK ){ + pBt->pPager->mcDb = db; sqlite3PagerSetMmapLimit(pBt->pPager, db->szMmap); rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader); } @@ -78688,7 +78219,9 @@ static int accessPayload( if( rc==SQLITE_OK ){ if( eOp!=0 && (sqlite3PagerPageRefcount(pDbPage)!=1 - || NEVER(((MemPage*)sqlite3PagerGetExtra(pDbPage))->isInit)) ){ + || NEVER(((MemPage*)sqlite3PagerGetExtra(pDbPage))->isInit)) + && sqlite3FaultSim(411)==SQLITE_OK + ){ sqlite3PagerUnref(pDbPage); return SQLITE_CORRUPT_PAGE(pPage); } @@ -79286,7 +78819,7 @@ SQLITE_PRIVATE int sqlite3BtreeTableMoveto( } } } - getVarint(pCell, (u64*)&nCellKey); + nCellKey = sqlite3VarintValue(pCell); if( nCellKeyupr ){ c = -1; break; } @@ -79341,12 +78874,12 @@ SQLITE_PRIVATE int sqlite3BtreeTableMoveto( ** zero if the cell is less than or equal pIdxKey. Return positive ** if unknown. ** -** Return value negative: Cell at pCur[idx] less than pIdxKey +** Return value negative: Cell at pPage[idx] less than pIdxKey ** -** Return value is zero: Cell at pCur[idx] equals pIdxKey +** Return value is zero: Cell at pPage[idx] equals pIdxKey ** ** Return value positive: Nothing is known about the relationship -** of the cell at pCur[idx] and pIdxKey. +** of the cell at pPage[idx] and pIdxKey. ** ** This routine is part of an optimization. It is always safe to return ** a positive value as that will cause the optimization to be skipped. @@ -80493,7 +80026,7 @@ static int fillInCell( nSrc = pX->nData; assert( pPage->intKeyLeaf ); /* fillInCell() only called for leaves */ nHeader += putVarint32(&pCell[nHeader], nPayload); - nHeader += putVarint(&pCell[nHeader], *(u64*)&pX->nKey); + nHeader += sqlite3PutVarint(&pCell[nHeader], *(u64*)&pX->nKey); }else{ assert( pX->nKey<=0x7fffffff && pX->pKey!=0 ); nSrc = nPayload = (int)pX->nKey; @@ -82242,7 +81775,7 @@ static int balance_nonroot( j--; pNew->xParseCell(pNew, b.apCell[j], &info); pCell = pTemp; - sz = 4 + putVarint(&pCell[4], info.nKey); + sz = 4 + sqlite3PutVarint(&pCell[4], info.nKey); pTemp = 0; }else{ pCell -= 4; @@ -83127,7 +82660,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 }else{ aOut += sqlite3PutVarint(aOut, pSrc->info.nPayload); } - if( pDest->pKeyInfo==0 ) aOut += putVarint(aOut, iKey); + if( pDest->pKeyInfo==0 ) aOut += sqlite3PutVarint(aOut, iKey); nIn = pSrc->info.nLocal; aIn = pSrc->info.pPayload; if( aIn+nIn>pSrc->pPage->aDataEnd ){ @@ -83366,7 +82899,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ assert( pTmp!=0 ); rc = sqlite3PagerWrite(pLeaf->pDbPage); if( rc==SQLITE_OK ){ - rc = insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n); + rc = insertCell(pPage, iCellIdx, pCell-4, nCell+4-(pCell[0]==2), pTmp, n); } dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc); if( rc ) return rc; @@ -83597,11 +83130,20 @@ SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree *p, Pgno *piTable, int flags){ /* ** Erase the given database page and all its children. Return ** the page to the freelist. +** +** The freePageFlag parameter serves a double role: +** +** * Bit 0 (freePageFlag&1) means that the page should be freed +** after it is cleared. +** +** * Bits 1-31 (freePageFlag>>1) is the depth of recursion. Use this +** to prevent a corrupt database file from recursing too deeply and +** overflowing the CPU stack. */ static int clearDatabasePage( BtShared *pBt, /* The BTree that contains the table */ Pgno pgno, /* Page number to clear */ - int freePageFlag, /* Deallocate page if true */ + int freePageFlag, /* bit 0: Deallocate page. Bits 1-31: depth */ i64 *pnChange /* Add number of Cells freed to this counter */ ){ MemPage *pPage; @@ -83615,6 +83157,9 @@ static int clearDatabasePage( if( pgno>btreePagecount(pBt) ){ return SQLITE_CORRUPT_PGNO(pgno); } + if( (freePageFlag>>1) > BTCURSOR_MAX_DEPTH ){ + return SQLITE_CORRUPT_PGNO(pgno); + } rc = getAndInitPage(pBt, pgno, &pPage, 0); if( rc ) return rc; if( (pBt->openFlags & BTREE_SINGLE)==0 @@ -83627,14 +83172,16 @@ static int clearDatabasePage( for(i=0; inCell; i++){ pCell = findCell(pPage, i); if( !pPage->leaf ){ - rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange); + rc = clearDatabasePage(pBt, get4byte(pCell), + (freePageFlag+2)|1, pnChange); if( rc ) goto cleardatabasepage_out; } BTREE_CLEAR_CELL(rc, pPage, pCell, info); if( rc ) goto cleardatabasepage_out; } if( !pPage->leaf ){ - rc = clearDatabasePage(pBt, get4byte(&pPage->aData[hdr+8]), 1, pnChange); + rc = clearDatabasePage(pBt, get4byte(&pPage->aData[hdr+8]), + (freePageFlag+2)|1, pnChange); if( rc ) goto cleardatabasepage_out; if( pPage->intKey ) pnChange = 0; } @@ -83642,7 +83189,7 @@ static int clearDatabasePage( testcase( !pPage->intKey ); *pnChange += pPage->nCell; } - if( freePageFlag ){ + if( (freePageFlag&1)!=0 ){ freePage(pPage, &rc); }else if( (rc = sqlite3PagerWrite(pPage->pDbPage))==0 ){ zeroPage(pPage, pPage->aData[hdr] | PTF_LEAF); @@ -83772,6 +83319,9 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){ } pMove = 0; rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3PagerWrite(pMove->pDbPage); + } freePage(pMove, &rc); releasePage(pMove); if( rc!=SQLITE_OK ){ @@ -84277,19 +83827,24 @@ static int checkTreePage( /* Check that the page exists */ checkProgress(pCheck); - if( pCheck->mxErr==0 ) goto end_of_check; + if( pCheck->mxErr==0 ) return 0; pBt = pCheck->pBt; usableSize = pBt->usableSize; if( iPage==0 ) return 0; if( checkRef(pCheck, iPage) ) return 0; pCheck->zPfx = "Tree %u page %u: "; pCheck->v1 = iPage; + pCheck->nAbove++; 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; } + if( pCheck->nAbove > BTCURSOR_MAX_DEPTH ){ + checkAppendMsg(pCheck,"btree depth exceeds %d",BTCURSOR_MAX_DEPTH); + goto end_of_check; + } /* Clear MemPage.isInit to make sure the corruption detection code in ** btreeInitPage() is executed. */ @@ -84369,6 +83924,11 @@ static int checkTreePage( doCoverageCheck = 0; continue; } + if( info.nPayload && info.pPayload[0]<2 ){ + checkAppendMsg(pCheck, "Bad cell header size"); + doCoverageCheck = 0; + continue; + } /* Check for integer primary key out of range */ if( pPage->intKey ){ @@ -84410,7 +83970,7 @@ static int checkTreePage( } }else{ /* Populate the coverage-checking heap for leaf pages */ - assert( heap[0] < pCheck->mxHeap ); + assert( heap!=0 && heap[0] < pCheck->mxHeap ); btreeHeapInsert(heap, (pc<<16)|(pc+info.nSize-1)); } } @@ -84430,7 +83990,7 @@ static int checkTreePage( u32 size; pc = get2byteAligned(&data[cellStart+i*2]); size = pPage->xCellSize(pPage, &data[pc]); - assert( heap[0] < pCheck->mxHeap ); + assert( heap!=0 && heap[0] < pCheck->mxHeap ); btreeHeapInsert(heap, (pc<<16)|(pc+size-1)); } } @@ -84447,7 +84007,7 @@ static int checkTreePage( assert( (u32)i<=usableSize-4 ); /* Enforced by btreeComputeFreeSpace() */ size = get2byte(&data[i+2]); assert( (u32)(i+size)<=usableSize ); /* due to btreeComputeFreeSpace() */ - assert( heap[0] < pCheck->mxHeap ); + assert( heap!=0 && heap[0] < pCheck->mxHeap ); btreeHeapInsert(heap, (((u32)i)<<16)|(i+size-1)); /* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a ** big-endian integer which is the offset in the b-tree page of the next @@ -84504,6 +84064,7 @@ static int checkTreePage( pCheck->zPfx = saved_zPfx; pCheck->v1 = saved_v1; pCheck->v2 = saved_v2; + pCheck->nAbove--; return depth+1; } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ @@ -84581,9 +84142,9 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( checkOom(&sCheck); goto integrity_ck_cleanup; } - sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize ); + sCheck.heap = (u32*)sqlite3Malloc( pBt->pageSize*2 ); #ifdef SQLITE_DEBUG - sCheck.mxHeap = pBt->pageSize/4 - 1; + sCheck.mxHeap = pBt->pageSize/2 - 1; #endif if( sCheck.heap==0 ){ checkOom(&sCheck); @@ -84636,7 +84197,9 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( } #endif sCheck.v0 = aRoot[i]; + assert( sCheck.nAbove==0 ); checkTreePage(&sCheck, aRoot[i], ¬Used, LARGEST_INT64); + assert( sCheck.nAbove==0 ); } sqlite3MemSetArrayInt64(aCnt, i, sCheck.nRow); } @@ -84669,7 +84232,7 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( /* Clean up and report errors. */ integrity_ck_cleanup: - sqlite3PageFree(sCheck.heap); + sqlite3_free(sCheck.heap); sqlite3_free(sCheck.aPgRef); *pnErr = sCheck.nErr; if( sCheck.nErr==0 ){ @@ -84978,6 +84541,13 @@ SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){ } #endif +/* Re-enable GCC compiler warnings that were suppressed at the top +** of this source file to prevent annoying false-positives. +*/ +#if defined(__GNUC__) && __GNUC__>=11 +# pragma GCC diagnostic pop +#endif + /************** End of btree.c ***********************************************/ /************** Begin file backup.c ******************************************/ /* @@ -85063,8 +84633,10 @@ struct sqlite3_backup { ** error message to pErrorDb. */ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ - int i = sqlite3FindDbName(pDb, zDb); + int i; + assert( pDb!=0 ); + i = sqlite3FindDbName(pDb, zDb); if( i==1 ){ Parse sParse; int rc = 0; @@ -85899,8 +85471,8 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114659 ** The problem appears to be fixed in GCC 15 */ i64 x; - assert( (MEM_Str&~p->flags)*4==sizeof(x) ); - memcpy(&x, (char*)&p->u, (MEM_Str&~p->flags)*4); + assert( (sqlite3Config.bSmallMalloc!=0xee)*8==sizeof(x) ); + memcpy(&x, (char*)&p->u.i, (sqlite3Config.bSmallMalloc!=0xee)*8); p->n = sqlite3Int64ToText(x, zBuf); #else p->n = sqlite3Int64ToText(p->u.i, zBuf); @@ -87767,7 +87339,30 @@ SQLITE_PRIVATE int sqlite3ValueFromExpr( u8 affinity, /* Affinity to use */ sqlite3_value **ppVal /* Write the new value here */ ){ - return pExpr ? valueFromExpr(db, pExpr, enc, affinity, ppVal, 0) : 0; + int rc = SQLITE_OK; + sqlite3_value *pVal = 0; + if( pExpr ){ + rc = valueFromExpr(db, pExpr, enc, affinity, &pVal, 0); + if( rc==SQLITE_OK && pVal + && affinity==SQLITE_AFF_REAL + && (pVal->flags & MEM_Int) + && (pVal->u.i<-140737488355328LL || pVal->u.i>140737488355327LL) + ){ + /* If the integer value is too large to fit in a 6-byte integer and + ** the affinity is REAL, convert it to a real value now. In most + ** cases an OP_RealAffinity opcode will be used to convert the + ** value to an actual real, but this opcode is omitted if the values + ** are being read directly from a table in order to create an index + ** key. It is important to get a "real" real value for the larger + ** magnitude integer values so that comparisons work correctly - + ** SQLite by default will convert real values to integers before + ** doing the comparison, which is different from converting to real + ** first. */ + sqlite3VdbeMemRealify(pVal); + } + } + *ppVal = pVal; + return rc; } #ifdef SQLITE_ENABLE_STAT4 @@ -87812,7 +87407,7 @@ static int stat4ValueFromExpr( }else if( pExpr->op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){ Vdbe *v; int iBindVar = pExpr->iColumn; - sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar); + sqlite3VdbeReprepareOnBind(pParse->pVdbe, iBindVar, 0); if( (v = pParse->pReprepare)!=0 ){ pVal = valueNew(db, pAlloc); if( pVal ){ @@ -88086,7 +87681,6 @@ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){ assert( pParse->aLabel==0 ); assert( pParse->nLabel==0 ); assert( p->nOpAlloc==0 ); - assert( pParse->szOpAlloc==0 ); sqlite3VdbeAddOp2(p, OP_Init, 0, 1); return p; } @@ -88190,7 +87784,8 @@ SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ pA->zNormSql = pB->zNormSql; pB->zNormSql = zTmp; #endif - pB->expmask = pA->expmask; + pB->expmask |= pA->expmask; + pB->smimask |= pA->smimask; pB->prepFlags = pA->prepFlags; memcpy(pB->aCounter, pA->aCounter, sizeof(pB->aCounter)); pB->aCounter[SQLITE_STMTSTATUS_REPREPARE]++; @@ -88236,8 +87831,7 @@ static int growOpArray(Vdbe *v, int nOp){ assert( nNew>=(v->nOpAlloc+nOp) ); pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op)); if( pNew ){ - p->szOpAlloc = sqlite3DbMallocSize(p->db, pNew); - v->nOpAlloc = p->szOpAlloc/sizeof(Op); + v->nOpAlloc = sqlite3DbMallocSize(p->db, pNew)/sizeof(Op); v->aOp = pNew; } return (pNew ? SQLITE_OK : SQLITE_NOMEM_BKPT); @@ -88409,6 +88003,20 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Int( return i; } +/* Generate an opcode that loads a 64-bit integer into register iDest +*/ +SQLITE_PRIVATE int sqlite3VdbeAddInt64(Vdbe *p, int iDest, i64 iVal){ + return sqlite3VdbeAddOp3(p, OP_Int64, LOWER32(iVal), iDest, UPPER32(iVal)); +} + +/* Generate an opcode that loads a 64-floating point value into register iDest. +*/ +SQLITE_PRIVATE int sqlite3VdbeAddDouble(Vdbe *p, int iDest, double rVal){ + i64 iVal; + memcpy(&iVal,&rVal,8); + return sqlite3VdbeAddOp3(p, OP_Real, LOWER32(iVal), iDest, UPPER32(iVal)); +} + /* Generate code for an unconditional jump to instruction iDest */ SQLITE_PRIVATE int sqlite3VdbeGoto(Vdbe *p, int iDest){ @@ -88512,24 +88120,6 @@ SQLITE_PRIVATE int sqlite3VdbeAddFunctionCall( return addr; } -/* -** Add an opcode that includes the p4 value with a P4_INT64 or -** P4_REAL type. -*/ -SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8( - Vdbe *p, /* Add the opcode to this VM */ - int op, /* The new opcode */ - int p1, /* The P1 operand */ - int p2, /* The P2 operand */ - int p3, /* The P3 operand */ - const u8 *zP4, /* The P4 operand */ - int p4type /* P4 operand type */ -){ - char *p4copy = sqlite3DbMallocRawNN(sqlite3VdbeDb(p), 8); - if( p4copy ) memcpy(p4copy, zP4, 8); - return sqlite3VdbeAddOp4(p, op, p1, p2, p3, p4copy, p4type); -} - #ifndef SQLITE_OMIT_EXPLAIN /* ** Return the address of the current EXPLAIN QUERY PLAN baseline. @@ -88601,11 +88191,21 @@ SQLITE_PRIVATE void sqlite3VdbeExplainPop(Parse *pParse){ ** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees ** as having been used. ** -** The zWhere string must have been obtained from sqlite3_malloc(). +** zWhere is a WHERE clause that defines which entries of the schema +** to reparse. If zWhere==0, that means all entries. p5 is a mask +** of INITFLAG_* values for the parse. +** +** In the current usage, the following are always true: +** +** ALTER TABLE: zWhere==0, p5!=0 +** Otherwise: zWhere!=0, p5==0 +** +** The zWhere string must have been obtained from sqlite3DbMalloc(). ** This routine will take ownership of the allocated memory. */ SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere, u16 p5){ int j; + assert( p5==0 || zWhere==0 ); sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC); sqlite3VdbeChangeP5(p, p5); for(j=0; jdb->nDb; j++) sqlite3VdbeUsesBtree(p, j); @@ -88662,7 +88262,7 @@ SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Parse *pParse){ ** a prior call to sqlite3VdbeMakeLabel(). */ static SQLITE_NOINLINE void resizeResolveLabel(Parse *p, Vdbe *v, int j){ - int nNewSize = 10 - p->nLabel; + int nNewSize = 25 - p->nLabel; p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel, nNewSize*sizeof(p->aLabel[0])); if( p->aLabel==0 ){ @@ -88833,6 +88433,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ || opcode==OP_Function || opcode==OP_PureFunc || ((opcode==OP_Halt || opcode==OP_HaltIfNull) && ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort)) + || (opcode==OP_MustBeInt && pOp->p2==0) ){ hasAbort = 1; break; @@ -89426,8 +89027,6 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){ freeP4FuncCtx(db, (sqlite3_context*)p4); break; } - case P4_REAL: - case P4_INT64: case P4_DYNAMIC: case P4_INTARRAY: { if( p4 ) sqlite3DbNNFreeNN(db, p4); @@ -89781,6 +89380,9 @@ static int translateP(char c, const Op *pOp){ ** "PX@PY" -> "r[X..X+Y-1]" or "r[x]" if y is 0 or 1 ** "PX@PY+1" -> "r[X..X+Y]" or "r[x]" if y is 0 ** "PY..PY" -> "r[X..Y]" or "r[x]" if y<=x +** "PINT13" -> int(P1|P3<<32) +** "PDBL13" -> real(P1|P3<<32) +** "PHEX23" -> hex(P2|P3<<32) */ SQLITE_PRIVATE char *sqlite3VdbeDisplayComment( sqlite3 *db, /* Optional - Oom error reporting only */ @@ -89816,6 +89418,20 @@ SQLITE_PRIVATE char *sqlite3VdbeDisplayComment( seenCom = 1; break; } + }else if( strncmp(&zSynopsis[ii],"INT13",5)==0 ){ + sqlite3_str_appendf(&x,"%lld",INT32_TO_64(pOp->p1,pOp->p3)); + ii += 4; +#ifdef SQLITE_ENABLE_COLUMN_USED_MASK + }else if( strncmp(&zSynopsis[ii],"HEX23",5)==0 ){ + sqlite3_str_appendf(&x,"0x%llx",INT32_TO_64(pOp->p2,pOp->p3)); + ii += 4; +#endif + }else if( strncmp(&zSynopsis[ii],"DBL13",5)==0 ){ + i64 iVal = INT32_TO_64(pOp->p1,pOp->p3); + double r; + memcpy(&r, &iVal, 8); + sqlite3_str_appendf(&x,"%.17g",r); + ii += 4; }else{ int v1 = translateP(c, pOp); int v2; @@ -89945,7 +89561,6 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){ #if VDBE_DISPLAY_P4 /* ** Compute a string that describes the P4 parameter for an opcode. -** Use zTemp for any required temporary buffer space. */ SQLITE_PRIVATE char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){ char *zP4 = 0; @@ -89994,18 +89609,10 @@ SQLITE_PRIVATE char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){ sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg); break; } - case P4_INT64: { - sqlite3_str_appendf(&x, "%lld", *pOp->p4.pI64); - break; - } case P4_INT32: { sqlite3_str_appendf(&x, "%d", pOp->p4.i); break; } - case P4_REAL: { - sqlite3_str_appendf(&x, "%.16g", *pOp->p4.pReal); - break; - } case P4_MEM: { Mem *pMem = pOp->p4.pMem; if( pMem->flags & MEM_Str ){ @@ -90731,7 +90338,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady( n = ROUND8P(sizeof(Op)*p->nOp); /* Bytes of opcode memory used */ x.pSpace = &((u8*)p->aOp)[n]; /* Unused opcode memory */ assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) ); - x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n); /* Bytes of unused memory */ + x.nFree = ROUNDDOWN8((p->nOpAlloc-p->nOp)*sizeof(Op)); /* Bytes unused mem */ assert( x.nFree>=0 ); assert( EIGHT_BYTE_ALIGNMENT(&x.pSpace[x.nFree]) ); @@ -92094,67 +91701,16 @@ SQLITE_PRIVATE u64 sqlite3FloatSwap(u64 in){ } #endif /* SQLITE_MIXED_ENDIAN_64BIT_FLOAT */ - -/* Input "x" is a sequence of unsigned characters that represent a -** big-endian integer. Return the equivalent native integer -*/ -#define ONE_BYTE_INT(x) ((i8)(x)[0]) -#define TWO_BYTE_INT(x) (256*(i8)((x)[0])|(x)[1]) -#define THREE_BYTE_INT(x) (65536*(i8)((x)[0])|((x)[1]<<8)|(x)[2]) -#define FOUR_BYTE_UINT(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) -#define FOUR_BYTE_INT(x) (16777216*(i8)((x)[0])|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) - /* -** Deserialize the data blob pointed to by buf as serial type serial_type -** and store the result in pMem. -** -** This function is implemented as two separate routines for performance. -** The few cases that require local variables are broken out into a separate -** routine so that in most cases the overhead of moving the stack pointer -** is avoided. +** Deserialize the REAL number pointed to by buf and store it in pMem. */ -static void serialGet( +static int sqlite3VdbeSerialGet7( const unsigned char *buf, /* Buffer to deserialize from */ - u32 serial_type, /* Serial type to deserialize */ 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; - if( serial_type==6 ){ - /* EVIDENCE-OF: R-29851-52272 Value is a big-endian 64-bit - ** twos-complement integer. */ - pMem->u.i = *(i64*)&x; - pMem->flags = MEM_Int; - testcase( pMem->u.i<0 ); - }else{ - /* EVIDENCE-OF: R-57343-49114 Value is a big-endian IEEE 754-2008 64-bit - ** floating point number. */ -#if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT) - /* Verify that integers and floating point values use the same - ** byte order. Or, that if SQLITE_MIXED_ENDIAN_64BIT_FLOAT is - ** defined that 64-bit floating point values really are mixed - ** endian. - */ - static const u64 t1 = ((u64)0x3ff00000)<<32; - static const double r1 = 1.0; - u64 t2 = t1; - swapMixedEndianFloat(t2); - assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 ); -#endif - assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 ); - swapMixedEndianFloat(x); - memcpy(&pMem->u.r, &x, sizeof(x)); - 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; + /* EVIDENCE-OF: R-57343-49114 Value is a big-endian IEEE 754-2008 64-bit + ** floating point number. */ + u64 x = sqlite3Get8byte(buf); assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 ); swapMixedEndianFloat(x); memcpy(&pMem->u.r, &x, sizeof(x)); @@ -92165,6 +91721,13 @@ static int serialGet7( pMem->flags = MEM_Real; return 0; } + +/* +** Deserialize the data blob pointed to by buf as serial type serial_type +** and store the result in pMem. +** +** Similar code is found in the implementation of the OP_Column opcode. +*/ SQLITE_PRIVATE void sqlite3VdbeSerialGet( const unsigned char *buf, /* Buffer to deserialize from */ u32 serial_type, /* Serial type to deserialize */ @@ -92223,16 +91786,21 @@ SQLITE_PRIVATE void sqlite3VdbeSerialGet( case 5: { /* 6-byte signed integer */ /* EVIDENCE-OF: R-50385-09674 Value is a big-endian 48-bit ** twos-complement integer. */ - pMem->u.i = FOUR_BYTE_UINT(buf+2) + (((i64)1)<<32)*TWO_BYTE_INT(buf); + pMem->u.i = SIX_BYTE_INT(buf); + pMem->flags = MEM_Int; + testcase( pMem->u.i<0 ); + return; + } + case 6: { /* 8-byte signed integer */ + /* EVIDENCE-OF: R-29851-52272 Value is a big-endian 64-bit + ** twos-complement integer. */ + pMem->u.i = (i64)sqlite3Get8byte(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); return; } - case 6: /* 8-byte signed integer */ case 7: { /* IEEE floating point */ - /* These use local variables, so do them in a separate routine - ** to avoid having to move the frame pointer in the common case */ - serialGet(buf,serial_type,pMem); + sqlite3VdbeSerialGet7(buf, pMem); return; } case 8: /* Integer 0 */ @@ -92838,7 +92406,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( }else if( serial_type==0 ){ rc = -1; }else if( serial_type==7 ){ - serialGet7(&aKey1[d1], &mem1); + sqlite3VdbeSerialGet7(&aKey1[d1], &mem1); rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r); }else{ i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]); @@ -92864,7 +92432,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( rc = -1; }else{ if( serial_type==7 ){ - if( serialGet7(&aKey1[d1], &mem1) ){ + if( sqlite3VdbeSerialGet7(&aKey1[d1], &mem1) ){ rc = -1; /* mem1 is a NaN */ }else if( mem1.u.ru.r ){ rc = -1; @@ -92946,7 +92514,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( serial_type = aKey1[idx1]; if( serial_type==0 || serial_type==10 - || (serial_type==7 && serialGet7(&aKey1[d1], &mem1)!=0) + || (serial_type==7 && sqlite3VdbeSerialGet7(&aKey1[d1], &mem1)!=0) ){ assert( rc==0 ); }else{ @@ -93020,65 +92588,42 @@ static int vdbeRecordCompareInt( const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F]; int serial_type = ((const u8*)pKey1)[1]; int res; - u32 y; - u64 x; i64 v; i64 lhs; vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo); assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB ); - switch( serial_type ){ - case 1: { /* 1-byte signed integer */ - lhs = ONE_BYTE_INT(aKey); - testcase( lhs<0 ); - break; - } - case 2: { /* 2-byte signed integer */ - lhs = TWO_BYTE_INT(aKey); - testcase( lhs<0 ); - break; - } - case 3: { /* 3-byte signed integer */ - lhs = THREE_BYTE_INT(aKey); - testcase( lhs<0 ); - break; - } - case 4: { /* 4-byte signed integer */ - y = FOUR_BYTE_UINT(aKey); - lhs = (i64)*(int*)&y; - testcase( lhs<0 ); - break; - } - case 5: { /* 6-byte signed integer */ - lhs = FOUR_BYTE_UINT(aKey+2) + (((i64)1)<<32)*TWO_BYTE_INT(aKey); - testcase( lhs<0 ); - break; - } - case 6: { /* 8-byte signed integer */ - x = FOUR_BYTE_UINT(aKey); - x = (x<<32) | FOUR_BYTE_UINT(aKey+4); - lhs = *(i64*)&x; - testcase( lhs<0 ); - break; - } - case 8: - lhs = 0; - break; - case 9: - lhs = 1; - break; - - /* This case could be removed without changing the results of running - ** this code. Including it causes gcc to generate a faster switch - ** statement (since the range of switch targets now starts at zero and - ** is contiguous) but does not cause any duplicate code to be generated - ** (as gcc is clever enough to combine the two like cases). Other - ** compilers might be similar. */ - case 0: case 7: - return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2); - default: - return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2); + /* Serial types 1 through 6 are big-endian integers of 1, 2, 3, 4, + ** 6, or 8 bytes. Rather than handle each width in its own switch + ** case, read 8 bytes and use an arithmetic right shift to drop the + ** unwanted low-order bytes and sign-extend the value. This helps + ** because the switch tends to mispredict when a key column contains + ** integers of varying sizes. The first entry of aShift[] is a + ** placeholder so that the table can be indexed by serial_type + ** directly. Reading 8 bytes is always safe, because a buffer passed + ** to this routine has at least 74 bytes of padding after it, as + ** explained in sqlite3VdbeFindCompare() below. + */ + if( (u32)(serial_type-1)<=5 ){ + static const u8 aShift[] = { 0, 56, 48, 40, 32, 16, 0 }; + lhs = ((i64)sqlite3Get8byte(aKey)) >> aShift[serial_type]; + /* ^^--- This shift operator + ** needs to be an arithmetic right-shift, which means that + ** if the left-hand operand (LHS) is negative, it will be sign-extended + ** so that the final results is also negative. All modern C + ** compilers work this way as long as the LHS is a signed integer + ** (which is why the unsigned result from sqlite3Get8byte() is cast + ** into i64), but it is not defined by the C standards, or so Claude + ** tells me. That the correct result is obtained is verified by the + ** following assert() and testcase() macros: + */ + assert( 0<=(i64)sqlite3Get8byte(aKey) || lhs<0 ); + testcase( lhs<0 ); + }else if( serial_type==8 || serial_type==9 ){ + lhs = serial_type - 8; + }else{ + return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2); } assert( pPKey2->u.i == pPKey2->aMem[0].u.i ); @@ -93213,7 +92758,7 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){ testcase( flags & MEM_Null ); testcase( flags & MEM_Blob ); if( (flags & (MEM_Real|MEM_IntReal|MEM_Null|MEM_Blob))==0 - && p->pKeyInfo->aColl[0]==0 + && sqlite3IsBinary(p->pKeyInfo->aColl[0]) ){ assert( flags & MEM_Str ); p->u.z = p->aMem[0].z; @@ -93429,17 +92974,28 @@ SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff /* ** Configure SQL variable iVar so that binding a new value to it signals ** to sqlite3_reoptimize() that re-preparing the statement may result -** in a better query plan. +** in a better query plan. If parameter bSmallint is true, then the +** statement is only re-prepared if the new value is integer value 0 or 1. +** +** The v->expmask bit is always set. expmask means that a reprepare is +** possible. The v->smimask bit is only set if we want to restrict +** reprepare when the value changes from (0,1) to something else, or from +** something else to (0,1). */ -SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){ +SQLITE_PRIVATE void sqlite3VdbeReprepareOnBind(Vdbe *v, int iVar, int bSmallint){ + u32 m; assert( iVar>0 ); assert( (v->db->flags & SQLITE_EnableQPSG)==0 || (v->db->mDbFlags & DBFLAG_InternalFunc)!=0 ); - if( iVar>=32 ){ - v->expmask |= 0x80000000; - }else{ - v->expmask |= ((u32)1 << (iVar-1)); + + m = (iVar>=32) ? 0x80000000 : ((u32)1 << (iVar-1)); + v->expmask |= m; + if( bSmallint ){ + v->smimask |= m; } + + /* smimask is always a subset of expmask */ + assert( (v->smimask & v->expmask) == v->smimask ); } /* @@ -93495,12 +93051,12 @@ static int vdbeIsMatchingIndexKey( ){ u8 *aRec = 0; u32 nRec = 0; - Mem mem; + Mem m; int rc = SQLITE_OK; - memset(&mem, 0, sizeof(mem)); - mem.enc = p->pKeyInfo->enc; - mem.db = p->pKeyInfo->db; + memset(&m, 0, sizeof(m)); + m.enc = p->pKeyInfo->enc; + m.db = p->pKeyInfo->db; nRec = sqlite3BtreePayloadSize(pCur); if( nRec>0x7fffffff ){ return SQLITE_CORRUPT_BKPT; @@ -93542,9 +93098,9 @@ static int vdbeIsMatchingIndexKey( if( (idxRec+nSerial)>nRec ){ rc = SQLITE_CORRUPT_BKPT; }else{ - sqlite3VdbeSerialGet(&aRec[idxRec], iSerial, &mem); - if( vdbeSkipField(mask, ii, &p->aMem[ii], &mem, bInt)==0 ){ - res = sqlite3MemCompare(&mem, &p->aMem[ii], p->pKeyInfo->aColl[ii]); + sqlite3VdbeSerialGet(&aRec[idxRec], iSerial, &m); + if( vdbeSkipField(mask, ii, &p->aMem[ii], &m, bInt)==0 ){ + res = sqlite3MemCompare(&m, &p->aMem[ii], p->pKeyInfo->aColl[ii]); if( res!=0 ) break; } } @@ -94233,15 +93789,18 @@ SQLITE_API void sqlite3_value_free(sqlite3_value *pOld){ /**************************** sqlite3_result_ ******************************* -** The following routines are used by user-defined functions to specify -** the function result. +** The following routines are used by application-defined SQL functions to +** specify the function return value. There are many variations on +** sqlite3_result_xxxx() for different types of return values. ** -** The setStrOrError() function calls sqlite3VdbeMemSetStr() to store the -** result as a string or blob. Appropriate errors are set if the string/blob -** is too big or if an OOM occurs. +** The setStrOrError() function is a helper function that invokes +** sqlite3VdbeMemSetStr() to store the result as a string or blob. +** Appropriate errors are set if the string/blob 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. +** The invokeValueDestructor(P,X) helper function invokes the destructor +** function X() on value P if P is not going to be used and need to +** be destroyed. */ static void setResultStrOrError( sqlite3_context *pCtx, /* Function context */ @@ -94554,7 +94113,7 @@ SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){ } } -/* Force an SQLITE_TOOBIG error. */ +/* Cause the SQL function to raise an SQLITE_TOOBIG error. */ SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){ #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ) return; @@ -94565,7 +94124,7 @@ SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){ SQLITE_UTF8, SQLITE_STATIC); } -/* An SQLITE_NOMEM error. */ +/* Cause the SQL function to raise an SQLITE_NOMEM error. */ SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){ #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ) return; @@ -94576,6 +94135,64 @@ SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){ sqlite3OomFault(pCtx->pOut->db); } +/* Make the return value of the SQL function or virtual table pCtx +** be the content of the sqlite3_str object pStr. The eOwn flag +** determines ownership of the sqlite3_str object and its content. +** +** eOwn Ownership transfer +** ------------- ------------------------------------------------ +** +** SQLITE_COPY The SQL function returns a copy the sqlite3_str +** content and leaves the sqlite3_str object itself +** unchanged. +** +** SQLITE_XFER The content of the sqlite3_str is transferred to +** the SQL function and the SQL function takes +** responsibility for freeing that content when it is +** no longer needed. The sqlite3_str object is reset +** to an empty string. +** +** SQLITE_FINISH Like SQLITE_XFER except that the pStr is also +** freed using sqlite3_str_free(). +*/ +SQLITE_API void sqlite3_result_str(sqlite3_context *pCtx, sqlite3_str *pStr, int eOwn){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCtx==0 ) return; + if( pStr==0 ) return; +#endif + testcase( pStr==(sqlite3_str*)&sqlite3OomStr ); + if( pStr->accError==0 ){ + if( pStr->nChar==0 ){ + setResultStrOrError(pCtx, "", 0, SQLITE_UTF8_ZT, SQLITE_STATIC); + sqlite3_str_reset(pStr); + }else{ + const char *zText = sqlite3_str_value(pStr); + /* Only internal code has the ability to capture a pointer to + ** an sqlite3_str object that uses static buffer. And none of + ** those internal use cases every invoke the sqlite3_result_str() + ** interface on a static-buffer sqlite3_str. Should this change + ** in the future, the following assert() will let us know. */ + assert( isMalloced(pStr) ); + if( eOwn==SQLITE_COPY ){ + setResultStrOrError(pCtx, zText, pStr->nChar, + SQLITE_UTF8, SQLITE_TRANSIENT); + }else{ + setResultStrOrError(pCtx, zText, pStr->nChar, + SQLITE_UTF8_ZT, SQLITE_DYNAMIC); + sqlite3StrAccumInit(pStr, pStr->db, 0, 0, pStr->mxAlloc); + } + } + }else if( pStr->accError==SQLITE_NOMEM ){ + sqlite3_result_error_nomem(pCtx); + }else{ + assert( pStr->accError==SQLITE_TOOBIG ); + sqlite3_result_error_toobig(pCtx); + } + if( eOwn==SQLITE_FINISH ){ + sqlite3_str_free(pStr); + } +} + #ifndef SQLITE_UNTESTABLE /* Force the INT64 value currently stored as the result to be ** a MEM_IntReal value. See the SQLITE_TESTCTRL_RESULT_INTREAL @@ -95543,7 +95160,11 @@ static int vdbeUnbind(Vdbe *p, unsigned int i){ ** following any change to the bindings of that parameter. */ assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 ); + assert( (p->expmask & p->smimask)==p->smimask ); if( p->expmask!=0 && (p->expmask & (i>=31 ? 0x80000000 : (u32)1<smimask is set and the old + ** value is an integer other than (0,1). But that is such a corner + ** case that it does not seem worth the extra code to implement. */ p->expired = 1; } return SQLITE_OK; @@ -95642,15 +95263,46 @@ SQLITE_API int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){ return sqlite3_bind_int64(p, i, (i64)iValue); } SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){ - int rc; - Vdbe *p = (Vdbe *)pStmt; - rc = vdbeUnbind(p, (u32)(i-1)); - if( rc==SQLITE_OK ){ - assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */ - sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue); + Mem *pVar; + Vdbe *p = (Vdbe*)pStmt; + if( vdbeSafetyNotNull(p) ){ + return SQLITE_MISUSE_BKPT; + } + sqlite3_mutex_enter(p->db->mutex); + if( p->eVdbeState!=VDBE_READY_STATE ){ + sqlite3Error(p->db, SQLITE_MISUSE_BKPT); sqlite3_mutex_leave(p->db->mutex); + sqlite3_log(SQLITE_MISUSE, + "bind on a busy prepared statement: [%s]", p->zSql); + return SQLITE_MISUSE_BKPT; } - return rc; + if( i<=0 || (--i)>=p->nVar ){ + sqlite3Error(p->db, SQLITE_RANGE); + sqlite3_mutex_leave(p->db->mutex); + return SQLITE_RANGE; + } + pVar = &p->aVar[i]; + if( p->expmask!=0 ){ + u32 expireMask = i>=32 ? 0x80000000 : (u32)1 << i; + assert( (p->expmask & p->smimask)==p->smimask ); + if( (p->expmask & expireMask)!=0 ){ + if( (p->smimask & expireMask)!=0 ){ + /* If the smimask bit is set, only expire the prepared statement + ** if the value is changing to or from (0,1) and something else */ + int sm1 = (pVar->flags & MEM_Int)!=0 && pVar->u.i>=0 && pVar->u.i<=1; + int sm2 = iValue>=0 && iValue<=1; + if( sm1!=sm2 ){ + p->expired = 1; + } + }else if( (pVar->flags & MEM_Int)==0 || pVar->u.i!=iValue ){ + /* Always expire if the value really is changing */ + p->expired = 1; + } + } + } + sqlite3VdbeMemSetInt64(pVar, iValue); + sqlite3_mutex_leave(p->db->mutex); + return SQLITE_OK; } SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){ int rc; @@ -96274,6 +95926,11 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppVa sqlite3VdbeMemSetInt64(pMem, p->iKey2); }else if( iStore>=pUnpack->nField ){ pMem = (sqlite3_value *)columnNullValue(); + }else if( (p->pTab->aCol) + && (p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL) + && (pMem->flags & (MEM_Int|MEM_IntReal)) + ){ + sqlite3VdbeMemRealify(pMem); } }else{ /* For an UPDATE, memory cell (p->iNewReg+1+iStore) contains the required @@ -96748,7 +96405,7 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( } #elif !defined(__STRICT_ANSI__) && defined(__GNUC__) && \ - (defined(i386) || defined(__i386__) || defined(_M_IX86)) + (defined(i586) || defined(__i586__) || defined(_M_IX86)) __inline__ sqlite_uint64 sqlite3Hwtime(void){ unsigned int lo, hi; @@ -97214,10 +96871,12 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){ int eType = sqlite3_value_type(pVal); if( eType==SQLITE_TEXT ){ Mem *pMem = (Mem*)pVal; - assert( pMem->db!=0 ); - sqlite3_mutex_enter(pMem->db->mutex); +#if SQLITE_THREADSAFE>0 + sqlite3_mutex *pMutex = pMem->db ? pMem->db->mutex : 0; +#endif + sqlite3_mutex_enter(pMutex); applyNumericAffinity(pMem, 0); - sqlite3_mutex_leave(pMem->db->mutex); + sqlite3_mutex_leave(pMutex); eType = sqlite3_value_type(pVal); } return eType; @@ -97463,6 +97122,10 @@ static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){ /* ** Compute a bloom filter hash using pOp->p4.i registers from aMem[] beginning ** with pOp->p3. Return the hash. +** +** IMPORTANT RESTRICTION (tag-202607231411): This hash is only valid if the +** collating sequence for TEXT is BINARY. Hence, Bloom filters that use this +** hash will not work for look-ups that use any other collating sequence. */ static u64 filterHash(const Mem *aMem, const Op *pOp){ int i, mx; @@ -97475,17 +97138,33 @@ static u64 filterHash(const Mem *aMem, const Op *pOp){ h += p->u.i; }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)); + }else if( p->flags & MEM_Str ){ + u64 x; + h += p->n; + if( p->n >= (int)sizeof(x) ){ + memcpy(&x, p->z, sizeof(x)); + h += x; + memcpy(&x, p->z + p->n - sizeof(x), sizeof(x)); + h += x; + }else{ + x = 0; + memcpy(&x, p->z, p->n); + h += x; + } + }else if( p->flags & MEM_Blob ){ + int n = p->n; + u64 x = 0; + if( n ){ + memcpy(&x, p->z, MIN(n, (int)sizeof(x))); + h += x; + } + h += 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 @@ -97557,6 +97236,7 @@ static SQLITE_NOINLINE int vdbeColumnFromOverflow( }else{ rc = sqlite3VdbeMemSetStr(pDest, pBuf, len, 0, sqlite3RCStrUnref); + pDest->enc = encoding; } }else{ rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, iOffset, len, pDest); @@ -97571,6 +97251,40 @@ static SQLITE_NOINLINE int vdbeColumnFromOverflow( return rc; } +/* +** Memory cell pMem may contain a blob or a NULL value. Cursor pCsr is +** open on an index. If the current index entry matches the blob value in +** pMem byte-for-byte, set pMem to NULL and return 1. Otherwise, return 0. +** +** If an error occurs, set (*pRc) to an SQLite error code. Return 1 in this +** case as well. +*/ +static SQLITE_NOINLINE int vdbeIndexKeyCompare( + BtCursor *pCsr, /* Cursor to compare key to */ + Mem *pMem, + int *pRc +){ + int ret = 0; + u32 nKey = 0; + + assert( pMem->flags & (MEM_Blob|MEM_Null) ); + nKey = sqlite3BtreePayloadSize(pCsr); + if( nKey==(u32)pMem->n && ALWAYS((pMem->flags & MEM_Blob)!=0) ){ + /* This code could just use sqlite3BtreePayloadFetch(). But calling that + ** function here apparently prevents compilers from inlining it in other, + ** more performance critical, places. So this code uses + ** MemFromBtreeZeroOffset(), which is just as fast in most cases, but also + ** handles the case where the index record uses overflow pages. */ + Mem m; + memset(&m, 0, sizeof(m)); + *pRc = sqlite3VdbeMemFromBtreeZeroOffset(pCsr, nKey, &m); + ret = (*pRc!=SQLITE_OK || 0==memcmp(pMem->z, m.z, nKey)); + sqlite3VdbeMemReleaseMalloc(&m); + } + + return ret; +} + /* ** Send a "statement aborts" message to the error log. */ @@ -98151,31 +97865,35 @@ case OP_Integer: { /* out2 */ break; } -/* Opcode: Int64 * P2 * P4 * -** Synopsis: r[P2]=P4 +/* Opcode: Int64 P1 P2 P3 * * +** Synopsis: r[P2]=PINT13 ** -** P4 is a pointer to a 64-bit integer value. -** Write that value into register P2. +** Combine P1 and P3 into a signed 64-bit integer. P1 is the least +** significant 32 bits and P3 is the most significant. Store the +** result in register P2. */ case OP_Int64: { /* out2 */ pOut = out2Prerelease(p, pOp); - assert( pOp->p4.pI64!=0 ); - pOut->u.i = *pOp->p4.pI64; + pOut->u.i = INT32_TO_64(pOp->p1,pOp->p3); break; } #ifndef SQLITE_OMIT_FLOATING_POINT -/* Opcode: Real * P2 * P4 * -** Synopsis: r[P2]=P4 +/* Opcode: Real P1 P2 P3 * * +** Synopsis: r[P2]=PDBL13 ** -** P4 is a pointer to a 64-bit floating point value. -** Write that value into register P2. +** P1 and P3 are combined to 64 bits with P1 being the lower the P3 +** the upper. The result is interpreted as a 64-bit floating-point +** and stored in register P2. */ case OP_Real: { /* same as TK_FLOAT, out2 */ + u64 ii; pOut = out2Prerelease(p, pOp); pOut->flags = MEM_Real; - assert( !sqlite3IsNaN(*pOp->p4.pReal) ); - pOut->u.r = *pOp->p4.pReal; + ii = (u64)INT32_TO_64(pOp->p1,pOp->p3); + swapMixedEndianFloat(ii); + memcpy(&pOut->u.r, &ii, 8); + assert( !sqlite3IsNaN(pOut->u.r) ); break; } #endif @@ -99968,30 +99686,91 @@ case OP_Column: { /* ncycle */ assert( t==pC->aType[p2] ); if( pC->szRow>=aOffset[p2+1] ){ /* This is the common case where the desired content fits on the original - ** page - where the content is not on an overflow page */ + ** page - where the content is not on an overflow page. + ** + ** The big switch() is an in-line variant of sqlite3VdbeSerialGet() that + ** has been optimized for the OP_Column opcode. + */ zData = pC->aRow + aOffset[p2]; - if( t<12 ){ - sqlite3VdbeSerialGet(zData, t, pDest); - }else{ - /* If the column value is a string, we need a persistent value, not - ** a MEM_Ephem value. This branch is a fast short-cut that is equivalent - ** to calling sqlite3VdbeSerialGet() and sqlite3VdbeDeephemeralize(). - */ - static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term }; - pDest->n = len = (t-12)/2; - pDest->enc = encoding; - if( pDest->szMalloc < len+2 ){ - if( len>db->aLimit[SQLITE_LIMIT_LENGTH] ) goto too_big; + switch( t ){ + case 0: + case 11: pDest->flags = MEM_Null; - if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem; - }else{ - pDest->z = pDest->zMalloc; + break; + case 1: + pDest->u.i = ONE_BYTE_INT(zData); + pDest->flags = MEM_Int; + testcase( pDest->u.i<0 ); + break; + case 2: + pDest->u.i = TWO_BYTE_INT(zData); + pDest->flags = MEM_Int; + testcase( pDest->u.i<0 ); + break; + case 3: + pDest->u.i = THREE_BYTE_INT(zData); + pDest->flags = MEM_Int; + testcase( pDest->u.i<0 ); + break; + case 4: + pDest->u.i = FOUR_BYTE_INT(zData); + pDest->flags = MEM_Int; + testcase( pDest->u.i<0 ); + break; + case 5: + pDest->u.i = SIX_BYTE_INT(zData); + pDest->flags = MEM_Int; + testcase( pDest->u.i<0 ); + break; + case 6: { + pDest->u.i = (i64)sqlite3Get8byte(zData); + pDest->flags = MEM_Int; + testcase( pDest->u.i<0 ); + break; } - memcpy(pDest->z, zData, len); - pDest->z[len] = 0; - pDest->z[len+1] = 0; - pDest->flags = aFlag[t&1]; - } + case 7: { + u64 x = sqlite3Get8byte(zData); + swapMixedEndianFloat(x); + pDest->flags = IsNaN(x) ? MEM_Null : MEM_Real; + memcpy(&pDest->u.r, &x, sizeof(x)); + testcase( pDest->u.r<0 ); + break; + } + case 8: + case 9: { + pDest->u.i = t-8; + pDest->flags = MEM_Int; + break; + } + case 10: + /* Internal use only: NULL with virtual table + ** UPDATE no-change flag set */ + pDest->flags = MEM_Null|MEM_Zero; + pDest->u.nZero = 0; + pDest->n = 0; + break; + default: { + /* If the column value is a string or blob, we need a persistent + ** value, not a MEM_Ephem value. This case is a fast short-cut + ** that is equivalent to calling sqlite3VdbeSerialGet() and + ** sqlite3VdbeDeephemeralize(). + */ + static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term }; + pDest->n = len = (t-12)/2; + pDest->enc = encoding; + if( pDest->szMalloc < len+2 ){ + if( len>db->aLimit[SQLITE_LIMIT_LENGTH] ) goto too_big; + pDest->flags = MEM_Null; + if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem; + }else{ + pDest->z = pDest->zMalloc; + } + memcpy(pDest->z, zData, len); + pDest->z[len] = 0; + pDest->z[len+1] = 0; + pDest->flags = aFlag[t&1]; + } + } /* End of switch */ }else{ u8 p5; pDest->enc = encoding; @@ -100191,22 +99970,9 @@ case OP_Affinity: { assert( zAffinity[0]==SQLITE_AFF_NONE || memIsValid(pIn1) ); applyAffinity(pIn1, zAffinity[0], encoding); if( zAffinity[0]==SQLITE_AFF_REAL && (pIn1->flags & MEM_Int)!=0 ){ - /* 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 - ** so that we keep the high-resolution integer value but know that - ** the type really wants to be REAL. */ - testcase( pIn1->u.i==140737488355328LL ); - testcase( pIn1->u.i==140737488355327LL ); - testcase( pIn1->u.i==-140737488355328LL ); - testcase( pIn1->u.i==-140737488355329LL ); - if( pIn1->u.i<=140737488355327LL && pIn1->u.i>=-140737488355328LL ){ - pIn1->flags |= MEM_IntReal; - pIn1->flags &= ~MEM_Int; - }else{ - pIn1->u.r = (double)pIn1->u.i; - pIn1->flags |= MEM_Real; - pIn1->flags &= ~(MEM_Int|MEM_Str); - } + pIn1->u.r = (double)pIn1->u.i; + pIn1->flags |= MEM_Real; + pIn1->flags &= ~(MEM_Int|MEM_Str); } REGISTER_TRACE((int)(pIn1-aMem), pIn1); zAffinity++; @@ -100459,12 +100225,24 @@ case OP_MakeRecord: { } nByte = nHdr+nData; + /* If we are able to put an over-run area of 7 bytes on the end of the + ** memory allocation into which the record is being constructed, then + ** the encoding of integer values can go faster. This is only possible + ** if SQLITE_MAX_LENGTH is no with 7 of INT32_MAX and if the host CPU + ** byte-order is known at compile-time. + */ +#if SQLITE_MAX_LENGTH<=2147483640 && SQLITE_BYTEORDER>0 +# define OVERRUN 7 /* We are able to allocate an overrun of 7 bytes */ +#else +# define OVERRUN 0 /* No overrun will be available */ +#endif + /* Make sure the output register has a buffer large enough to store ** the new record. The output register (pOp->p3) is not allowed to ** be one of the input registers (because the following call to ** sqlite3VdbeMemClearAndResize() could clobber the value before it is used). */ - if( nByte+nZero<=pOut->szMalloc ){ + if( nByte+nZero<=pOut->szMalloc-OVERRUN ){ /* The output register is already large enough to hold the record. ** No error checks or buffer enlargement is required */ pOut->z = pOut->zMalloc; @@ -100474,7 +100252,7 @@ case OP_MakeRecord: { if( nByte+nZero>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } - if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){ + if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte+OVERRUN) ){ goto no_mem; } } @@ -100517,6 +100295,27 @@ case OP_MakeRecord: { } len = sqlite3SmallTypeSizes[serial_type]; assert( len>=1 && len<=8 && len!=5 && len!=7 ); +#if SQLITE_BYTEORDER==1234 + v = sqlite3BSwap64(v); + if( OVERRUN ){ + static const u8 aShift[] = { 0, 56, 48, 40, 32, 16, 0, 0 }; + v >>= aShift[serial_type]; + memcpy(zPayload, &v, 8); + }else{ + /* Test this limb by compiling with -DSQLITE_MAX_LENGTH=2147483647 */ + memcpy(zPayload, (u8*)&v + 8 - len, len); + } +#elif SQLITE_BYTEORDER==4321 + if( OVERRUN ){ + static const u8 aShift[] = { 0, 56, 48, 40, 32, 16, 0, 0 }; + v <<= aShift[serial_type]; + memcpy(zPayload, &v, 8); + }else{ + /* Test this limb by compiling with -DSQLITE_MAX_LENGTH=2147483647 */ + memcpy(zPayload, (u8*)&v + 8 - len, len); + } +#else + /* Test this limb by compiling with -DSQLITE_BYTEORDER=0 */ switch( len ){ default: zPayload[7] = (u8)(v&0xff); v >>= 8; zPayload[6] = (u8)(v&0xff); v >>= 8; @@ -100532,6 +100331,8 @@ case OP_MakeRecord: { /* no break */ deliberate_fall_through case 1: zPayload[0] = (u8)(v&0xff); } +#endif +#undef OVERRUN /* We are done with the OVERRUN macro now */ zPayload += len; } }else if( serial_type<0x80 ){ @@ -101489,21 +101290,21 @@ case OP_Close: { /* ncycle */ } #ifdef SQLITE_ENABLE_COLUMN_USED_MASK -/* Opcode: ColumnsUsed P1 * * P4 * +/* Opcode: ColumnsUsed P1 P2 P3 * * +** Synopsis: Cursor P1 uses columns PHEX23 ** ** This opcode (which only exists if SQLite was compiled with ** SQLITE_ENABLE_COLUMN_USED_MASK) identifies which columns of the -** table or index for cursor P1 are used. P4 is a 64-bit integer -** (P4_INT64) in which the first 63 bits are one for each of the -** first 63 columns of the table or index that are actually used -** by the cursor. The high-order bit is set if any column after -** the 64th is used. +** table or index for cursor P1 are used. P2 and P3 combine to give +** a 64-bit unsigned integer mask. P2 stores the lower 32 bits and +** P3 stores the upper 32 bits. If the high-order bit of P3 is set +** that means that and 64-th or some later column is used. */ case OP_ColumnsUsed: { VdbeCursor *pC; pC = p->apCsr[pOp->p1]; assert( pC->eCurType==CURTYPE_BTREE ); - pC->maskUsed = *(u64*)pOp->p4.pI64; + pC->maskUsed = INT32_TO_64(pOp->p2,pOp->p3); break; } #endif @@ -102014,24 +101815,6 @@ case OP_SeekHit: { /* ncycle */ break; } -/* Opcode: IfNotOpen P1 P2 * * * -** Synopsis: if( !csr[P1] ) goto P2 -** -** If cursor P1 is not open or if P1 is set to a NULL row using the -** OP_NullRow opcode, then jump to instruction P2. Otherwise, fall through. -*/ -case OP_IfNotOpen: { /* jump */ - VdbeCursor *pCur; - - assert( pOp->p1>=0 && pOp->p1nCursor ); - pCur = p->apCsr[pOp->p1]; - VdbeBranchTaken(pCur==0 || pCur->nullRow, 2); - if( pCur==0 || pCur->nullRow ){ - goto jump_to_p2_and_check_for_interrupt; - } - break; -} - /* Opcode: Found P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** @@ -102273,7 +102056,7 @@ case OP_SeekRowid: { /* jump0, in3, ncycle */ VdbeCursor *pC; BtCursor *pCrsr; int res; - u64 iKey; + i64 iKey; pIn3 = &aMem[pOp->p3]; testcase( pIn3->flags & MEM_Int ); @@ -102287,9 +102070,21 @@ case OP_SeekRowid: { /* jump0, in3, ncycle */ ** changing the datatype of pIn3, however, as it is used by other ** parts of the prepared statement. */ Mem x = pIn3[0]; - applyAffinity(&x, SQLITE_AFF_NUMERIC, encoding); - if( (x.flags & MEM_Int)==0 ) goto jump_to_p2; - iKey = x.u.i; + if( x.flags & MEM_Str ){ + applyNumericAffinity(&x, 1); + } + if( x.flags & MEM_Int ){ + iKey = x.u.i; + }else + if( (x.flags & MEM_Real)==0 + || x.u.r < -9223372036854775808.0 + || x.u.r > 9223372036854774784.0 + /* ^^^^^^^^^^^^^^^^^^^^^-- same value as every other double + ** between 9223372036854774263.0 and 923372036854775295.0 */ + || (double)(iKey = sqlite3RealToI64(x.u.r))!=x.u.r + ){ + goto jump_to_p2; + } goto notExistsWithKey; } /* Fall through into OP_NotExists */ @@ -102969,14 +102764,17 @@ case OP_Rowid: { /* out2, ncycle */ break; } -/* Opcode: NullRow P1 * * * * +/* Opcode: NullRow P1 P2 * * * ** -** Move the cursor P1 to a null row. Any OP_Column operations +** Move the cursor P1 to a null row if P2 is 0. Any OP_Column operations ** that occur while the cursor is on the null row will always ** write a NULL. ** ** If cursor P1 is not previously opened, open it now to a special ** pseudo-cursor that always returns NULL for every column. +** +** If P2 is not 0, then the nullRow flag on the pseudo-cursor is +** turned off. */ case OP_NullRow: { VdbeCursor *pC; @@ -102993,7 +102791,7 @@ case OP_NullRow: { pC->noReuse = 1; pC->uc.pCursor = sqlite3BtreeFakeValidCursor(); } - pC->nullRow = 1; + pC->nullRow = (pOp->p2==0); pC->cacheStatus = CACHE_STALE; if( pC->eCurType==CURTYPE_BTREE ){ assert( pC->uc.pCursor!=0 ); @@ -103399,15 +103197,20 @@ case OP_SorterInsert: { /* in2 */ break; } -/* Opcode: IdxDelete P1 P2 P3 P4 * -** Synopsis: key=r[P2@P3] +/* Opcode: IdxDelete P1 P2 P3 P4 P5 +** Synopsis: key=r[P2@P5] ** -** The content of P3 registers starting at register P2 form +** The content of P5 registers starting at register P2 form ** an unpacked index key. This opcode removes that entry from the ** index opened by cursor P1. ** ** P4 is a pointer to an Index structure. ** +** If P3 is non-zero, it is the register number of a register holding +** a record that will be inserted into this index. If that record is +** identical to the one that would be deleted by this instruction, +** skip the delete and set register P3 to NULL. +** ** Raise an SQLITE_CORRUPT_INDEX error if no matching index entry is found ** and not in writable_schema mode. */ @@ -103417,8 +103220,8 @@ case OP_IdxDelete: { int res; UnpackedRecord r; - assert( pOp->p3>0 ); - assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem+1 - p->nCursor)+1 ); + assert( pOp->p5>0 ); + assert( pOp->p2>0 && pOp->p2+pOp->p5<=(p->nMem+1 - p->nCursor)+1 ); assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); @@ -103427,7 +103230,7 @@ case OP_IdxDelete: { pCrsr = pC->uc.pCursor; assert( pCrsr!=0 ); r.pKeyInfo = pC->pKeyInfo; - r.nField = (u16)pOp->p3; + r.nField = pOp->p5; r.default_rc = 0; r.aMem = &aMem[pOp->p2]; rc = sqlite3BtreeIndexMoveto(pCrsr, &r, &res); @@ -103446,6 +103249,13 @@ case OP_IdxDelete: { break; } } + + if( pOp->p3 && vdbeIndexKeyCompare(pCrsr, &aMem[pOp->p3], &rc) ){ + if( rc ) goto abort_due_to_error; + sqlite3VdbeMemSetNull(&aMem[pOp->p3]); + break; + } + rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE); if( rc ) goto abort_due_to_error; assert( pC->deferredMoveto==0 ); @@ -103519,6 +103329,11 @@ case OP_IdxRowid: { /* out2, ncycle */ assert( pTabCur->eCurType==CURTYPE_BTREE ); assert( pTabCur->uc.pCursor!=0 ); assert( pTabCur->isTable ); +#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG) + assert( + sqlite3BtreeCursorHintTblCsr(pC->uc.pCursor)==pTabCur->uc.pCursor + ); +#endif pTabCur->nullRow = 0; pTabCur->movetoTarget = rowid; pTabCur->deferredMoveto = 1; @@ -103879,12 +103694,19 @@ case OP_SqlExec: { break; } -/* Opcode: ParseSchema P1 * * P4 * +/* Opcode: ParseSchema P1 * * P4 P5 ** ** Read and parse all entries from the schema table of database P1 ** that match the WHERE clause P4. If P4 is a NULL pointer, then the ** entire schema for P1 is reparsed. ** +** When P4 is NULL, the P5 value is used as the mFlags argument +** to sqlite3InitOne(). In other words, P5 should be a mask composed +** of INITFLAG_* values. +** +** The P4==0 case is only used by ALTER TABLE and P5!=0 for all such +** cases. For uses other than ALTER TABLE, P4<>0 and P5==0. +** ** This opcode invokes the parser to create a new virtual machine, ** then runs the new virtual machine. It is thus a re-entrant opcode. */ @@ -103912,6 +103734,7 @@ case OP_ParseSchema: { #ifndef SQLITE_OMIT_ALTERTABLE if( pOp->p4.z==0 ){ + assert( pOp->p5!=0 ); sqlite3SchemaClear(db->aDb[iDb].pSchema); db->mDbFlags &= ~DBFLAG_SchemaKnownOk; rc = sqlite3InitOne(db, iDb, &p->zErrMsg, pOp->p5); @@ -103920,6 +103743,7 @@ case OP_ParseSchema: { }else #endif { + assert( pOp->p5==0 ); zSchema = LEGACY_SCHEMA_TABLE; initData.db = db; initData.iDb = iDb; @@ -104281,7 +104105,7 @@ case OP_Program: { /* jump0 */ if( p->nFrame>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){ rc = SQLITE_ERROR; - sqlite3VdbeError(p, "too many levels of trigger recursion"); + sqlite3VdbeError(p, "triggers nested too deep"); goto abort_due_to_error; } @@ -105892,23 +105716,37 @@ case OP_Init: { /* jump0 */ } #ifdef SQLITE_ENABLE_CURSOR_HINTS -/* Opcode: CursorHint P1 * * P4 * +/* Opcode: CursorHint P1 * P3 P4 * ** -** Provide a hint to cursor P1 that it only needs to return rows that -** satisfy the Expr in P4. TK_REGISTER terms in the P4 expression refer -** to values currently held in registers. TK_COLUMN terms in the P4 +** Provide a hint to cursor P1. +** +** If P4 is of type P4_EXPR, then the hint is that the cursor need only return +** rows that satisfy the Expr in P4. TK_REGISTER terms in the P4 expression +** refer to values currently held in registers. TK_COLUMN terms in the P4 ** expression refer to columns in the b-tree to which cursor P1 is pointing. +** P3 is ignore in this case. +** +** Or, if P4 is P4_NOTUSED, then the hint is that cursor P1 is an index cursor +** used to drive table cursor P3. In other words, that this VM may execute +** OP_DeferredSeek instructions to lazily position P3 based on current +** position of P1. */ case OP_CursorHint: { VdbeCursor *pC; + pC = p->apCsr[pOp->p1]; assert( pOp->p1>=0 && pOp->p1nCursor ); - assert( pOp->p4type==P4_EXPR ); - pC = p->apCsr[pOp->p1]; + if( pC ){ assert( pC->eCurType==CURTYPE_BTREE ); - sqlite3BtreeCursorHint(pC->uc.pCursor, BTREE_HINT_RANGE, - pOp->p4.pExpr, aMem); + if( pOp->p4type==P4_EXPR ){ + sqlite3BtreeCursorHint(pC->uc.pCursor, BTREE_HINT_RANGE, + pOp->p4.pExpr, aMem); + }else if( p->apCsr[pOp->p3] ){ + sqlite3BtreeCursorHint( + pC->uc.pCursor, BTREE_HINT_TABLECURSOR, p->apCsr[pOp->p3]->uc.pCursor + ); + } } break; } @@ -107040,6 +106878,7 @@ struct VdbeSorter { #define SORTER_TYPE_INTEGER 0x01 #define SORTER_TYPE_TEXT 0x02 +#define SORTER_TYPE_REAL 0x04 /* ** An instance of the following object is used to read records out of a @@ -107613,6 +107452,150 @@ static int vdbeSorterCompareInt( return res; } +/* Helper function for vdbeSorterCompareReal(). +** +** The first elements of both pKey1 and pKey2 have been decoded into double +** values r1 and r2. Do the comparison between those keys and return the +** result. If r1==r2, break the tie with a comparison of subsequent elements +** from each key. +*/ +static int vdbeSorterFinishRealCompare( + SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ + int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ + const void *pKey1, int nKey1, /* Left side of comparison */ + const void *pKey2, int nKey2, /* Right side of comparison */ + double r1, /* REAL value of first element of pKey1 */ + double r2 /* REAL value of first element of pKey2 */ +){ + int res; + if( r1r2 ){ + res = +1; + }else{ + res = 0; + } + assert( pTask->pSorter->pKeyInfo->aSortFlags!=0 ); + if( res==0 ){ + if( pTask->pSorter->pKeyInfo->nKeyField>1 ){ + res = vdbeSorterCompareTail( + pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 + ); + } + }else if( pTask->pSorter->pKeyInfo->aSortFlags[0] ){ + assert( !(pTask->pSorter->pKeyInfo->aSortFlags[0]&KEYINFO_ORDER_BIGNULL) ); + res = res * -1; + } + return res; +} + +/* Helper function for vdbeSorterCompareReal(). +** +** Buffer p[] is a record where the first term is guaranteed to be either +** a floating-point value, or an integer stand-in for a floating point +** value (a MEM_IntReal). Whatever its format, extract the value and +** return it. +*/ +static double vdbeSorterGetReal(const u8 *p){ + double r; /* the return value */ + + assert( p[0]<0x80 ); /* 1-byte headers: nAllField<13 */ + assert( p[1]>0 && p[1]<10 ); /* first fields proven numeric */ + + if( p[1]==7 ){ + u64 x = sqlite3Get8byte(p + p[0]); + swapMixedEndianFloat(x); + assert( !IsNaN(x) ); + memcpy(&r, &x, sizeof(r)); + }else{ + Mem m; + m.u.i = 0; + sqlite3VdbeSerialGet(p + p[0], p[1], &m); + assert( m.flags==MEM_Int ); + r = (double)m.u.i; + } + return r; +} + +/* Helper function for vdbeSorterCompareReal() +** +** This routine handles the case of comparing two floating-point values +** where one or both of the floating-point are represented by integers. +** In other words, where one both is an MEM_RealInt. +** +** This subroutine is factored out from vdbeSorterCompareReal() for +** efficiency. If inlined into vdbeSorterCompareReal(), this routine +** will use extra stack space and consume CPU cycles setting up and +** breaking down that stack space, even if in the common case where +** this path is not used. +*/ +static SQLITE_NOINLINE int vdbeSorterCompareRealInt( + SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ + int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ + const void *pKey1, int nKey1, /* Left side of comparison */ + const void *pKey2, int nKey2 /* Right side of comparison */ +){ + const u8 * const p1 = (const u8 * const)pKey1; + const u8 * const p2 = (const u8 * const)pKey2; + if( p1[1]==6 || p2[1]==6 ){ + /* 64-bit integer values cannot be represented exactly by a double so + ** must be handled by the generalized comparison function. */ + return vdbeSorterCompare(pTask, + pbKey2Cached, pKey1,nKey1, pKey2,nKey2); + }else{ + double r1 = vdbeSorterGetReal(p1); + double r2 = vdbeSorterGetReal(p2); + return vdbeSorterFinishRealCompare(pTask,pbKey2Cached, + pKey1,nKey1,pKey2,nKey2,r1,r2); + } +} + +/* +** Comparison function optimized for the case where the first term +** of both keys are either MEM_Real or MEM_RealInt. +** +** See also vdbeSorterCompareInt() for MEM_Int values and +** vdbeSorterCompareText() for MEM_Str values. The general +** case is vdbeSorterCompare() which handles anything, but is slower. +*/ +static int vdbeSorterCompareReal( + SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ + int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ + const void *pKey1, int nKey1, /* Left side of comparison */ + const void *pKey2, int nKey2 /* Right side of comparison */ +){ + const u8*const p1 = (const u8*const)pKey1; /* Left key record */ + const u8*const p2 = (const u8*const)pKey2; /* Right key record */ + u64 x; /* A real value stored as an integer */ + double r1; /* First element of pKey1 */ + double r2; /* First element of pKey2 */ + + assert( p1[0]<0x80 && p2[0]<0x80 ); /* 1-byte headers: nAllField<13 */ + assert( p1[1]>0 && p1[1]<10 ); /* first field guaranteed numeric */ + assert( p2[1]>0 && p2[1]<10 ); /* first field guaranteed numeric */ + + if( p1[1]!=7 || p2[1]!=7 ){ + /* One or both floating point values are stored as INTEGER. This might + ** be because of the MEM_RealInt encoding. Try to optimize that case. */ + return vdbeSorterCompareRealInt(pTask, + pbKey2Cached, pKey1,nKey1, pKey2,nKey2 + ); + } + assert( p1[0]<=nKey1-8 && p2[0]<=nKey2-8 ); + + x = sqlite3Get8byte(p1 + *p1); + swapMixedEndianFloat(x); + assert( !IsNaN(x) ); + memcpy(&r1, &x, sizeof(r1)); + x = sqlite3Get8byte(p2 + *p2); + swapMixedEndianFloat(x); + assert( !IsNaN(x) ); + memcpy(&r2, &x, sizeof(r2)); + return vdbeSorterFinishRealCompare(pTask, + pbKey2Cached, pKey1,nKey1, pKey2,nKey2, r1, r2 + ); +} + /* ** Initialize the temporary index cursor just opened as a sorter cursor. ** @@ -107735,7 +107718,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( && (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl) && (pKeyInfo->aSortFlags[0] & KEYINFO_ORDER_BIGNULL)==0 ){ - pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT; + pSorter->typeMask = SORTER_TYPE_INTEGER|SORTER_TYPE_TEXT|SORTER_TYPE_REAL; } } @@ -108037,6 +108020,7 @@ static int vdbeSorterOpenTempFile( ); if( rc==SQLITE_OK ){ i64 max = SQLITE_MAX_MMAP_SIZE; + sqlite3mcOpenTempJournal(db, *ppFd); sqlite3OsFileControlHint(*ppFd, SQLITE_FCNTL_MMAP_SIZE, (void*)&max); if( nExtend>0 ){ vdbeSorterExtendFile(db, *ppFd, nExtend); @@ -108107,10 +108091,12 @@ static SorterRecord *vdbeSorterMerge( ** sorter object passed as the only argument. */ static SorterCompare vdbeSorterGetCompare(VdbeSorter *p){ - if( p->typeMask==SORTER_TYPE_INTEGER ){ + if( p->typeMask & SORTER_TYPE_INTEGER ){ return vdbeSorterCompareInt; - }else if( p->typeMask==SORTER_TYPE_TEXT ){ + }else if( p->typeMask & SORTER_TYPE_TEXT ){ return vdbeSorterCompareText; + }else if( p->typeMask & SORTER_TYPE_REAL ){ + return vdbeSorterCompareReal; } return vdbeSorterCompare; } @@ -108508,8 +108494,12 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite( assert( pCsr->eCurType==CURTYPE_SORTER ); pSorter = pCsr->uc.pSorter; getVarint32NR((const u8*)&pVal->z[1], t); - if( t>0 && t<10 && t!=7 ){ - pSorter->typeMask &= SORTER_TYPE_INTEGER; + if( t>0 && t<10 ){ + if( t==7 ){ + pSorter->typeMask &= SORTER_TYPE_REAL; + }else{ + pSorter->typeMask &= (SORTER_TYPE_INTEGER|SORTER_TYPE_REAL); + } }else if( t>10 && (t & 0x01) ){ pSorter->typeMask &= SORTER_TYPE_TEXT; }else{ @@ -110024,6 +110014,7 @@ struct MemJournal { int flags; /* xOpen flags */ sqlite3_vfs *pVfs; /* The "real" underlying VFS */ const char *zJournal; /* Name of the journal file */ + sqlite3* mcDb; }; /* @@ -110097,6 +110088,7 @@ static int memjrnlCreateFile(MemJournal *p){ memset(p, 0, sizeof(MemJournal)); rc = sqlite3OsOpen(copy.pVfs, copy.zJournal, pReal, copy.flags, 0); if( rc==SQLITE_OK ){ + sqlite3mcOpenTempJournal(copy.mcDb, pReal); int nChunk = copy.nChunkSize; i64 iOff = 0; FileChunk *pIter; @@ -111408,7 +111400,7 @@ static int lookupName( ** cnt>1 means there were two or more matches. ** ** cnt==0 is always an error. cnt>1 is often an error, but might - ** be multiple matches for a NATURAL LEFT JOIN or a LEFT JOIN USING. + ** be multiple matches for a NATURAL OUTER JOIN or a OUTER JOIN USING. */ assert( pFJMatch==0 || cnt>0 ); assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) ); @@ -111491,10 +111483,19 @@ static int lookupName( if( cnt==1 ){ assert( pNC!=0 ); #ifndef SQLITE_OMIT_AUTHORIZATION - if( pParse->db->xAuth - && (pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER) - ){ - sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList); + if( db->xAuth ){ + if( pFJMatch ){ + assert( pExpr->op==TK_FUNCTION ); + assert( sqlite3_stricmp(pExpr->u.zToken,"coalesce")==0 ); + assert( pExpr->x.pList==pFJMatch ); + assert( pFJMatch->nExpr>0 ); + for(i=0; inExpr; i++){ + assert( pFJMatch->a[i].pExpr->op==TK_COLUMN ); + sqlite3AuthRead(pParse,pFJMatch->a[i].pExpr,pSchema,pNC->pSrcList); + } + }else if( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER ){ + sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList); + } } #endif /* Increment the nRef value on all name contexts from TopNC up to @@ -111900,8 +111901,13 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ /* Internal-use-only functions are disallowed unless the ** SQL is being compiled using sqlite3NestedParse() or ** the SQLITE_TESTCTRL_INTERNAL_FUNCTIONS test-control has be - ** used to activate internal functions for testing purposes */ - no_such_func = 1; + ** used to activate internal functions for testing purposes. + ** + ** The 2 value for no_such_func means that the function is + ** an internal-use-only function which should be treated as a + ** non-existant function for name resolution purposes. + */ + no_such_func = 2; pDef = 0; }else if( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 @@ -111945,9 +111951,16 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ is_agg = 0; } #endif - else if( no_such_func && pParse->db->init.busy==0 + else if( no_such_func + && (pParse->db->init.busy==0 || + (no_such_func==2 && pParse->db->init.busy==2)) + /* Suppress "no such function" errors when reading + ** the sqlite_schema table. Except, do raise the error + ** if init.busy is 2, meaning the schema parse is due + ** to an ALTER TABLE ADD COLUMN statement, and the function + ** is an internal-use-only function (no_such_func==2). */ #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION - && pParse->explain==0 + && pParse->explain==0 #endif ){ sqlite3ErrorMsg(pParse, "no such function: %#T", pExpr); @@ -112204,7 +112217,7 @@ static int resolveOrderByTermToExprList( int rc; /* Return code from subprocedures */ u8 savedSuppErr; /* Saved value of db->suppressErr */ - assert( sqlite3ExprIsInteger(pE, &i, 0)==0 ); + assert( sqlite3ExprIsInteger(pE, &i, 0, 0)==0 ); pEList = pSelect->pEList; /* Resolve all names in the ORDER BY term expression @@ -112303,7 +112316,7 @@ static int resolveCompoundOrderBy( if( pItem->fg.done ) continue; pE = sqlite3ExprSkipCollateAndLikely(pItem->pExpr); if( NEVER(pE==0) ) continue; - if( sqlite3ExprIsInteger(pE, &iCol, 0) ){ + if( sqlite3ExprIsInteger(pE, &iCol, 0, 0) ){ if( iCol<=0 || iCol>pEList->nExpr ){ resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr, pE); return 1; @@ -112486,7 +112499,7 @@ static int resolveOrderGroupBy( continue; } } - if( sqlite3ExprIsInteger(pE2, &iCol, 0) ){ + if( sqlite3ExprIsInteger(pE2, &iCol, 0, 0) ){ /* The ORDER BY term is an integer constant. Again, set the column ** number so that sqlite3ResolveOrderGroupBy() will convert the ** order-by term to a copy of the result-set expression */ @@ -113176,23 +113189,29 @@ SQLITE_PRIVATE int sqlite3ExprDataType(const Expr *pExpr){ ** and the pExpr parameter is returned unchanged. */ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken( - const Parse *pParse, /* Parsing context */ + Parse *pParse, /* Parsing context */ Expr *pExpr, /* Add the "COLLATE" clause to this expression */ const Token *pCollName, /* Name of collating sequence */ int dequote /* True to dequote pCollName */ ){ - if( pCollName->n>0 ){ + if( pCollName->n>0 && pParse->nErr==0 ){ Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, dequote); + assert( pExpr!=0 ); if( pNew ){ pNew->pLeft = pExpr; pNew->flags |= EP_Collate|EP_Skip; +#if SQLITE_MAX_EXPR_DEPTH>0 + pNew->nHeight = pExpr->nHeight+1; + sqlite3ExprCheckHeight(pParse, pNew->nHeight); + testcase( pParse->nErr>0 ); +#endif pExpr = pNew; } } return pExpr; } SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString( - const Parse *pParse, /* Parsing context */ + Parse *pParse, /* Parsing context */ Expr *pExpr, /* Add the "COLLATE" clause to this expression */ const char *zC /* The collating sequence name */ ){ @@ -113334,7 +113353,9 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr){ SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse *pParse, const Expr *pE1, const Expr *pE2){ CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pE1); CollSeq *pColl2 = sqlite3ExprNNCollSeq(pParse, pE2); - return sqlite3StrICmp(pColl1->zName, pColl2->zName)==0; + assert( (pColl1==pColl2) == + (sqlite3_stricmp(pColl1->zName,pColl2->zName)==0) ); + return pColl1==pColl2; } /* @@ -113664,6 +113685,7 @@ static int exprVectorRegister( Expr *pVector, /* Vector to extract element from */ int iField, /* Field to extract from pVector */ int regSelect, /* First in array of registers */ + Expr *pTmp, /* Temporary space */ Expr **ppExpr, /* OUT: Expression element */ int *pRegFree /* OUT: Temp register to free */ ){ @@ -113675,8 +113697,17 @@ static int exprVectorRegister( } if( op==TK_SELECT ){ assert( ExprUseXSelect(pVector) ); - *ppExpr = pVector->x.pSelect->pEList->a[iField].pExpr; - return regSelect+iField; + /* Use the temporary expression node to wrap expression iField of the + ** sub-select in a TK_SELECT_COLUMN node. This causes the caller to + ** use the affinity of the expression in any comparison, but not the + ** collation sequence. */ + memset(pTmp, 0, sizeof(Expr)); + pTmp->op = TK_SELECT_COLUMN; + pTmp->pLeft = pVector; + pTmp->iColumn = iField; + pTmp->iTable = pVector->x.pSelect->pEList->nExpr; + *ppExpr = pTmp; + return regSelect+iField; } if( op==TK_VECTOR ){ assert( ExprUseXList(pVector) ); @@ -113743,11 +113774,12 @@ static void codeVectorCompare( for(i=0; 1 /*Loop exits by "break"*/; i++){ int regFree1 = 0, regFree2 = 0; Expr *pL = 0, *pR = 0; + Expr tmp1, tmp2; int r1, r2; assert( i>=0 && ipParse->nVar ){ pParse->nVar = (int)x; doAdd = 1; + }else if( xaVnbmc[x>>6] & MASKBIT64(x&63))==0; }else if( sqlite3VListNumToName(pParse->pVList, x)==0 ){ doAdd = 1; } @@ -114375,6 +114409,9 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n } if( doAdd ){ pParse->pVList = sqlite3VListAdd(db, pParse->pVList, z, n, x); + if( pParse->pVList!=0 && xaVnbmc[x>>6] |= MASKBIT64(x&63); + } } } pExpr->iColumn = x; @@ -115506,7 +115543,7 @@ static SQLITE_NOINLINE int exprNodeIsConstantFunction( if( pDef==0 || pDef->xFinalize!=0 || (pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0 - || ExprHasProperty(pExpr, EP_WinFunc) + || NEVER(ExprHasProperty(pExpr, EP_WinFunc)) ){ pWalker->eCode = 0; return WRC_Abort; @@ -115527,6 +115564,7 @@ static SQLITE_NOINLINE int exprNodeIsConstantFunction( ** sqlite3ExprIsConstantNotJoin() pWalker->eCode==2 ** sqlite3ExprIsTableConstant() pWalker->eCode==3 ** sqlite3ExprIsConstantOrFunction() pWalker->eCode==4 or 5 +** sqlite3ExprListIsConstant() pWalker->eCode==1 or 6 ** ** In all cases, the callbacks set Walker.eCode=0 and abort if the expression ** is found to not be a constant. @@ -115553,19 +115591,25 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ } switch( pExpr->op ){ - /* Consider functions to be constant if all their arguments are constant - ** and either pWalker->eCode==4 or 5 or the function has the - ** SQLITE_FUNC_CONST flag. */ case TK_FUNCTION: - if( (pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc)) - && !ExprHasProperty(pExpr, EP_WinFunc) - ){ + if( ExprHasProperty(pExpr, EP_WinFunc) ){ + pWalker->eCode = 0; /* Window functions are never constant */ + return WRC_Abort; + }else if( pWalker->eCode>=4 && pWalker->eCode<=5 ){ + /* Functions used within a CREATE TABLE statement are constant as + ** long as all of their arguments are constant */ if( pWalker->eCode==5 ) ExprSetProperty(pExpr, EP_FromDDL); return WRC_Continue; + }else if( ExprHasProperty(pExpr,EP_ConstFunc) ){ + /* Functions marked with EP_ConstFunc are constant as long as + ** all their arugments are constant and they are not window functions */ + return WRC_Continue; }else if( pWalker->pParse ){ + /* Functions are constant if they have SQLITE_FUNC_CONSTANT or + ** SQLITE_FUNC_SLOCHNG and if all arguments are constant */ return exprNodeIsConstantFunction(pWalker, pExpr); }else{ - pWalker->eCode = 0; + pWalker->eCode = 0; /* Function call is not constant */ return WRC_Abort; } case TK_ID: @@ -115599,6 +115643,13 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_RAISE ); pWalker->eCode = 0; return WRC_Abort; + case TK_IS: + case TK_ISNOT: + if( pWalker->eCode==6 ){ + pWalker->eCode = 0; + return WRC_Abort; + } + return WRC_Continue; case TK_VARIABLE: if( pWalker->eCode==5 ){ /* Silently convert bound parameters that appear inside of CREATE @@ -115649,11 +115700,27 @@ SQLITE_PRIVATE int sqlite3ExprIsConstant(Parse *pParse, Expr *p){ return exprIsConst(pParse, p, 1); } +/* +** Return true if all expressions in pList are constant. If parameter bNoIs +** is true, do not consider expressions that contain "IS" operators to be +** constant. IS operators are not always considered constant as expressions +** like "x IS TRUE" need to be transformed to TK_TRUTH expression nodes, +** which happens at the same time as column name resolution. +*/ +SQLITE_PRIVATE int sqlite3ExprListIsConstant(Parse *pParse, ExprList *pList, int bNoIs){ + const int iInit = bNoIs ? 6 : 1; + int ii; + for(ii=0; iinExpr; ii++){ + if( 0==exprIsConst(pParse, pList->a[ii].pExpr, iInit) ) return 0; + } + return 1; +} + /* ** Walk an expression tree. Return non-zero if ** ** (1) the expression is constant, and -** (2) the expression does originate in the ON or USING clause +** (2) the expression does not originate in the ON or USING clause ** of a LEFT JOIN, and ** (3) the expression does not contain any EP_FixedCol TK_COLUMN ** operands created by the constant propagation optimization. @@ -115890,65 +115957,75 @@ SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){ #endif /* -** If the expression p codes a constant integer that is small enough -** to fit in a 32-bit integer, return 1 and put the value of the integer -** in *pValue. If the expression is not an integer or if it is too big -** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged. +** If the expression p codes a constant integer between 0 and 0x7fffffff, +** then return 1 and put the value of the integer in *pValue. If the +** expression is not an integer or if it is an integer that is out side +** the range of 0...0x7fffffff, then return 0 and leave *pValue unchanged. ** ** If the pParse pointer is provided, then allow the expression p to be -** a parameter (TK_VARIABLE) that is bound to an integer. -** But if pParse is NULL, then p must be a pure integer literal. -*/ -SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr *p, int *pValue, Parse *pParse){ - int rc = 0; - if( NEVER(p==0) ) return 0; /* Used to only happen following on OOM */ - - /* If an expression is an integer literal that fits in a signed 32-bit - ** integer, then the EP_IntValue flag will have already been set */ - assert( p->op!=TK_INTEGER || (p->flags & EP_IntValue)!=0 - || sqlite3GetInt32(p->u.zToken, &rc)==0 ); - - if( p->flags & EP_IntValue ){ - *pValue = p->u.iValue; - return 1; - } - switch( p->op ){ - case TK_UPLUS: { - rc = sqlite3ExprIsInteger(p->pLeft, pValue, 0); - break; +** a parameter (TK_VARIABLE) that is bound to an integer between 0 and +** 0x7fffffff. Variables that hold anything other than integers, or that +** hold integers outside the range of 0..0x7fffffff are not seen. +** But if pParse is NULL, then p must be a pure integer literal between +** 0 and 0x7fffffff. +** +** If pParse is not NULL and expression p is a variable, then the variable +** is marked so as to cause the statement to be reprepared each time a new +** value is bound to it. Except, if parameter bRSI is true, then the statement +** will only be reprepared if the rebind changes the value to or from a +** "small integer" (either 0 or 1). Note that if p is a variable then +** reprepare is always enabled for that variable, regardless of its current +** binding. The RSI is only enabled if the current binding is a small +** integer. "RSI" stands for "Reprepare Small Integers". +*/ +SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr *p, int *pValue, Parse *pParse, int bRSI){ + int iSign = 1; /* Either +1 or -1. */ + while( 1/*exit-by-break*/ ){ + if( NEVER(p==0) ) return 0; + if( ExprUseUValue(p) ){ + *pValue = p->u.iValue*iSign; + return 1; } - case TK_UMINUS: { - int v = 0; - if( sqlite3ExprIsInteger(p->pLeft, &v, 0) ){ - assert( ((unsigned int)v)!=0x80000000 ); - *pValue = -v; - rc = 1; - } - break; + if( p->op==TK_UPLUS ){ + p = p->pLeft; + pParse = 0; + continue; } - case TK_VARIABLE: { - sqlite3_value *pVal; - if( pParse==0 ) break; + if( p->op==TK_UMINUS ){ + iSign = -iSign; + p = p->pLeft; + pParse = 0; + continue; + } + if( p->op==TK_VARIABLE && pParse!=0 ){ + sqlite3_value *pVal; /* The variable */ + int isSmall = 0; /* Only reprepare if change to/from small integer */ + int rc = 0; /* 1 if successful, 0 if failed */ + assert( iSign==1 ); if( NEVER(pParse->pVdbe==0) ) break; if( (pParse->db->flags & SQLITE_EnableQPSG)!=0 ) break; - sqlite3VdbeSetVarmask(pParse->pVdbe, p->iColumn); pVal = sqlite3VdbeGetBoundValue(pParse->pReprepare, p->iColumn, SQLITE_AFF_BLOB); if( pVal ){ - if( sqlite3_value_type(pVal)==SQLITE_INTEGER ){ - sqlite3_int64 vv = sqlite3_value_int64(pVal); - if( vv == (vv & 0x7fffffff) ){ /* non-negative numbers only */ - *pValue = (int)vv; - rc = 1; + i64 vv; + if( sqlite3_value_type(pVal)==SQLITE_INTEGER + && (vv = sqlite3_value_int64(pVal))>=0 + && vv<=0x7fffffff + ){ + *pValue = (int)vv; + if( bRSI ){ + isSmall = vv<=1; } + rc = 1; } sqlite3ValueFree(pVal); } - break; + sqlite3VdbeReprepareOnBind(pParse->pVdbe, p->iColumn, isSmall); + return rc; } - default: break; + break; } - return rc; + return 0; } /* @@ -116082,10 +116159,8 @@ static Select *isCandidateForInOpt(const Expr *pX){ if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */ p = pX->x.pSelect; if( p->pPrior ) return 0; /* Not a compound SELECT */ - if( p->selFlags & (SF_Distinct|SF_Aggregate) ){ - testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ); - testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate ); - return 0; /* No DISTINCT keyword and no aggregate functions */ + if( p->selFlags & SF_Aggregate ){ + return 0; /* No GROUP BY keyword or aggregate functions */ } assert( p->pGroupBy==0 ); /* Has no GROUP BY clause */ if( p->pLimit ) return 0; /* Has no LIMIT clause */ @@ -116117,13 +116192,24 @@ static Select *isCandidateForInOpt(const Expr *pX){ ** to a non-NULL value if iCur contains no NULLs. Cause register regHasNull ** to be set to NULL if iCur contains one or more NULL values. */ -static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){ +static void sqlite3SetHasNullFlag( + Vdbe *v, /* Write new code into this statement under construction */ + int iCur, /* Cursor for the index */ + int regHasNull, /* Register in which to store hasNull flag */ + int eSortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */ +){ int addr1; + int op; sqlite3VdbeAddOp2(v, OP_Integer, 0, regHasNull); - addr1 = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v); + if( eSortOrder==SQLITE_SO_ASC ){ + op = OP_Rewind; + }else{ + op = OP_Last; + } + addr1 = sqlite3VdbeAddOp1(v, op, iCur); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, regHasNull); sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); - VdbeComment((v, "first_entry_in(%d)", iCur)); + VdbeComment((v, op==OP_Last?"last_entry_in(%d)":"first_entry_in(%d)", iCur)); sqlite3VdbeJumpHere(v, addr1); } #endif @@ -116384,13 +116470,14 @@ SQLITE_PRIVATE int sqlite3FindInIndex( if( prRhsHasNull ){ #ifdef SQLITE_ENABLE_COLUMN_USED_MASK - i64 mask = (1<nMem; if( nExpr==1 ){ - sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull); + sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull, + pIdx->aSortOrder[0]); } } sqlite3VdbeJumpHere(v, iAddr); @@ -116439,7 +116526,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex( } sqlite3CodeRhsOfIN(pParse, pX, iTab, bloomOk); if( rMayHaveNull ){ - sqlite3SetHasNullFlag(v, iTab, rMayHaveNull); + sqlite3SetHasNullFlag(v, iTab, rMayHaveNull, SQLITE_SO_ASC); } pParse->nQueryLoop = savedNQueryLoop; } @@ -116694,6 +116781,8 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( } #endif pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nVal, 1); + assert( pKeyInfo!=0 || pParse->nErr ); + if( pKeyInfo==0 ) return; if( ExprUseXSelect(pExpr) ){ /* Case 1: expr IN (SELECT ...) @@ -116718,6 +116807,19 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( sqlite3SelectDestInit(&dest, SRT_Set, iTab); dest.zAffSdst = exprINAffinity(pParse, pExpr); pSelect->iLimit = 0; + assert( pEList!=0 ); + assert( pEList->nExpr>0 ); + assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); + for(i=0; iaColl[i] = pColl = sqlite3BinaryCompareCollSeq( + pParse, p, pEList->a[i].pExpr + ); + if( !sqlite3IsBinary(pColl) ){ + allowBloom = 0; /* tag-202607231411 */ + } + } if( addrOnce && allowBloom && OptimizationEnabled(pParse->db, SQLITE_BloomFilter) @@ -116726,9 +116828,10 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( addrBloom = sqlite3VdbeAddOp2(v, OP_Blob, 10000, regBloom); VdbeComment((v, "Bloom filter")); dest.iSDParm2 = regBloom; + sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO); + pKeyInfo = 0; } testcase( pSelect->selFlags & SF_Distinct ); - testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ pCopy = sqlite3SelectDup(pParse->db, pSelect, 0); rc = pParse->db->mallocFailed ? 1 :sqlite3Select(pParse, pCopy, &dest); sqlite3SelectDelete(pParse->db, pCopy); @@ -116746,16 +116849,6 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( sqlite3KeyInfoUnref(pKeyInfo); return; } - assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */ - assert( pEList!=0 ); - assert( pEList->nExpr>0 ); - assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); - for(i=0; iaColl[i] = sqlite3BinaryCompareCollSeq( - pParse, p, pEList->a[i].pExpr - ); - } } }else if( ALWAYS(pExpr->x.pList!=0) ){ /* Case 2: expr IN (exprlist) @@ -116776,10 +116869,9 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( }else if( affinity==SQLITE_AFF_REAL ){ affinity = SQLITE_AFF_NUMERIC; } - if( pKeyInfo ){ - assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); - pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft); - } + assert( pKeyInfo!=0 ); + assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); + pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft); /* Loop through each expression in . */ r1 = sqlite3GetTempReg(pParse); @@ -117164,13 +117256,28 @@ static void sqlite3ExprCodeIN( ** we need to reorder the LHS values to be in index order. Run Affinity ** before reordering the columns, so that the affinity is correct. */ - sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector); + if( nVector==1 ){ + char aff = zAff[0]; + if( aff>=SQLITE_AFF_TEXT && aff!=sqlite3ExprAffinity(pLeft) ){ + /* The OP_Affinity below may change the value. In this case, create a + ** copy of rLhs to run OP_Affinity on, in case the original register + ** is used again (e.g. if it is TK_AGG_COLUMN). */ + int rTmp = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_Copy, rLhs, rTmp, 0); + rLhs = rTmp; + sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, 1, 0, zAff, 1); + } + }else{ + sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector); + } + for(i=0; ipLeft, i); if( pParse->nErr ) goto sqlite3ExprCodeIN_oom_error; if( sqlite3ExprCanBeNull(p) ){ + testcase( aiMap[i]!=i ); sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+aiMap[i], destStep2); VdbeCoverage(v); } @@ -117251,7 +117359,13 @@ static void sqlite3ExprCodeIN( ** of the RHS. */ if( destStep6 ) sqlite3VdbeResolveLabel(v, destStep6); - addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, destIfFalse); + if( eType==IN_INDEX_INDEX_DESC ){ + addrTop = sqlite3VdbeAddOp2(v, OP_Last, iTab, destIfFalse); + }else{ + testcase( eType==IN_INDEX_EPH ); + testcase( eType==IN_INDEX_ROWID ); + addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, destIfFalse); + } VdbeCoverage(v); if( nVector>1 ){ destNotNull = sqlite3VdbeMakeLabel(pParse); @@ -117275,6 +117389,7 @@ static void sqlite3ExprCodeIN( ** ...)" is the collating sequence of x.". */ pColl = sqlite3ExprCollSeq(pParse, p); } + testcase( aiMap[i]!=i ); sqlite3VdbeAddOp3(v, OP_Column, iTab, aiMap[i], r3); sqlite3VdbeAddOp4(v, OP_Ne, rLhs+aiMap[i], destNotNull, r3, (void*)pColl, P4_COLLSEQ); @@ -117318,7 +117433,7 @@ static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){ sqlite3AtoF(z, &value); assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */ if( negateFlag ) value = -value; - sqlite3VdbeAddOp4Dup8(v, OP_Real, 0, iMem, 0, (u8*)&value, P4_REAL); + sqlite3VdbeAddDouble(v, iMem, value); } } #endif @@ -117359,7 +117474,7 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ #endif }else{ if( negFlag ){ value = c==3 ? SMALLEST_INT64 : -value; } - sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64); + sqlite3VdbeAddInt64(v, iMem, value); } } } @@ -117440,12 +117555,12 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable( if( iCol<0 || iCol==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut); VdbeComment((v, "%s.rowid", pTab->zName)); - }else{ - int op; + }else{ int x; if( IsVirtual(pTab) ){ - op = OP_VColumn; x = iCol; + sqlite3VdbeAddOp3(v, OP_VColumn, iTabCur, x, regOut); + return; #ifndef SQLITE_OMIT_GENERATED_COLUMNS }else if( (pCol = &pTab->aCol[iCol])->colFlags & COLFLAG_VIRTUAL ){ Parse *pParse = sqlite3VdbeParser(v); @@ -117465,13 +117580,11 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable( }else if( !HasRowid(pTab) ){ testcase( iCol!=sqlite3TableColumnToStorage(pTab, iCol) ); x = sqlite3TableColumnToIndex(sqlite3PrimaryKeyIndex(pTab), iCol); - op = OP_Column; }else{ x = sqlite3TableColumnToStorage(pTab,iCol); testcase( x!=iCol ); - op = OP_Column; } - sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut); + sqlite3VdbeAddOp3(v, OP_Column, iTabCur, x, regOut); sqlite3ColumnDefault(v, pTab, iCol, regOut); } } @@ -117733,7 +117846,7 @@ static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){ } assert( ExprUseXList(pExpr) ); db = pWalker->pParse->db; - n = ALWAYS(pExpr->x.pList) ? pExpr->x.pList->nExpr : 0; + n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0; pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){ pWalker->eCode = 1; @@ -117750,7 +117863,7 @@ static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){ ** 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){ +SQLITE_PRIVATE int sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){ Walker w; memset(&w, 0, sizeof(w)); w.pParse = pParse; @@ -117854,6 +117967,11 @@ static int exprPartidxExprLookup(Parse *pParse, Expr *pExpr, int iTarget){ ret = sqlite3ExprCodeTarget(pParse, p->pExpr, iTarget); sqlite3VdbeAddOp4(pParse->pVdbe, OP_Affinity, ret, 1, 0, (const char*)&p->aff, 1); + if( sqlite3ExprCanReturnSubtype(pParse, p->pExpr) ){ + /* If the expression value may have a sub-type, clear it. Values + ** read from columns do not have subtypes. */ + sqlite3VdbeAddOp1(pParse->pVdbe, OP_ClrSubtype, ret); + } if( addr ){ sqlite3VdbeJumpHere(v, addr); sqlite3VdbeChangeP3(v, addr, ret); @@ -118382,7 +118500,12 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) pDef = sqlite3FindFunction(db, "unknown", nFarg, enc, 0); } #endif - if( pDef==0 || pDef->xFinalize!=0 ){ + if( pDef==0 + || pDef->xFinalize!=0 + || ((pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0 && + !pParse->nested && + (db->mDbFlags & DBFLAG_InternalFunc)==0) + ){ sqlite3ErrorMsg(pParse, "unknown function: %#T()", pExpr); break; } @@ -119523,7 +119646,7 @@ static SQLITE_NOINLINE int exprCompareVariable( sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR); if( pR ){ iVar = pVar->iColumn; - sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); + sqlite3VdbeReprepareOnBind(pParse->pVdbe, iVar, 0); pL = sqlite3VdbeGetBoundValue(pParse->pReprepare, iVar, SQLITE_AFF_BLOB); if( pL ){ if( sqlite3_value_type(pL)==SQLITE_TEXT ){ @@ -119779,7 +119902,7 @@ static int sqlite3ExprIsNotTrue(Expr *pExpr){ if( pExpr->op==TK_NULL ) return 1; if( pExpr->op==TK_TRUEFALSE && sqlite3ExprTruthValue(pExpr)==0 ) return 1; v = 1; - if( sqlite3ExprIsInteger(pExpr, &v, 0) && v==0 ) return 1; + if( sqlite3ExprIsInteger(pExpr, &v, 0, 0) && v==0 ) return 1; return 0; } @@ -121030,6 +121153,30 @@ static void sqlite3ErrorIfNotEmpty( ); } +/* +** zCol is a column name used in an ALTER TABLE DROP, ADD or RENAME COLUMN +** operation. zOp identifies the specific operation - "drop", "add", "rename +** to" or "rename from". pTab is the table being altered. +** +** If pTab has a rowid and zCol is a rowid alias, then SQLITE_ERROR is +** returned and an error message left in pParse. Or, if zCol is not an alias +** for "rowid" or pTab is not an intkey table, then SQLITE_OK is returned. +*/ +static int isRowidAlias( + Parse *pParse, + Table *pTab, + const char *zCol, + const char *zOp +){ + if( HasRowid(pTab) && sqlite3IsRowid(zCol) ){ + sqlite3ErrorMsg(pParse, "cannot %s rowid alias: %s", zOp, zCol); + return SQLITE_ERROR; + } + return SQLITE_OK; +} + + + /* ** This function is called after an "ALTER TABLE ... ADD" statement ** has been parsed. Argument pColDef contains the text of the new @@ -121075,9 +121222,9 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ #endif - /* Check that the new column is not specified as PRIMARY KEY or UNIQUE. - ** If there is a NOT NULL constraint, then the default value for the - ** column must not be NULL. + /* Check that the new column is not specified as PRIMARY KEY or UNIQUE, + ** or a rowid alias. If there is a NOT NULL constraint, then the default + ** value for the column must not be NULL. */ if( pCol->colFlags & COLFLAG_PRIMKEY ){ sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column"); @@ -121088,6 +121235,7 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ "Cannot add a UNIQUE column"); return; } + if( isRowidAlias(pParse, pTab, pCol->zCnName, "add") ) return; if( (pCol->colFlags & COLFLAG_GENERATED)==0 ){ /* If the default value for the new column was specified with a ** literal NULL, then set pDflt to 0. This simplifies checking @@ -121176,6 +121324,7 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ || (pCol->notNull && (pCol->colFlags & COLFLAG_GENERATED)!=0) || (pTab->tabFlags & TF_Strict)!=0 ){ + pParse->colNamesSet = 1; sqlite3NestedParse(pParse, "SELECT CASE WHEN quick_check GLOB 'CHECK*'" " THEN raise(ABORT,'CHECK constraint failed')" @@ -121380,6 +121529,8 @@ SQLITE_PRIVATE void sqlite3AlterRenameColumn( sqlite3MayAbort(pParse); zNew = sqlite3NameFromToken(db, pNew); if( !zNew ) goto exit_rename_column; + if( isRowidAlias(pParse, pTab, zOld, "rename from") ) goto exit_rename_column; + if( isRowidAlias(pParse, pTab, zNew, "rename to") ) goto exit_rename_column; assert( pNew->n>0 ); bQuote = sqlite3Isquote(pNew->z[0]); sqlite3NestedParse(pParse, @@ -123006,6 +123157,7 @@ SQLITE_PRIVATE void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, const T sqlite3ErrorMsg(pParse, "no such column: \"%T\"", pName); goto exit_drop_column; } + if( isRowidAlias(pParse, pTab, zCol, "drop") ) goto exit_drop_column; /* Do not allow the user to drop a PRIMARY KEY column or a column ** constrained by a UNIQUE constraint. */ @@ -123137,16 +123289,38 @@ static int getWhitespace(const u8 *z){ /* ** Argument z points into the body of a constraint - specifically the ** second token of the constraint definition. For a named constraint, -** z points to the first token past the CONSTRAINT keyword. For an +** z points to the second token of the constraint definition. For an ** unnamed NOT NULL constraint, z points to the first byte past the NOT ** keyword. ** +** Argument eTok may be the token value of the first token of the constraint +** (e.g. TK_CHECK or TK_REFERENCES) or zero. If it is either TK_REFERENCES +** or TK_FOREIGN, special parsing is enabled to find the end of the foreign-key +** constraint definition. +** ** Return the number of bytes until the end of the constraint. */ -static int getConstraint(const u8 *z){ +static int getConstraint(const u8 *z, int eTok){ int iOff = 0; int t = 0; +#ifndef SQLITE_OMIT_FOREIGN_KEY + if( eTok==TK_FOREIGN ){ + /* For a FOREIGN KEY constraint, use getConstraint() to parse everything + ** up to the REFERENCES keyword. Then getConstraintToken() to consume + ** the TK_REFERENCES token itself. Then fall through to the special + ** handling for TK_REFERENCES below. */ + iOff = getConstraint(z, 0); + iOff += getConstraintToken(&z[iOff], &eTok); + } + + if( eTok==TK_REFERENCES ){ + /* REFERENCES is followed by a table name. Gobble this up here in + ** case the table name is a fallback token like TK_GENERATED. */ + iOff += getConstraintToken(&z[iOff], &t); + } +#endif + /* Now, the current constraint proceeds until the next occurence of one ** of the following tokens: ** @@ -123318,11 +123492,11 @@ static void dropConstraintFunc( t = TK_CHECK; }else{ iOff += nTok; - iOff += getConstraint(&zSql[iOff]); + iOff += getConstraint(&zSql[iOff], t); } if( cmp==0 || (iNotNull>=0 && t==TK_NOT) ){ - if( t!=TK_NOT && t!=TK_CHECK ){ + if( t!=TK_NOT && t!=TK_CHECK && t!=TK_REFERENCES && t!=TK_FOREIGN ){ errorMPrintf(ctx, "constraint may not be dropped: %s", zCons); return; } @@ -123331,7 +123505,7 @@ static void dropConstraintFunc( } }else if( t==TK_NOT && iNotNull==ii ){ - iEnd = iOff + getConstraint(&zSql[iOff]); + iEnd = iOff + getConstraint(&zSql[iOff], 0); break; }else if( t==TK_RP || t==TK_ILLEGAL ){ iEnd = -1; @@ -123389,9 +123563,8 @@ static void addConstraintFunc( int iCol = sqlite3_value_int(argv[2]); int iOff = 0; int ii; - char *zNew = 0; + sqlite3_str *pNew; int t = 0; - sqlite3 *db; UNUSED_PARAMETER(NotUsed); if( skipCreateTable(ctx, zSql, &iOff) ) return; @@ -123411,13 +123584,11 @@ static void addConstraintFunc( iOff += getWhitespace(&zSql[iOff]); - db = sqlite3_context_db_handle(ctx); - if( iCol<0 ){ - zNew = sqlite3MPrintf(db, "%.*s, %s%s", iOff, zSql, zCons, &zSql[iOff]); - }else{ - zNew = sqlite3MPrintf(db, "%.*s %s%s", iOff, zSql, zCons, &zSql[iOff]); - } - sqlite3_result_text(ctx, zNew, -1, SQLITE_DYNAMIC); + pNew = sqlite3_str_new(sqlite3_context_db_handle(ctx)); + sqlite3_str_append(pNew, (const char*)zSql, iOff); + if( iCol<0 ) sqlite3_str_append(pNew, ",", 1); + sqlite3_str_appendf(pNew, " %s%s", zCons, &zSql[iOff]); + sqlite3_result_str(ctx, pNew, SQLITE_FINISH); } /* @@ -123759,7 +123930,7 @@ SQLITE_PRIVATE void sqlite3AlterAddConstraint( /* Search for a constraint violation. Throw an exception if one is found. */ sqlite3NestedParse(pParse, "SELECT sqlite_fail('constraint failed', %d) " - "FROM %Q.%Q WHERE (%.*s) IS NOT TRUE", + "FROM %Q.%Q WHERE (%.*s) IS FALSE", SQLITE_CONSTRAINT, zDb, pTab->zName, nExpr, zExpr ); @@ -124677,7 +124848,7 @@ static void statGet( assert( p->current.anEq[i] || p->nRow==0 ); #endif } - sqlite3ResultStrAccum(context, &sStat); + sqlite3_result_str(context, &sStat, SQLITE_XFER); } #ifdef SQLITE_ENABLE_STAT4 else if( eCall==STAT_GET_ROWID ){ @@ -124714,7 +124885,7 @@ static void statGet( sqlite3_str_appendf(&sStat, "%llu ", (u64)aCnt[i]); } if( sStat.nChar ) sStat.nChar--; - sqlite3ResultStrAccum(context, &sStat); + sqlite3_result_str(context, &sStat, SQLITE_XFER); } #endif /* SQLITE_ENABLE_STAT4 */ #ifndef SQLITE_DEBUG @@ -125872,6 +126043,23 @@ SQLITE_PRIVATE int sqlite3DbIsNamed(sqlite3 *db, int iDb, const char *zName){ ); } +/* +** If any TEMP triggers reference schema pSchema, move those triggers to +** reference the TEMP schema itself. +*/ +static void detachTempTriggers(sqlite3 *db, Schema *pSchema){ + HashElem *pEntry; + assert( db->aDb[1].pSchema ); + pEntry = sqliteHashFirst(&db->aDb[1].pSchema->trigHash); + while( pEntry ){ + Trigger *pTrig = (Trigger*)sqliteHashData(pEntry); + if( pTrig->pTabSchema==pSchema ){ + pTrig->pTabSchema = pTrig->pSchema; + } + pEntry = sqliteHashNext(pEntry); + } +} + /* ** An SQL user-function registered to do the work of an ATTACH statement. The ** three arguments to the function come directly from an attach statement: @@ -125941,9 +126129,16 @@ static void attachFunc( /* Both the Btree and the new Schema were allocated successfully. ** Close the old db and update the aDb[] slot with the new memdb ** values. */ + detachTempTriggers(db, pNew->pSchema); sqlite3BtreeClose(pNew->pBt); pNew->pBt = pNewBt; pNew->pSchema = pNewSchema; + if( db->init.iDb==0 ){ + /* Clear all eponymous virtual table instances, as they are holding + ** pointers to the schema object just freed by sqlite3BtreeClose() */ + sqlite3VtabEponymousTableClearAll(db); + } + sqlite3ExpirePreparedStatements(db, 1); }else{ sqlite3BtreeClose(pNewBt); rc = SQLITE_NOMEM; @@ -126120,7 +126315,6 @@ static void detachFunc( sqlite3 *db = sqlite3_context_db_handle(context); int i; Db *pDb = 0; - HashElem *pEntry; char zErr[128]; UNUSED_PARAMETER(NotUsed); @@ -126147,18 +126341,7 @@ static void detachFunc( goto detach_error; } - /* If any TEMP triggers reference the schema being detached, move those - ** triggers to reference the TEMP schema itself. */ - assert( db->aDb[1].pSchema ); - pEntry = sqliteHashFirst(&db->aDb[1].pSchema->trigHash); - while( pEntry ){ - Trigger *pTrig = (Trigger*)sqliteHashData(pEntry); - if( pTrig->pTabSchema==pDb->pSchema ){ - pTrig->pTabSchema = pTrig->pSchema; - } - pEntry = sqliteHashNext(pEntry); - } - + detachTempTriggers(db, pDb->pSchema); sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; pDb->pSchema = 0; @@ -126644,8 +126827,14 @@ SQLITE_PRIVATE void sqlite3AuthRead( ** either SQLITE_OK (zero) or SQLITE_IGNORE or SQLITE_DENY. If SQLITE_DENY ** is returned, then the error count and error message in pParse are ** modified appropriately. +** +** Divided into two routines. realAuthCheck() does the work. The +** sqlite3AuthCheck() routine is usually a fast no-op but invokes +** realAuthCheck() (and spends time doing some stack pushes and pops +** as a result) in the uncommon case where an authorization check is +** actually needed. */ -SQLITE_PRIVATE int sqlite3AuthCheck( +static int SQLITE_NOINLINE realAuthCheck( Parse *pParse, int code, const char *zArg1, @@ -126659,7 +126848,7 @@ SQLITE_PRIVATE int sqlite3AuthCheck( ** or if the parser is being invoked from within sqlite3_declare_vtab. */ assert( !IN_RENAME_OBJECT || db->xAuth==0 ); - if( db->xAuth==0 || db->init.busy || IN_SPECIAL_PARSE ){ + if( IN_SPECIAL_PARSE ){ return SQLITE_OK; } @@ -126684,6 +126873,19 @@ SQLITE_PRIVATE int sqlite3AuthCheck( } return rc; } +SQLITE_PRIVATE int sqlite3AuthCheck( + Parse *pParse, + int code, + const char *zArg1, + const char *zArg2, + const char *zArg3 +){ + if( pParse->db->xAuth!=0 && pParse->db->init.busy==0 ){ + return realAuthCheck(pParse,code,zArg1,zArg2,zArg3); + }else{ + return SQLITE_OK; + } +} /* ** Push an authorization context. After this routine is called, the @@ -126788,6 +126990,7 @@ static SQLITE_NOINLINE void lockTable( assert( pToplevel->nTableLock < 0x7fff0000 ); nBytes = sizeof(TableLock) * (pToplevel->nTableLock+1); + if( pToplevel->nTableLock==0 ) pToplevel->aTableLock = 0; pToplevel->aTableLock = sqlite3DbReallocOrFree(pToplevel->db, pToplevel->aTableLock, nBytes); if( pToplevel->aTableLock ){ @@ -126954,7 +127157,7 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ /* Initialize any AUTOINCREMENT data structures required. */ - if( pParse->pAinc ) sqlite3AutoincrementBegin(pParse); + if( pParse->usesAinc ) sqlite3AutoincrementBegin(pParse); /* Code constant expressions that were factored out of inner loops. */ @@ -126987,7 +127190,7 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ if( pParse->nErr==0 ){ /* A minimum of one cursor is required if autoincrement is used * See ticket [a696379c1f08866] */ - assert( pParse->pAinc==0 || pParse->nTab>0 ); + assert( pParse->usesAinc==0 || pParse->nTab>0 ); sqlite3VdbeMakeReady(v, pParse); pParse->rc = SQLITE_DONE; }else{ @@ -127419,10 +127622,41 @@ SQLITE_PRIVATE void sqlite3ColumnSetExpr( } } +#ifndef SQLITE_OMIT_AUTHORIZATION +/* +** If the expression contains any TK_FUNCTION, send it to the authorizer +** and if the authorization fails then raise an error. +*/ +static int authFunctions(Walker *pWalker, Expr *p){ + if( p->op==TK_FUNCTION ){ + Parse *pParse = pWalker->pParse; + int rc = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, p->u.zToken, 0); + if( rc ){ + sqlite3ErrorMsg(pParse, "not authorized to use function: %#T", p); + return WRC_Abort; + } + } + return WRC_Continue; +} +static void sqlite3FuncAuth(Parse *pParse, Expr *pExpr){ + Walker w; + memset(&w, 0, sizeof(w)); + w.xExprCallback = authFunctions; + w.pParse = pParse; + sqlite3WalkExpr(&w,pExpr); +} +#endif /* SQLITE_OMIT_AUTHORIZATION */ + /* ** Return the expression associated with a column. The expression might be ** the DEFAULT clause or the AS clause of a generated column. ** Return NULL if the column has no associated expression. +** +** There are two variants of this routine. sqlite3ColumnExpr() just +** returns the expression with no side effects. sqlite3ColumnExprAuth() +** takes the extra step of invoking the authorizer (if one is defined) +** and raising an error if the returned expression uses any unauthorized +** SQL function. */ SQLITE_PRIVATE Expr *sqlite3ColumnExpr(Table *pTab, Column *pCol){ if( pCol->iDflt==0 ) return 0; @@ -127431,6 +127665,28 @@ SQLITE_PRIVATE Expr *sqlite3ColumnExpr(Table *pTab, Column *pCol){ if( NEVER(pTab->u.tab.pDfltList->nExpriDflt) ) return 0; return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr; } +SQLITE_PRIVATE Expr *sqlite3ColumnExprAuth(Table *pTab, Column *pCol, Parse *pParse){ + Expr *pExpr = sqlite3ColumnExpr(pTab,pCol); +#ifndef SQLITE_OMIT_AUTHORIZATION + if( pParse->db->xAuth!=0 ){ + sqlite3FuncAuth(pParse, pExpr); + } +#endif + return pExpr; +} + +/* +** Suppress false-positive warning message generated with -O3 in GCC +** on the second call to sqlite3Strlen30() in the sqlite3ColumnSetColl() +** function below. See the forum thread beginning on 2026-05-10T01:11:22Z. +** +** See also the "pop" pragma to undo this warning suppression immediately +** after the function. +*/ +#if defined(__GNUC__) && __GNUC__>=11 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wstringop-overread" +#endif /* ** Set the collating sequence name for a column. @@ -127457,6 +127713,11 @@ SQLITE_PRIVATE void sqlite3ColumnSetColl( } } +/* Undo the false-positive warning suppression above. */ +#if defined(__GNUC__) && __GNUC__>=11 +# pragma GCC diagnostic pop +#endif + /* ** Return the collating sequence name for a column */ @@ -128479,6 +128740,13 @@ SQLITE_PRIVATE void sqlite3AddDefaultValue( pDfltExpr = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE); sqlite3DbFree(db, x.u.zToken); sqlite3ColumnSetExpr(pParse, p, pCol, pDfltExpr); +#ifndef SQLITE_OMIT_AUTHORIZATION + /* Reject unauthorized functions from DEFAULT clauses */ + if( db->init.busy==0 && db->xAuth!=0 ){ + sqlite3FuncAuth(pParse, pExpr); + } +#endif /* SQLITE_OMIT_AUTHORIZER */ + } } if( IN_RENAME_OBJECT ){ @@ -128934,6 +129202,23 @@ static int resizeIndexObject(Parse *pParse, Index *pIdx, int N){ return SQLITE_OK; } +/* +** Return true if the index pIdx can support a Bloom filter on its +** first N columns. Specifically, return true if all of the first N +** columns have the BINARY collating sequence or no collating sequence +** at all, and return false if there are any non-BINARY collating +** seqeuences on any of the first N columns. tag-202607231411 +*/ +SQLITE_PRIVATE int sqlite3IndexBloomable(const Index *pIdx, int N){ + int i; + assert( pIdx!=0 ); + assert( N <= pIdx->nColumn ); + for(i=0; iazColl[i],"BINARY")!=0 ) return 0; + } + return 1; +} + /* ** Estimate the total row width for a table. */ @@ -129285,14 +129570,11 @@ SQLITE_PRIVATE void sqlite3MarkAllShadowTablesOf(sqlite3 *db, Table *pTab){ /* ** Return true if zName is a shadow table name in the current database ** connection. -** -** zName is temporarily modified while this routine is running, but is -** restored to its original value prior to this routine returning. */ SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName){ const char *zTail; /* Pointer to the last "_" in zName */ Table *pTab; /* Table that zName is a shadow of */ - char *zCopy; + char *zCopy; /* Transient copy of zName after last "_" */ zTail = strrchr(zName, '_'); if( zTail==0 ) return 0; zCopy = sqlite3DbStrNDup(db, zName, (int)(zTail-zName)); @@ -129331,7 +129613,6 @@ static void markExprListImmutable(ExprList *pList){ #define markExprListImmutable(X) /* no-op */ #endif /* SQLITE_DEBUG */ - /* ** This routine is called to report the final ")" that terminates ** a CREATE TABLE statement. @@ -130804,8 +131085,9 @@ SQLITE_PRIVATE void sqlite3CreateIndex( if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){ if( !ifNotExist ){ sqlite3ErrorMsg(pParse, "index %s already exists", zName); + }else if( db->init.busy ){ + sqlite3ErrorMsg(pParse,""); /* corruptSchema() will do the error */ }else{ - assert( !db->init.busy ); sqlite3CodeVerifySchema(pParse, iDb); sqlite3ForceNotReadOnly(pParse); } @@ -133997,6 +134279,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete( v = pParse->pVdbe; pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ + int p3 = 0; assert( iIdxCur+i!=iDataCur || pPk==pIdx ); if( aRegIdx!=0 && aRegIdx[i]==0 ) continue; if( pIdx==pPk ) continue; @@ -134004,10 +134287,12 @@ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete( VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName)); r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1, &iPartIdxLabel, pPrior, r1); - sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1, - pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn - ); + if( pIdx->bHasExpr && aRegIdx ){ + p3 = aRegIdx[i]; + } + sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1, p3); sqlite3VdbeChangeP4(v, -1, (const char*)pIdx, P4_INDEX); + sqlite3VdbeChangeP5(v, pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn); sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); pPrior = pIdx; } @@ -134246,13 +134531,17 @@ static void lengthFunc( case SQLITE_TEXT: { const unsigned char *z = sqlite3_value_text(argv[0]); const unsigned char *z0; - unsigned char c; if( z==0 ) return; z0 = z; - while( (c = *z)!=0 ){ - z++; - if( c>=0xc0 ){ - while( (*z & 0xc0)==0x80 ){ z++; z0++; } + while( 1 /*exit-by-break*/ ){ + /* vvvvvv---- See tag-20260418-01 */ + if( (u8)(z[0]-1)<(0x80-1) ){ + z++; + }else if( z[0]==0 ){ + break; + }else{ + z++; + while( (z[0]&0xc0)==0x80 ){ z++; z0++; } } } sqlite3_result_int(context, (int)(z-z0)); @@ -134432,7 +134721,6 @@ static void printfFunc( PrintfArguments x; StrAccum str; const char *zFormat; - int n; sqlite3 *db = sqlite3_context_db_handle(context); if( argc>=1 && (zFormat = (const char*)sqlite3_value_text(argv[0]))!=0 ){ @@ -134442,18 +134730,7 @@ static void printfFunc( sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); str.printfFlags = SQLITE_PRINTF_SQLFUNC; sqlite3_str_appendf(&str, zFormat, &x); - if( str.accError==SQLITE_OK ){ - n = str.nChar; - sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n, - SQLITE_DYNAMIC); - }else{ - if( str.accError==SQLITE_NOMEM ){ - sqlite3_result_error_nomem(context); - }else{ - sqlite3_result_error_toobig(context); - } - sqlite3_str_reset(&str); - } + sqlite3_result_str(context, &str, SQLITE_XFER); } } @@ -134502,7 +134779,7 @@ static void substrFunc( p2 = sqlite3_value_int64(argv[2]); if( p2==0 && sqlite3_value_type(argv[2])==SQLITE_NULL ) return; }else{ - p2 = sqlite3_context_db_handle(context)->aLimit[SQLITE_LIMIT_LENGTH]; + p2 = LARGEST_INT64; } if( p1==0 ){ #ifdef SQLITE_SUBSTR_COMPATIBILITY @@ -134540,12 +134817,25 @@ static void substrFunc( } assert( p1>=0 && p2>=0 ); if( p0type!=SQLITE_BLOB ){ - while( *z && p1 ){ - SQLITE_SKIP_UTF8(z); - p1--; + for( ; p1>0; p1--){ + /* vvvvvv---- See tag-20260418-01 */ + if( (u8)(z[0]-1)<(0x80-1) ){ + z++; + }else if( z[0]==0 ){ + break; + }else{ + do{ z++; }while( (z[0]&0xc0)==0x80 ); + } } - for(z2=z; *z2 && p2; p2--){ - SQLITE_SKIP_UTF8(z2); + for(z2=z; p2>0; p2--){ + /* vvvvvv---- See tag-20260418-01 */ + if( (u8)(z2[0]-1)<(0x80-1) ){ + z2++; + }else if( z2[0]==0 ){ + break; + }else{ + do{ z2++; }while( (z2[0]&0xc0)==0x80 ); + } } sqlite3_result_text64(context, (char*)z, z2-z, SQLITE_TRANSIENT, SQLITE_UTF8); @@ -135387,12 +135677,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ UNUSED_PARAMETER(argc); sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); sqlite3QuoteValue(&str,argv[0],SQLITE_PTR_TO_INT(sqlite3_user_data(context))); - sqlite3_result_text(context, sqlite3StrAccumFinish(&str), str.nChar, - SQLITE_DYNAMIC); - if( str.accError!=SQLITE_OK ){ - sqlite3_result_null(context); - sqlite3_result_error_code(context, str.accError); - } + sqlite3_result_str(context, &str, SQLITE_XFER); } /* @@ -135612,7 +135897,7 @@ static void replaceFunc( int nRep; /* Size of zRep */ i64 nOut; /* Maximum size of zOut */ int loopLimit; /* Last zStr[] that might match zPattern[] */ - int i, j; /* Loop counters */ + i64 i, j; /* Loop counters */ unsigned cntExpand; /* Number zOut expansions */ sqlite3 *db = sqlite3_context_db_handle(context); @@ -135933,6 +136218,21 @@ static void soundexFunc( } #endif /* SQLITE_SOUNDEX */ +#if defined(SQLITE_DEBUG) || defined(SQLITE_BUILTIN_OOM_FUNCTION) +/* +** This SQL function just invokes sqlite3OomFault() and then returns +** NULL. Used for testing only. +*/ +static void oomFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + sqlite3 *db = sqlite3_context_db_handle(context); + sqlite3OomFault(db); +} +#endif /* SQLITE_DEBUG || SQLITE_BUILTIN_OOM_FUNCTION */ + #ifndef SQLITE_OMIT_LOAD_EXTENSION /* ** A function that loads a shared-library extension then returns NULL. @@ -136425,7 +136725,7 @@ static void groupConcatFinalize(sqlite3_context *context){ GroupConcatCtx *pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0); if( pGCC ){ - sqlite3ResultStrAccum(context, &pGCC->str); + sqlite3_result_str(context, &pGCC->str, SQLITE_XFER); #ifndef SQLITE_OMIT_WINDOWFUNC sqlite3_free(pGCC->pnSepLengths); #endif @@ -136435,18 +136735,8 @@ static void groupConcatFinalize(sqlite3_context *context){ static void groupConcatValue(sqlite3_context *context){ GroupConcatCtx *pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0); - if( pGCC ){ - StrAccum *pAccum = &pGCC->str; - if( pAccum->accError==SQLITE_TOOBIG ){ - 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); - } + if( pGCC && pGCC->nAccum>0 ){ + sqlite3_result_str(context, &pGCC->str, SQLITE_COPY); } } #else @@ -137066,14 +137356,28 @@ static void percentStep(sqlite3_context *pCtx, int argc, sqlite3_value **argv){ ** (1) To avoid a dependency on qsort() ** (2) To avoid the function call to the comparison routine for each ** comparison. +** +** If parameter iReq is non-negative, then the caller will only access +** elements a[iReq] and a[iReq+1] (if it exists) of the sorted array and +** so it is not necessary to position any other elements. Or if iReq is +** negative, then the final array must be fully sorted. */ -static void percentSort(double *a, unsigned int n){ - int iLt; /* Entries before a[iLt] are less than rPivot */ - int iGt; /* Entries at or after a[iGt] are greater than rPivot */ +static void percentSort( + double *a, /* Array to sort */ + unsigned int n, /* Number of elements in array a[] */ + int iReq /* Element caller cares about (or -ve) */ +){ + int iLt; /* Entries before a[iLt] are less than or equal to rPivot */ + int iGt; /* Entries a[iGt] and after are greater or equal to rPivot */ int i; /* Loop counter */ double rPivot; /* The pivot value */ - while( n>=2 ){ + assert( n>=2 ); + do{ + /* Put the first, middle, and last elements in sorted order. + ** After doing so, return immediately if the array contains + ** three or fewer elements as there is nothing more to do. + */ if( a[0]>a[n-1] ){ SWAP_DOUBLE(a[0],a[n-1]) } @@ -137086,6 +137390,11 @@ static void percentSort(double *a, unsigned int n){ SWAP_DOUBLE(a[i],a[iGt]) } if( n==3 ) return; + + /* Take the value of the middle element as the pivot. Shuffle + ** values around so that all elements less than the pivot come + ** before all elements greater than the pivot. + */ rPivot = a[i]; iLt = i = 1; do{ @@ -137102,15 +137411,48 @@ static void percentSort(double *a, unsigned int n){ i++; } }while( i(int)(n/2) ){ - if( n-iGt>=2 ) percentSort(a+iGt, n-iGt); - n = iLt; + + assert( iLt>0 && iLtiLt+1 ); + assert( a[iLt]==rPivot ); + assert( a[iLt-1]<=rPivot ); + assert( a[iGt]>=rPivot ); + assert( a[iLt+1]>=rPivot ); + + if( iReq>=0 ){ + /* In this case, the only elements that the caller requires sorted into + ** the correct positions are elements a[iReq] and a[iReq+1]. At this + ** point we know that element a[iLt] is in the correct position and + ** all elements smaller than a[iLt] are in the left-hand partition. + ** So if (iReq=iLt), then elements iReq and iReq+1 are either in the + ** right partition or the equal partition (elements for which + ** iLt<=iElem=2 ) percentSort(a, iLt); - a += iGt; - n -= iGt; + /* Recurse on the smaller partition only. The smaller partition + ** will hold n/2 or fewer entries, which assures that the stack + ** depth will not exceed O(log(n)), even for pathological cases. + ** Loop without recursion for the larger partition. */ + if( iLt>(int)(n/2) ){ + if( n-iGt>=2 ) percentSort(a+iGt, n-iGt, -1); + n = iLt; + }else{ + if( iLt>=2 ) percentSort(a, iLt, -1); + a += iGt; + n -= iGt; + } } - } + }while( n>=2 ); } /* @@ -137145,7 +137487,7 @@ static void percentInverse(sqlite3_context *pCtx,int argc,sqlite3_value **argv){ } if( p->bSorted==0 ){ assert( p->nUsed>1 ); - percentSort(p->a, p->nUsed); + percentSort(p->a, p->nUsed, -1); p->bSorted = 1; } p->bKeepSorted = 1; @@ -137174,13 +137516,17 @@ static void percentCompute(sqlite3_context *pCtx, int bIsFinal){ if( p==0 ) return; if( p->a==0 ) return; if( p->nUsed ){ + ix = p->rPct*(p->nUsed-1); + i1 = (unsigned)ix; if( p->bSorted==0 ){ + /* In cases where bIsFinal is non-zero, setting Percentile.bSorted + ** after the percentSort() call here is not technically correct, as + ** the array is not fully sorted. But in this case the object will be + ** freed below anyway, so it doesn't matter. */ assert( p->nUsed>1 ); - percentSort(p->a, p->nUsed); + percentSort(p->a, p->nUsed, (bIsFinal ? (int)i1 : -1)); p->bSorted = 1; } - ix = p->rPct*(p->nUsed-1); - i1 = (unsigned)ix; if( settings & 1 ){ vx = p->a[i1]; }else{ @@ -137235,7 +137581,7 @@ static void filestatFunc( assert( pPager!=0 ); fd = sqlite3PagerFile(pPager); pStr = sqlite3_str_new(db); - if( pStr==0 ){ + if( sqlite3_str_errcode(pStr) ){ sqlite3_result_error_nomem(context); }else{ sqlite3_str_append(pStr, "{\"db\":", 6); @@ -137248,8 +137594,7 @@ static void filestatFunc( if( rc ) sqlite3_str_append(pStr, "null", 4); } sqlite3_str_append(pStr, "}", 1); - sqlite3_result_text(context, sqlite3_str_finish(pStr), -1, - sqlite3_free); + sqlite3_result_str(context, pStr, SQLITE_FINISH); } sqlite3BtreeLeave(pBtree); }else{ @@ -137258,6 +137603,48 @@ static void filestatFunc( } #endif /* SQLITE_DEBUG || SQLITE_ENABLE_FILESTAT */ +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_WALSTAT) +/* +** Implementation of sqlite_walstat(SCHEMA). +** +** Return JSON text that describes the current state of a WAL file. +** This function is for debugging and analysis only. It is not part +** of production builds. This function is not part of the SQLite API +** and is likely to change or be removed in future versions of SQLite. +*/ +static void walstatFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + sqlite3 *db = sqlite3_context_db_handle(context); + const char *zDbName; + sqlite3_str *pStr; + Btree *pBtree; + + zDbName = (const char*)sqlite3_value_text(argv[0]); + pBtree = sqlite3DbNameToBtree(db, zDbName); + if( pBtree ){ + Pager *pPager; + sqlite3BtreeEnter(pBtree); + pPager = sqlite3BtreePager(pBtree); + assert( pPager!=0 ); + pStr = sqlite3_str_new(db); + if( sqlite3_str_errcode(pStr) ){ + sqlite3_result_error_nomem(context); + }else{ + sqlite3_str_append(pStr, "{", 1); + sqlite3PagerWalStat(pPager, pStr); + sqlite3_str_append(pStr, "}", 1); + sqlite3_result_str(context, pStr, SQLITE_FINISH); + } + sqlite3BtreeLeave(pBtree); + }else{ + sqlite3_result_text(context, "{}", 2, SQLITE_STATIC); + } +} +#endif /* SQLITE_DEBUG || SQLITE_ENABLE_WALSTAT */ + #ifdef SQLITE_DEBUG /* ** Implementation of fpdecode(x,y,z) function. @@ -137338,7 +137725,7 @@ static void parseuriFunc( flgs = (unsigned int)sqlite3_value_int(argv[1]); rc = sqlite3ParseUri(zVfs, zUri, &flgs, &pVfs, &zFile, &zErr); pResult = sqlite3_str_new(0); - if( pResult ){ + if( !sqlite3_str_errcode(pResult) ){ int i; sqlite3_str_appendf(pResult, "rc=%d", rc); sqlite3_str_appendf(pResult, ", flags=0x%x", flgs); @@ -137365,8 +137752,8 @@ static void parseuriFunc( } } } - sqlite3_result_text(ctx, sqlite3_str_finish(pResult), -1, sqlite3_free); } + sqlite3_result_str(ctx, pResult, SQLITE_FINISH); sqlite3_free_filename(zFile); sqlite3_free(zErr); } @@ -137418,6 +137805,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ #endif #if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILESTAT) FUNCTION(sqlite_filestat, 1, 0, 0, filestatFunc ), + FUNCTION(sqlite_walstat, 1, 0, 0, walstatFunc ), #endif FUNCTION(ltrim, 1, 1, 0, trimFunc ), FUNCTION(ltrim, 2, 1, 0, trimFunc ), @@ -137446,6 +137834,9 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ FUNCTION(fpdecode, 3, 0, 0, fpdecodeFunc ), FUNCTION(parseuri, -1, 0, 0, parseuriFunc ), #endif +#if defined(SQLITE_DEBUG) || defined(SQLITE_BUILTIN_OOM_FUNCTION) + FUNCTION(oom, -1, 0, 0, oomFunc ), +#endif #ifndef SQLITE_OMIT_FLOATING_POINT FUNCTION(round, 1, 0, 0, roundFunc ), FUNCTION(round, 2, 0, 0, roundFunc ), @@ -137463,7 +137854,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ FUNCTION(nullif, 2, 0, 1, nullifFunc ), DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ), DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), - FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ), + SFUNCTION(sqlite_log, 2, 0, 0, errlogFunc ), FUNCTION(unistr, 1, 0, 0, unistrFunc ), FUNCTION(quote, 1, 0, 0, quoteFunc ), FUNCTION(unistr_quote, 1, 1, 0, quoteFunc ), @@ -138894,7 +139285,7 @@ static Trigger *fkActionTrigger( testcase( pCol->colFlags & COLFLAG_STORED ); pDflt = 0; }else{ - pDflt = sqlite3ColumnExpr(pFKey->pFrom, pCol); + pDflt = sqlite3ColumnExprAuth(pFKey->pFrom, pCol, pParse); } if( pDflt ){ pNew = sqlite3ExprDup(db, pDflt, 0); @@ -139512,6 +139903,9 @@ static int autoIncBegin( return 0; } + if( pToplevel->usesAinc==0 ){ + pToplevel->pAinc = 0; + } pInfo = pToplevel->pAinc; while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; } if( pInfo==0 ){ @@ -139521,6 +139915,7 @@ static int autoIncBegin( if( pParse->db->mallocFailed ) return 0; pInfo->pNext = pToplevel->pAinc; pToplevel->pAinc = pInfo; + pToplevel->usesAinc = 1; pInfo->pTab = pTab; pInfo->iDb = iDb; pToplevel->nMem++; /* Register to hold name of table */ @@ -139549,6 +139944,7 @@ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){ assert( sqlite3IsToplevel(pParse) ); assert( v ); /* We failed long ago if this is not so */ + assert( pParse->usesAinc ); for(p = pParse->pAinc; p; p = p->pNext){ static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList autoInc[] = { @@ -139616,6 +140012,7 @@ static SQLITE_NOINLINE void autoIncrementEnd(Parse *pParse){ sqlite3 *db = pParse->db; assert( v ); + assert( pParse->usesAinc ); for(p = pParse->pAinc; p; p = p->pNext){ static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList autoIncEnd[] = { @@ -139648,7 +140045,7 @@ static SQLITE_NOINLINE void autoIncrementEnd(Parse *pParse){ } } SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){ - if( pParse->pAinc ) autoIncrementEnd(pParse); + if( pParse->usesAinc ) autoIncrementEnd(pParse); } #else /* @@ -139675,25 +140072,13 @@ SQLITE_PRIVATE void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){ } } -/* -** 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; + if( sqlite3ExprListIsConstant(pParse, pRow, 0)==0 ) return 0; for(ii=0; iinExpr; ii++){ Expr *pExpr = pRow->a[ii].pExpr; assert( pExpr->op!=TK_RAISE ); @@ -139759,7 +140144,7 @@ SQLITE_PRIVATE Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList if( pParse->bHasWith /* condition (a) above */ || pParse->db->init.busy /* condition (b) above */ - || exprListIsConstant(pParse,pRow)==0 /* condition (c) above */ + || sqlite3ExprListIsConstant(pParse, pRow, 1)==0 /* condition (c) above */ || (pLeft->pSrc->nSrc==0 && exprListIsNoAffinity(pParse,pLeft->pEList)==0) /* condition (d) above */ || IN_SPECIAL_PARSE @@ -140472,7 +140857,7 @@ SQLITE_PRIVATE void sqlite3Insert( /* Hidden columns that are not explicitly named in the INSERT ** get their default value */ sqlite3ExprCodeFactorable(pParse, - sqlite3ColumnExpr(pTab, &pTab->aCol[i]), + sqlite3ColumnExprAuth(pTab, &pTab->aCol[i], pParse), iRegStore); continue; } @@ -140484,7 +140869,7 @@ SQLITE_PRIVATE void sqlite3Insert( /* A column not named in the insert column list gets its ** default value */ sqlite3ExprCodeFactorable(pParse, - sqlite3ColumnExpr(pTab, &pTab->aCol[i]), + sqlite3ColumnExprAuth(pTab, &pTab->aCol[i], pParse), iRegStore); continue; } @@ -140492,7 +140877,7 @@ SQLITE_PRIVATE void sqlite3Insert( }else if( nColumn==0 ){ /* This is INSERT INTO ... DEFAULT VALUES. Load the default value. */ sqlite3ExprCodeFactorable(pParse, - sqlite3ColumnExpr(pTab, &pTab->aCol[i]), + sqlite3ColumnExprAuth(pTab, &pTab->aCol[i], pParse), iRegStore); continue; }else{ @@ -140543,6 +140928,7 @@ SQLITE_PRIVATE void sqlite3Insert( sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v); + sqlite3MayAbort(pParse); } /* Copy the new data already generated. */ @@ -140611,6 +140997,7 @@ SQLITE_PRIVATE void sqlite3Insert( sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, addr1+2); VdbeCoverage(v); } sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid); VdbeCoverage(v); + sqlite3MayAbort(pParse); } }else if( IsVirtual(pTab) || withoutRowid ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid); @@ -141090,7 +141477,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( assert( (pCol->colFlags & COLFLAG_GENERATED)==0 ); nSeenReplace++; sqlite3ExprCodeCopy(pParse, - sqlite3ColumnExpr(pTab, pCol), iReg); + sqlite3ColumnExprAuth(pTab, pCol, pParse), iReg); sqlite3VdbeJumpHere(v, addr1); break; } @@ -141303,6 +141690,22 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( pTrigger = 0; regTrigCnt = sqlite3FkRequired(pParse, pTab, 0, 0); } + if( regTrigCnt ){ + /* At this point regTrigCnt is non-zero if there are DELETE triggers + ** or FK triggers. But we only care about these things if there is + ** a chance that a row will be deleted by an ON CONFLICT REPLACE + ** constraint. So zero regTrigCnt if no such constraint can be found. */ + if( overrideError!=OE_Replace ){ + if( overrideError!=OE_Default ){ + regTrigCnt = 0; + }else if( pkChng==0 || pPk || pTab->keyConf!=OE_Replace ){ + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( pIdx->onError==OE_Replace ) break; + } + if( pIdx==0 ) regTrigCnt = 0; + } + } + } if( regTrigCnt ){ /* Replace triggers might exist. Allocate the counter and ** initialize it to zero. */ @@ -141354,9 +141757,13 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( if( onError==OE_Replace /* IPK rule is REPLACE */ && onError!=overrideError /* Rules for other constraints are different */ && pTab->pIndex /* There exist other constraints */ - && !upsertIpkDelay /* IPK check already deferred by UPSERT */ ){ - ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1; + if( upsertIpkDelay ){ + ipkTop = upsertIpkDelay + 1; + upsertIpkDelay = 0; + }else{ + ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1; + } VdbeComment((v, "defer IPK REPLACE until last")); } @@ -141450,11 +141857,11 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( } } sqlite3VdbeResolveLabel(v, addrRowidOk); - if( pUpsert && pUpsertClause!=pUpsert ){ - upsertIpkReturn = sqlite3VdbeAddOp0(v, OP_Goto); - }else if( ipkTop ){ + if( ipkTop ){ ipkBottom = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeJumpHere(v, ipkTop-1); + }else if( pUpsert && pUpsertClause!=pUpsert ){ + upsertIpkReturn = sqlite3VdbeAddOp0(v, OP_Goto); } } @@ -141474,6 +141881,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( int iThisCur; /* Cursor for this UNIQUE index */ int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */ int addrConflictCk; /* First opcode in the conflict check logic */ + int nConflictCk; /* Number of opcodes in conflict check logic */ if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */ if( pUpsert ){ @@ -141650,6 +142058,11 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( } } + nConflictCk = sqlite3VdbeCurrentAddr(v) - addrConflictCk; + assert( nConflictCk>0 || db->mallocFailed ); + testcase( nConflictCk<=0 ); + testcase( nConflictCk>1 ); + /* Generate code that executes if the new index entry is not unique */ assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail || onError==OE_Ignore || onError==OE_Replace || onError==OE_Update ); @@ -141675,13 +142088,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( break; } default: { - int nConflictCk; /* Number of opcodes in conflict check logic */ - assert( onError==OE_Replace ); - nConflictCk = sqlite3VdbeCurrentAddr(v) - addrConflictCk; - assert( nConflictCk>0 || db->mallocFailed ); - testcase( nConflictCk<=0 ); - testcase( nConflictCk>1 ); if( regTrigCnt ){ sqlite3MultiWrite(pParse); nReplaceTrig++; @@ -141695,57 +142102,57 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( if( pTrigger && isUpdate ){ sqlite3VdbeAddOp1(v, OP_CursorUnlock, iDataCur); } - if( regTrigCnt ){ - int addrBypass; /* Jump destination to bypass recheck logic */ + seenReplace = 1; + break; + } + } + if( regTrigCnt ){ + int addrBypass; /* Jump destination to bypass recheck logic */ - sqlite3VdbeAddOp2(v, OP_AddImm, regTrigCnt, 1); /* incr trigger cnt */ - addrBypass = sqlite3VdbeAddOp0(v, OP_Goto); /* Bypass recheck */ - VdbeComment((v, "bypass recheck")); - - /* Here we insert code that will be invoked after all constraint - ** checks have run, if and only if one or more replace triggers - ** fired. */ - sqlite3VdbeResolveLabel(v, lblRecheckOk); - lblRecheckOk = sqlite3VdbeMakeLabel(pParse); - if( pIdx->pPartIdxWhere ){ - /* Bypass the recheck if this partial index is not defined - ** for the current row */ - sqlite3VdbeAddOp2(v, OP_IsNull, regIdx-1, lblRecheckOk); - VdbeCoverage(v); - } - /* Copy the constraint check code from above, except change - ** the constraint-ok jump destination to be the address of - ** the next retest block */ - while( nConflictCk>0 ){ - VdbeOp x; /* Conflict check opcode to copy */ - /* The sqlite3VdbeAddOp4() call might reallocate the opcode array. - ** Hence, make a complete copy of the opcode, rather than using - ** a pointer to the opcode. */ - x = *sqlite3VdbeGetOp(v, addrConflictCk); - if( x.opcode!=OP_IdxRowid ){ - int p2; /* New P2 value for copied conflict check opcode */ - const char *zP4; - if( sqlite3OpcodeProperty[x.opcode]&OPFLG_JUMP ){ - p2 = lblRecheckOk; - }else{ - p2 = x.p2; - } - zP4 = x.p4type==P4_INT32 ? SQLITE_INT_TO_PTR(x.p4.i) : x.p4.z; - sqlite3VdbeAddOp4(v, x.opcode, x.p1, p2, x.p3, zP4, x.p4type); - sqlite3VdbeChangeP5(v, x.p5); - VdbeCoverageIf(v, p2!=x.p2); - } - nConflictCk--; - addrConflictCk++; - } - /* If the retest fails, issue an abort */ - sqlite3UniqueConstraint(pParse, OE_Abort, pIdx); + sqlite3VdbeAddOp2(v, OP_AddImm, regTrigCnt, 1); /* incr trigger cnt */ + addrBypass = sqlite3VdbeAddOp0(v, OP_Goto); /* Bypass recheck */ + VdbeComment((v, "bypass recheck")); - sqlite3VdbeJumpHere(v, addrBypass); /* Terminate the recheck bypass */ + /* Here we insert code that will be invoked after all constraint + ** checks have run, if and only if one or more replace triggers + ** fired. */ + sqlite3VdbeResolveLabel(v, lblRecheckOk); + lblRecheckOk = sqlite3VdbeMakeLabel(pParse); + if( pIdx->pPartIdxWhere ){ + /* Bypass the recheck if this partial index is not defined + ** for the current row */ + sqlite3VdbeAddOp2(v, OP_IsNull, regIdx-1, lblRecheckOk); + VdbeCoverage(v); + } + /* Copy the constraint check code from above, except change + ** the constraint-ok jump destination to be the address of + ** the next retest block */ + while( nConflictCk>0 ){ + VdbeOp x; /* Conflict check opcode to copy */ + /* The sqlite3VdbeAddOp4() call might reallocate the opcode array. + ** Hence, make a complete copy of the opcode, rather than using + ** a pointer to the opcode. */ + x = *sqlite3VdbeGetOp(v, addrConflictCk); + if( x.opcode!=OP_IdxRowid || isUpdate ){ + int p2; /* New P2 value for copied conflict check opcode */ + const char *zP4; + if( sqlite3OpcodeProperty[x.opcode]&OPFLG_JUMP ){ + p2 = lblRecheckOk; + }else{ + p2 = x.p2; + } + zP4 = x.p4type==P4_INT32 ? SQLITE_INT_TO_PTR(x.p4.i) : x.p4.z; + sqlite3VdbeAddOp4(v, x.opcode, x.p1, p2, x.p3, zP4, x.p4type); + sqlite3VdbeChangeP5(v, x.p5); + VdbeCoverageIf(v, p2!=x.p2); } - seenReplace = 1; - break; + nConflictCk--; + addrConflictCk++; } + /* If the retest fails, issue an abort */ + sqlite3UniqueConstraint(pParse, OE_Abort, pIdx); + + sqlite3VdbeJumpHere(v, addrBypass); /* Terminate the recheck bypass */ } sqlite3VdbeResolveLabel(v, addrUniqueOk); if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField); @@ -141784,8 +142191,8 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( }else{ sqlite3VdbeGoto(v, addrRecheck); } - sqlite3VdbeResolveLabel(v, lblRecheckOk); } + if( regTrigCnt ) sqlite3VdbeResolveLabel(v, lblRecheckOk); /* Generate the table record */ if( HasRowid(pTab) ){ @@ -141888,7 +142295,10 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( || pIdx->pNext==0 || pIdx->pNext->onError==OE_Replace ); if( aRegIdx[i]==0 ) continue; - if( pIdx->pPartIdxWhere ){ + if( pIdx->pPartIdxWhere || (update_flags && pIdx->bHasExpr) ){ + /* If this is a partial index, or an UPDATE of an index on an + ** expression, then the record register may be set to NULL to indicate + ** that no record should be inserted into this index. */ sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); } @@ -142063,6 +142473,44 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ return 1; } +/* +** Examine an expression node and abort if it references the ROWID. +** This is a Walker callback used by xferCompatibleCheck() +*/ +static int xferCheckRowid(Walker *pWalk, Expr *pExpr){ + if( pExpr->op==TK_COLUMN && pExpr->iColumn<0 ){ + pWalk->eCode = 1; + return WRC_Abort; + }else{ + return WRC_Continue; + } +} + +/* +** Analyze CHECK constraints on the source and destination tables and +** return true if those CHECK constraints are compatible with the +** xfer-optimization. +** +** * The pDest and pSrc tables must have identical CHECK constraints. +** +** * If the destination table, pDest, does not have an +** INTEGER PRIMARY KEY column, then no CHECK constraint may +** referenced the ROWID. (See forum post 2026-05-11T13:15:57Z) +*/ +static int xferCompatibleCheck(Table *pDest, Table *pSrc){ + if( sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){ + return 0; + } + if( pDest->iPKey<0 ){ + Walker w; + memset(&w, 0, sizeof(w)); + w.xExprCallback = xferCheckRowid; + sqlite3WalkExprList(&w,pDest->pCheck); + if( w.eCode ) return 0; + } + return 1; +} + /* ** Attempt the transfer optimization on INSERTs of the form ** @@ -142189,8 +142637,19 @@ static int xferOptimization( if( pDest->iPKey!=pSrc->iPKey ){ return 0; /* Both tables must have the same INTEGER PRIMARY KEY */ } - if( (pDest->tabFlags & TF_Strict)!=0 && (pSrc->tabFlags & TF_Strict)==0 ){ - return 0; /* Cannot feed from a non-strict into a strict table */ + if( (pDest->tabFlags & TF_Strict)!=0 ){ + if( (pSrc->tabFlags & TF_Strict)==0 ){ + return 0; /* Cannot feed from a non-strict into a strict table */ + } + for(i=0; inCol; i++){ + unsigned eDestType = pDest->aCol[i].eCType; + unsigned eSrcType = pSrc->aCol[i].eCType; + if( eDestType==COLTYPE_ANY ) continue; + if( eDestType==eSrcType ) continue; + if( eDestType==COLTYPE_INT && eSrcType==COLTYPE_INTEGER ) continue; + if( eDestType==COLTYPE_INTEGER && eSrcType==COLTYPE_INT ) continue; + return 0; /* Incompatible types in source and destination */ + } } for(i=0; inCol; i++){ Column *pDestCol = &pDest->aCol[i]; @@ -142284,7 +142743,7 @@ static int xferOptimization( #ifndef SQLITE_OMIT_CHECK if( pDest->pCheck && (db->mDbFlags & DBFLAG_Vacuum)==0 - && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) + && !xferCompatibleCheck(pDest,pSrc) ){ return 0; /* Tables have different CHECK constraints. Ticket #2252 */ } @@ -142305,6 +142764,18 @@ static int xferOptimization( if( (db->flags & SQLITE_CountRows)!=0 ){ return 0; /* xfer opt does not play well with PRAGMA count_changes */ } +#ifndef SQLITE_OMIT_AUTHORIZATION + if( db->xAuth ){ + int iDb = sqlite3SchemaToIndex(db, pSrc->pSchema); + if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 0; + for(i=0; inCol; i++){ + Column *pSrcCol = &pSrc->aCol[i]; + if( sqlite3AuthReadCol(pParse, pSrc->zName, pSrcCol->zCnName, iDb) ){ + return 0; + } + } + } +#endif /* If we get this far, it means that the xfer optimization is at ** least a possibility, though it might only work if the destination @@ -142748,7 +143219,7 @@ struct sqlite3_api_routines { const char * (*libversion)(void); int (*libversion_number)(void); void *(*malloc)(int); - char * (*mprintf)(const char*,...); + char *(SQLITE_CDECL*mprintf)(const char*,...); int (*open)(const char*,sqlite3**); int (*open16)(const void*,sqlite3**); int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); @@ -142769,11 +143240,11 @@ struct sqlite3_api_routines { void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*)); void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*)); void (*result_value)(sqlite3_context*,sqlite3_value*); - void * (*rollback_hook)(sqlite3*,void(*)(void*),void*); + void *(*rollback_hook)(sqlite3*,void(*)(void*),void*); int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, const char*,const char*),void*); void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); - char * (*xsnprintf)(int,char*,const char*,...); + char *(SQLITE_CDECL*xsnprintf)(int,char*,const char*,...); int (*step)(sqlite3_stmt*); int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, char const**,char const**,int*,int*,int*); @@ -142837,7 +143308,7 @@ struct sqlite3_api_routines { int (*xthreadsafe)(void); void (*result_zeroblob)(sqlite3_context*,int); void (*result_error_code)(sqlite3_context*,int); - int (*test_control)(int, ...); + int (SQLITE_CDECL*test_control)(int, ...); void (*randomness)(int,void*); sqlite3 *(*context_db_handle)(sqlite3_context*); int (*extended_result_codes)(sqlite3*,int); @@ -142857,11 +143328,11 @@ struct sqlite3_api_routines { void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*), void(*xDestroy)(void*)); - int (*db_config)(sqlite3*,int,...); + int (SQLITE_CDECL*db_config)(sqlite3*,int,...); sqlite3_mutex *(*db_mutex)(sqlite3*); int (*db_status)(sqlite3*,int,int*,int*,int); int (*extended_errcode)(sqlite3*); - void (*log)(int,const char*,...); + void (SQLITE_CDECL*log)(int,const char*,...); sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64); const char *(*sourceid)(void); int (*stmt_status)(sqlite3_stmt*,int,int); @@ -142871,7 +143342,7 @@ struct sqlite3_api_routines { int (*wal_checkpoint)(sqlite3*,const char*); void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); - int (*vtab_config)(sqlite3*,int op,...); + int (SQLITE_CDECL*vtab_config)(sqlite3*,int op,...); int (*vtab_on_conflict)(sqlite3*); /* Version 3.7.16 and later */ int (*close_v2)(sqlite3*); @@ -142940,7 +143411,7 @@ struct sqlite3_api_routines { int (*keyword_check)(const char*,int); sqlite3_str *(*str_new)(sqlite3*); char *(*str_finish)(sqlite3_str*); - void (*str_appendf)(sqlite3_str*, const char *zFormat, ...); + void (SQLITE_CDECL*str_appendf)(sqlite3_str*, const char *zFormat, ...); void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list); void (*str_append)(sqlite3_str*, const char *zIn, int N); void (*str_appendall)(sqlite3_str*, const char *zIn); @@ -143015,6 +143486,9 @@ struct sqlite3_api_routines { void (*str_free)(sqlite3_str*); int (*carray_bind)(sqlite3_stmt*,int,void*,int,int,void(*)(void*)); int (*carray_bind_v2)(sqlite3_stmt*,int,void*,int,int,void(*)(void*),void*); + /* Version 3.54.0 and later */ + sqlite3_int64 (*incomplete)(const char*); + void (*result_str)(sqlite3_context*,sqlite3_str*,int); }; /* @@ -143358,6 +143832,9 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_str_free sqlite3_api->str_free #define sqlite3_carray_bind sqlite3_api->carray_bind #define sqlite3_carray_bind_v2 sqlite3_api->carray_bind_v2 +/* Version 3.54.0 and later */ +#define sqlite3_incomplete sqlite3_api->incomplete +#define sqlite3_result_str sqlite3_api->result_str #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) @@ -143890,11 +144367,14 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_str_free, #ifdef SQLITE_ENABLE_CARRAY sqlite3_carray_bind, - sqlite3_carray_bind_v2 + sqlite3_carray_bind_v2, #else 0, - 0 + 0, #endif + /* Version 3.54.0 and later */ + sqlite3_incomplete, + sqlite3_result_str }; /* True if x is the directory separator character @@ -144576,7 +145056,7 @@ static const PragmaName aPragmaName[] = { /* ColNames: */ 0, 0, /* iArg: */ SQLITE_CountRows }, #endif -#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && defined(_WIN32) {/* zName: */ "data_store_directory", /* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY, /* ePragFlg: */ PragFlg_NoColumns1, @@ -144999,7 +145479,7 @@ static const PragmaName aPragmaName[] = { /* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError }, #endif }; -/* Number of pragmas: 68 on by default, 78 total. */ +/* Number of pragmas: 67 on by default, 78 total. */ /************** End of pragma.h **********************************************/ /************** Continuing where we left off in pragma.c *********************/ @@ -145052,7 +145532,7 @@ static u8 getSafetyLevel(const char *z, int omitFull, u8 dflt){ /* on no off false yes true extra full */ int i, n; if( sqlite3Isdigit(*z) ){ - return (u8)sqlite3Atoi(z); + return sqlite3Atoi(z)!=0; } n = sqlite3Strlen30(z); for(i=0; isafety_level = iLevel; pDb->bSyncSet = 1; @@ -146725,10 +147211,9 @@ SQLITE_PRIVATE void sqlite3Pragma( for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); /* Current table */ Index *pIdx; /* An index on pTab */ - int nIdx; /* Number of indexes on pTab */ if( tableSkipIntegrityCheck(pTab,pObjTab) ) continue; if( HasRowid(pTab) ) cnt++; - for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; } + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ cnt++; } } if( cnt==0 ) continue; if( pObjTab ) cnt++; @@ -146908,8 +147393,8 @@ SQLITE_PRIVATE void sqlite3Pragma( }else{ if( pCol->iDflt ){ sqlite3_value *pDfltValue = 0; - sqlite3ValueFromExpr(db, sqlite3ColumnExpr(pTab,pCol), ENC(db), - pCol->affinity, &pDfltValue); + sqlite3ValueFromExpr(db, sqlite3ColumnExprAuth(pTab,pCol,pParse), + ENC(db), pCol->affinity, &pDfltValue); if( pDfltValue ){ p4 = sqlite3_value_type(pDfltValue); sqlite3ValueFree(pDfltValue); @@ -147623,9 +148108,10 @@ SQLITE_PRIVATE void sqlite3Pragma( ** disables the timeout. */ /*case PragTyp_BUSY_TIMEOUT*/ default: { + int n = 0; assert( pPragma->ePragTyp==PragTyp_BUSY_TIMEOUT ); - if( zRight ){ - sqlite3_busy_timeout(db, sqlite3Atoi(zRight)); + if( zRight && sqlite3GetInt32(zRight,&n) ){ + sqlite3_busy_timeout(db, n); } returnSingleInt(v, db->busyTimeout); break; @@ -148192,6 +148678,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char } assert( iDb>=0 && iDbnDb ); + assert( db->aDb[iDb].pSchema!=0 ); if( argv[3]==0 ){ corruptSchema(pData, argv, 0); }else if( argv[4] @@ -148210,6 +148697,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char int rc; u8 saved_iDb = db->init.iDb; sqlite3_stmt *pStmt; + const char *zEnd; TESTONLY(int rcp); /* Return code from sqlite3_prepare() */ assert( db->init.busy ); @@ -148224,7 +148712,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char db->init.orphanTrigger = 0; db->init.azInit = (const char**)argv; pStmt = 0; - TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0); + TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, &zEnd); rc = db->errCode; assert( (rc&0xFF)==(rcp&0xFF) ); db->init.iDb = saved_iDb; @@ -148240,6 +148728,8 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char corruptSchema(pData, argv, sqlite3_errmsg(db)); } } + }else if( zEnd[0] ){ + corruptSchema(pData, argv, 0); } db->init.azInit = sqlite3StdType; /* Any array of string ptrs will do */ sqlite3_finalize(pStmt); @@ -148267,6 +148757,16 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char } } } + if( pData->pzErrMsg[0]==0 ){ + Schema *pX = db->aDb[iDb].pSchema; + if( pX->tblHash.count + pX->idxHash.count + pX->trigHash.count + > (u32)db->aLimit[SQLITE_LIMIT_SCHEMA] + ){ + *pData->pzErrMsg = sqlite3MPrintf(db, "too many schema objects"); + pData->rc = SQLITE_ERROR; + return 1; + } + } return 0; } @@ -148298,7 +148798,13 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl assert( sqlite3_mutex_held(db->mutex) ); assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); - db->init.busy = 1; + db->init.busy = 1 + ((mFlags & INITFLAG_AlterAdd)!=0); + /* ^--- Any non-zero value for init.busy means that we are scanning + ** the sqlite_schema table to build the internal schema representation, + ** rather than running actual CREATE statements. init.busy==2 has the + ** additional meaning that the scan is happening as part of + ** ALTER TABLE ADD COLUMN, which is stricter in its enforcement of + ** function name resolution. */ /* Construct the in-memory representation schema tables (sqlite_schema or ** sqlite_temp_schema) by invoking the parser directly. The appropriate @@ -148657,7 +149163,7 @@ SQLITE_PRIVATE void sqlite3ParseObjectReset(Parse *pParse){ assert( db->pParse==pParse ); assert( pParse->nested==0 ); #ifndef SQLITE_OMIT_SHARED_CACHE - if( pParse->aTableLock ) sqlite3DbNNFreeNN(db, pParse->aTableLock); + if( pParse->nTableLock ) sqlite3DbNNFreeNN(db, pParse->aTableLock); #endif while( pParse->pCleanup ){ ParseCleanup *pCleanup = pParse->pCleanup; @@ -148741,6 +149247,7 @@ SQLITE_PRIVATE void *sqlite3ParserAddCleanup( ** is generated by Lemon. */ SQLITE_PRIVATE void sqlite3ParseObjectInit(Parse *pParse, sqlite3 *db){ + assert( db!=0 ); memset(PARSE_HDR(pParse), 0, PARSE_HDR_SZ); memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ); assert( db->pParse!=pParse ); @@ -149140,7 +149647,7 @@ SQLITE_API int sqlite3_prepare16( const void **pzTail /* OUT: End of parsed string */ ){ int rc; - rc = sqlite3Prepare16(db,zSql,nBytes,0,ppStmt,pzTail); + rc = sqlite3Prepare16(db,zSql,nBytes&~1,0,ppStmt,pzTail); assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ return rc; } @@ -149152,7 +149659,7 @@ SQLITE_API int sqlite3_prepare16_v2( const void **pzTail /* OUT: End of parsed string */ ){ int rc; - rc = sqlite3Prepare16(db,zSql,nBytes,SQLITE_PREPARE_SAVESQL,ppStmt,pzTail); + rc = sqlite3Prepare16(db,zSql,nBytes&~1,SQLITE_PREPARE_SAVESQL,ppStmt,pzTail); assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ return rc; } @@ -149165,7 +149672,7 @@ SQLITE_API int sqlite3_prepare16_v3( const void **pzTail /* OUT: End of parsed string */ ){ int rc; - rc = sqlite3Prepare16(db,zSql,nBytes, + rc = sqlite3Prepare16(db,zSql,nBytes&~1, SQLITE_PREPARE_SAVESQL|(prepFlags&SQLITE_PREPARE_MASK), ppStmt,pzTail); assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ @@ -149696,6 +150203,7 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){ int i, j; /* Loop counters */ SrcItem *pLeft; /* Left table being joined */ SrcItem *pRight; /* Right table being joined */ + int bSeenTFunc = 0; /* True if have seen table-valued function */ pSrc = p->pSrc; pLeft = &pSrc->a[0]; @@ -149838,7 +150346,18 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){ p->selFlags |= SF_OnToWhere; } - if( IsVirtual(pRightTab) && joinType==EP_OuterON && pRight->u1.pFuncArg ){ + if( bSeenTFunc==0 ){ + bSeenTFunc = (pLeft->fg.isTabFunc && pLeft->u1.pFuncArg); + } + + /* We also need to call sqlite3SelectCheckOnClauses() to verify that + ** table-valued function arguments do not illegally refer to any tables to + ** their right. This test is required if either (a) there is a RIGHT JOIN + ** in the SrcList, or (b) there is a LEFT JOIN to the right of a + ** table-valued function. */ + if( (pRight->fg.isTabFunc && joinType==EP_OuterON && pRight->u1.pFuncArg) + || (bSeenTFunc && joinType==EP_OuterON) + ){ p->selFlags |= SF_OnToWhere; } } @@ -150305,6 +150824,48 @@ static void selectExprDefer( } #endif +#ifdef SQLITE_DEBUG +/* +** This is a byte-code validation check that only runs when SQLITE_DEBUG +** is defined. This routine looks backwards through the bytecode +** for the definition of cursor with index iCur. It extracts the KeyInfo from +** that cursor (it must be an index cursor) and verifies that the cursor +** does not use any collating seqeuences other than BINARY for its first +** nCol columns. +** +** This routine is used inside of an assert(). So it should return true +** on success and false if the invariant is not satisfied. +** +** tag-202607231411 +*/ +static int sqlite3CursorBloomable(Parse *pParse, int iCur, int nCol){ + int i,k; + Vdbe *v = pParse->pVdbe; + if( pParse->nErr ) return 1; + assert( v ); + for(k=sqlite3VdbeCurrentAddr(v)-1; k>0; k--){ + const VdbeOp *pOp = sqlite3VdbeGetOp(v, k); + const KeyInfo *pKeyInfo; + if( pOp->p1!=iCur ) continue; + if( pOp->opcode!=OP_OpenRead + && pOp->opcode!=OP_OpenWrite + && pOp->opcode!=OP_OpenEphemeral + ){ + continue; + } + assert( pOp->p4type==P4_KEYINFO ); + pKeyInfo = (const KeyInfo*)pOp->p4.pKeyInfo; + assert( pKeyInfo!=0 ); + for(i=0; iaColl[i]) ); + } + return 1; + } + return 0; +} +#endif /* SQLITE_DEBUG */ + + /* ** This routine generates the code for the inside of the inner loop ** of a SELECT. @@ -150575,6 +151136,7 @@ static void selectInnerLoop( r1, pDest->zAffSdst, nResultCol); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol); if( pDest->iSDParm2 ){ + assert( sqlite3CursorBloomable(pParse,iParm,nResultCol) ); sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pDest->iSDParm2, 0, regResult, nResultCol); ExplainQueryPlan((pParse, 0, "CREATE BLOOM FILTER")); @@ -150904,6 +151466,9 @@ static void generateSortTail( Table *pTab = pSort->aDefer[i].pTab; int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); sqlite3OpenTable(pParse, pSort->aDefer[i].iCsr, iDb, pTab, OP_OpenRead); + sqlite3VdbeAddOp2(v, OP_Rewind, pSort->aDefer[i].iCsr, + sqlite3VdbeCurrentAddr(v)+1); + VdbeCoverage(v); nRefKey = MAX(nRefKey, pSort->aDefer[i].nKey); } #endif @@ -151610,6 +152175,20 @@ SQLITE_PRIVATE void sqlite3SubqueryColumnTypes( pTab->szTabRow = 1; /* Any non-zero value works */ } +/* +** Check the current subquery nesting depth. Return true and set an +** error if it has gone too deep. +*/ +static int checkSubqueryNestingDepth(Parse *pParse){ +#if SQLITE_MAX_EXPR_DEPTH>0 + if( pParse->nNestSel >= pParse->db->aLimit[SQLITE_LIMIT_EXPR_DEPTH] ){ + sqlite3ErrorMsg(pParse, "VIEWs and/or subqueries nested too deep"); + return 1; + } +#endif + return 0; +} + /* ** Given a SELECT statement, generate a Table structure that describes ** the result set of that SELECT. @@ -151620,12 +152199,7 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect, c u64 savedFlags; pParse->nNestSel++; -#if SQLITE_MAX_EXPR_DEPTH>0 - if( pParse->nNestSel >= db->aLimit[SQLITE_LIMIT_EXPR_DEPTH] ){ - sqlite3ErrorMsg(pParse, "VIEWs and/or subqueries nested too deep"); - return 0; - } -#endif + if( checkSubqueryNestingDepth(pParse) ) return 0; savedFlags = db->flags; db->flags &= ~(u64)SQLITE_FullColNames; db->flags |= SQLITE_ShortColNames; @@ -151660,9 +152234,7 @@ SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){ if( pParse->pVdbe ){ return pParse->pVdbe; } - if( pParse->pToplevel==0 - && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst) - ){ + if( pParse->pToplevel==0 ){ pParse->okConstFactor = 1; } return sqlite3VdbeCreate(pParse); @@ -151713,7 +152285,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ p->iLimit = iLimit = ++pParse->nMem; v = sqlite3GetVdbe(pParse); assert( v!=0 ); - if( sqlite3ExprIsInteger(pLimit->pLeft, &n, pParse) ){ + if( sqlite3ExprIsInteger(pLimit->pLeft, &n, pParse, 0) ){ sqlite3VdbeAddOp2(v, OP_Integer, n, iLimit); VdbeComment((v, "LIMIT counter")); if( n==0 ){ @@ -151726,6 +152298,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ sqlite3ExprCode(pParse, pLimit->pLeft, iLimit); sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeCoverage(v); VdbeComment((v, "LIMIT counter")); + sqlite3MayAbort(pParse); sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, iBreak); VdbeCoverage(v); } if( pLimit->pRight ){ @@ -151733,6 +152306,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ pParse->nMem++; /* Allocate an extra register for limit+offset */ sqlite3ExprCode(pParse, pLimit->pRight, iOffset); sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeCoverage(v); + sqlite3MayAbort(pParse); VdbeComment((v, "OFFSET counter")); sqlite3VdbeAddOp3(v, OP_OffsetLimit, iLimit, iOffset+1, iOffset); VdbeComment((v, "LIMIT+OFFSET")); @@ -152080,11 +152654,33 @@ static int hasAnchor(Select *p){ } /* -** This routine is called to process a compound query form from +** Return TRUE if p is a UNION with a LIMIT of exactly 1 and no OFFSET +** clause. This is a precondition for a couple of related optimizations. +** +** False negatives are harmless (apart from resulting in a slower query). +** False positives can result in incorrect answers, however. To provoke +** false negatives for testing purposes, disable the SQLITE_UnionLimit +** optimization. +*/ +static int unionWithLimitOne(sqlite3 *db, Select *p){ + int v; + if( p->op!=TK_UNION ) return 0; + if( p->pLimit==0 ) return 0; + if( p->pLimit->pRight ) return 0; /* No OFFSET */ + v = 0; + assert( p->pLimit->pLeft!=0 ); + if( sqlite3ExprIsInteger(p->pLimit->pLeft, &v, 0, 0)==0 ) return 0; + if( v!=1 ) return 0; + if( OptimizationDisabled(db, SQLITE_UnionLimit) ) return 0; + return 1; +} + +/* +** This routine is called to process a compound query formed from ** two or more separate queries using UNION, UNION ALL, EXCEPT, or ** INTERSECT ** -** "p" points to the right-most of the two queries. the query on the +** "p" points to the right-most of the two queries. The query on the ** left is p->pPrior. The left query could also be a compound query ** in which case this routine will be called recursively. ** @@ -152168,7 +152764,7 @@ static int multiSelect( /* If the compound has an ORDER BY clause, then always use the merge ** algorithm. */ return multiSelectByMerge(pParse, p, pDest); - }else if( p->op!=TK_ALL ){ + }else if( p->op!=TK_ALL && !unionWithLimitOne(db,p) ){ /* If the compound is EXCEPT, INTERSECT, or UNION (anything other than ** UNION ALL) then also always use the merge algorithm. However, the ** multiSelectByMerge() routine requires that the compound have an @@ -152180,7 +152776,8 @@ static int multiSelect( p->pOrderBy->a[0].u.x.iOrderByCol = 1; return multiSelectByMerge(pParse, p, pDest); }else{ - /* For a UNION ALL compound without ORDER BY, simply run the left + /* For a UNION ALL compound without ORDER BY, or for a UNION with a + ** LIMIT of exactly 1 and no OFFSET and no ORDER BY, simply run the left ** query, then run the right query */ int addr = 0; int nLimit = 0; /* Initialize to suppress harmless compiler warning */ @@ -152221,7 +152818,7 @@ static int multiSelect( p->pPrior = pPrior; p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); if( p->pLimit - && sqlite3ExprIsInteger(p->pLimit->pLeft, &nLimit, pParse) + && sqlite3ExprIsInteger(p->pLimit->pLeft, &nLimit, pParse, 0) && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit) ){ p->nSelectRow = sqlite3LogEst((u64)nLimit); @@ -152384,6 +152981,7 @@ static int generateOutputSubroutine( sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1, pIn->iSdst, pIn->nSdst); if( pDest->iSDParm2>0 ){ + assert( sqlite3CursorBloomable(pParse, pDest->iSDParm, pIn->nSdst) ); sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pDest->iSDParm2, 0, pIn->iSdst, pIn->nSdst); ExplainQueryPlan((pParse, 0, "CREATE BLOOM FILTER")); @@ -152730,7 +153328,7 @@ static int multiSelectByMerge( /* Compute the limit registers */ computeLimitRegisters(pParse, p, labelEnd); - if( p->iLimit && op==TK_ALL ){ + if( p->iLimit && (op==TK_ALL || unionWithLimitOne(db,p)) ){ regLimitA = ++pParse->nMem; regLimitB = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Copy, p->iOffset ? p->iOffset+1 : p->iLimit, @@ -153758,7 +154356,7 @@ static int flattenSubquery( pSub = pSub1; for(pParent=p; pParent; pParent=pParent->pPrior, pSub=pSub->pPrior){ int nSubSrc; - u8 jointype = pSubitem->fg.jointype; + u8 jointype = pParent->pSrc->a[iFrom].fg.jointype; assert( pSub!=0 ); pSubSrc = pSub->pSrc; /* FROM clause of subquery */ nSubSrc = pSubSrc->nSrc; /* Number of terms in subquery FROM clause */ @@ -153783,7 +154381,6 @@ static int flattenSubquery( pSrc = sqlite3SrcListEnlarge(pParse, pSrc, nSubSrc-1,iFrom+1); if( pSrc==0 ) break; pParent->pSrc = pSrc; - pSubitem = &pSrc->a[iFrom]; } /* Transfer the FROM clause terms from the subquery into the @@ -153801,7 +154398,7 @@ static int flattenSubquery( pItem->fg.jointype |= (jointype & JT_LTORJ); memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i])); } - pSubitem->fg.jointype |= jointype; + pSrc->a[iFrom].fg.jointype |= jointype; /* Begin substituting subquery result set expressions for ** references to the iParent in the outer query. @@ -153916,12 +154513,21 @@ 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. +** Add a new entry to the pConst object, if appropriate. +** +** * Do not add if pValue is not constant. (This is enforced by +** the caller) +** +** * Do not add duplicate pColumn entries ** -** The caller guarantees the pColumn is a column and pValue is a constant. -** This routine has to do some additional checks before completing the -** insert. +** * Do not add if pValue has an affinity +** +** * Do not add if the comparison uses a collating sequence other +** than binary. +** +** * Do not add if pValue is a function that might return a subtype +** +** The caller guarantees the pColumn is a column. */ static void constInsert( WhereConst *pConst, /* The WhereConst into which we are inserting */ @@ -153932,12 +154538,12 @@ static void constInsert( int i; assert( pColumn->op==TK_COLUMN ); assert( sqlite3ExprIsConstant(pConst->pParse, pValue) ); - if( ExprHasProperty(pColumn, EP_FixedCol) ) return; if( sqlite3ExprAffinity(pValue)!=0 ) return; if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pConst->pParse,pExpr)) ){ return; } + if( sqlite3ExprCanReturnSubtype(pConst->pParse, pValue) ) return; /* 2018-10-25 ticket [cf5ed20f] ** Make sure the same pColumn is not inserted more than once */ @@ -154841,14 +155447,13 @@ SQLITE_PRIVATE With *sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){ } /* -** This function checks if argument pFrom refers to a CTE declared by +** This function checks to see if argument pFrom refers to a CTE declared by ** a WITH clause on the stack currently maintained by the parser (on the -** pParse->pWith linked list). And if currently processing a CTE -** CTE expression, through routine checks to see if the reference is -** a recursive reference to the CTE. +** pParse->pWith linked list). And if currently processing a CTE expression, +** it also checks to see if the reference is a recursive reference to the CTE. ** -** If pFrom matches a CTE according to either of these two above, pFrom->pSTab -** and other fields are populated accordingly. +** If pFrom matches a CTE, pFrom->pSTab and other fields are populated +** accordingly. ** ** Return 0 if no match is found. ** Return 1 if a match is found. @@ -154977,6 +155582,18 @@ static int resolveFromTermToCte( pRecTerm = pRecTerm->pPrior; } +#if SQLITE_MAX_EXPR_DEPTH>0 + if( pParse->nTab>=db->aLimit[SQLITE_LIMIT_EXPR_DEPTH] ){ + /* Bug 2026-10-04T05:35:14Z: Prevent nested CTEs from generating + ** an exponential number of cursors. The error message here will + ** be "Nested too deep", which isn't exactly correct, but it is + ** sufficient, and we don't want to use extra code space for more + ** detail on such an obscure error. */ + pParse->nNestSel = pParse->nTab; + } + pParse->nNestSel++; + if( checkSubqueryNestingDepth(pParse) ) return 2; +#endif pCte->zCteErr = "circular reference: %s"; pSavedWith = pParse->pWith; pParse->pWith = pWith; @@ -155001,6 +155618,10 @@ static int resolveFromTermToCte( } } pParse->pWith = pWith; +#if SQLITE_MAX_EXPR_DEPTH>0 + pParse->nNestSel--; + assert( pParse->nNestSel>=0 ); +#endif for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior); pEList = pLeft->pEList; @@ -155447,6 +156068,7 @@ static int selectExpander(Walker *pWalker, Select *p){ pRight = sqlite3Expr(db, TK_ID, zName); if( (pTabList->nSrc>1 && ( (pFrom->fg.jointype & JT_LTORJ)==0 + || zTName!=0 || (selFlags & SF_NestedFrom)!=0 || !inAnyUsingClause(zName,pFrom,pTabList->nSrc-i-1) ) @@ -156333,7 +156955,8 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */ if( ExprHasProperty(pExpr, EP_WinFunc) ) return 0;/* Not a window function */ pFrom = p->pSrc->a; - if( pFrom->fg.isSubquery==0 ) return 0; /* FROM is a subquery */ + if( pFrom->fg.isSubquery==0 ) return 0; /* FROM is a subquery */ + if( (p->selFlags & SF_Correlated)!=0 ) return 0; /* Not a correlated subq */ pSub = pFrom->u4.pSubq->pSelect; if( pSub->pPrior==0 ) return 0; /* Must be a compound */ if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */ @@ -156376,6 +156999,10 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ }else{ pExpr = sqlite3PExpr(pParse, TK_PLUS, pTerm, pExpr); } + if( pParse->nErr ){ + sqlite3ExprDelete(db, pExpr); + pExpr = 0; + } pSub = pPrior; } p->pEList->a[0].pExpr = pExpr; @@ -156552,6 +157179,7 @@ static SQLITE_NOINLINE void existsToJoin( } pSub->pSrc = 0; sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pSub); + recomputeColumnsUsed(p, &p->pSrc->a[p->pSrc->nSrc-1]); #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x100000 ){ TREETRACE(0x100000,pParse,p, @@ -156569,10 +157197,10 @@ static SQLITE_NOINLINE void existsToJoin( */ typedef struct CheckOnCtx CheckOnCtx; struct CheckOnCtx { - SrcList *pSrc; /* SrcList for this context */ - int iJoin; /* Cursor numbers must be =< than this */ - int bFuncArg; /* True for table-function arg */ - CheckOnCtx *pParent; /* Parent context */ + SrcList *pSrc; /* SrcList for this context */ + int iJoin; /* Cursors must be left of this one, if not negative */ + int bFuncArg; /* True for table-function arg */ + CheckOnCtx *pParent; /* Parent context */ }; /* @@ -156603,11 +157231,11 @@ static int selectCheckOnClausesExpr(Walker *pWalker, Expr *pExpr){ ** set it to the cursor number of the RHS of the join to which this ** ON expression was attached and then iterate through the entire ** expression. */ - assert( pCtx->iJoin==0 || pCtx->iJoin==pExpr->w.iJoin ); - if( pCtx->iJoin==0 ){ + assert( pCtx->iJoin<0 || pCtx->iJoin==pExpr->w.iJoin ); + if( pCtx->iJoin<0 ){ pCtx->iJoin = pExpr->w.iJoin; sqlite3WalkExprNN(pWalker, pExpr); - pCtx->iJoin = 0; + pCtx->iJoin = -1; return WRC_Prune; } } @@ -156617,19 +157245,25 @@ static int selectCheckOnClausesExpr(Walker *pWalker, Expr *pExpr){ ** Then, if CheckOnCtx.iJoin indicates that this expression is part of an ** ON clause from that SrcList (i.e. if iJoin is non-zero), check that it ** does not refer to a table to the right of CheckOnCtx.iJoin. */ + int iTab = pExpr->iTable; do { SrcList *pSrc = pCtx->pSrc; int nSrc = pSrc->nSrc; - int iTab = pExpr->iTable; int ii; for(ii=0; iia[ii].iCursor!=iTab; ii++){} if( iiiJoin && iTab>pCtx->iJoin ){ - sqlite3ErrorMsg(pWalker->pParse, - "%s references tables to its right", - (pCtx->bFuncArg ? "table-function argument" : "ON clause") - ); - return WRC_Abort; + /* pSrc is the FROM clause that contains iTab */ + if( pCtx->iJoin>=0 ){ + for(ii--; ii>=0 && pSrc->a[ii].iCursor!=pCtx->iJoin; ii--){} + if( ii>=0 ){ + /* Table iJoin appears to the left of table iTab in the SrcList. + ** Therefore the expression refers to a table to its right. */ + sqlite3ErrorMsg(pWalker->pParse, + "%s references tables to its right", + (pCtx->bFuncArg ? "table-function argument" : "ON clause") + ); + return WRC_Abort; + } } break; } @@ -156651,6 +157285,7 @@ static int selectCheckOnClausesSelect(Walker *pWalker, Select *pSelect){ memset(&sCtx, 0, sizeof(sCtx)); sCtx.pSrc = pSelect->pSrc; sCtx.pParent = pCtx; + sCtx.iJoin = -1; pWalker->u.pCheckOnCtx = &sCtx; sqlite3WalkSelect(pWalker, pSelect); pWalker->u.pCheckOnCtx = pCtx; @@ -156676,20 +157311,41 @@ SQLITE_PRIVATE void sqlite3SelectCheckOnClauses(Parse *pParse, Select *pSelect){ w.u.pCheckOnCtx = &sCtx; memset(&sCtx, 0, sizeof(sCtx)); sCtx.pSrc = pSelect->pSrc; + sCtx.iJoin = -1; sqlite3WalkExpr(&w, pSelect->pWhere); pSelect->selFlags &= ~SF_OnToWhere; /* Check for any table-function args that are attached to virtual tables - ** on the RHS of an outer join. They are subject to the same constraints - ** as ON clauses. */ + ** on the RHS of an outer join. They are subject to similar constraints + ** as ON clauses. Specifically: + ** + ** * If the table-valued function is to the left of any RIGHT JOIN, or if + ** it is the RHS of a RIGHT JOIN, then the table-valued function arguments + ** may not refer to any tables to the right of this one. + ** + ** * If the table-valued function is to the left of a LEFT JOIN, then it + ** may not refer to any table that occurs to the right of the LEFT JOIN. + */ sCtx.bFuncArg = 1; for(ii=0; iipSrc->nSrc; ii++){ SrcItem *pItem = &pSelect->pSrc->a[ii]; - if( pItem->fg.isTabFunc - && (pItem->fg.jointype & JT_OUTER) - ){ - sCtx.iJoin = pItem->iCursor; - sqlite3WalkExprList(&w, pItem->u1.pFuncArg); + if( pItem->fg.isTabFunc ){ + sCtx.iJoin = -1; + if( (pItem->fg.jointype & (JT_LTORJ|JT_RIGHT)) ){ + sCtx.iJoin = pItem->iCursor; + }else{ + int jj; + for(jj=ii+1; jjpSrc->nSrc; jj++){ + SrcItem *pItem2 = &pSelect->pSrc->a[jj]; + if( pItem2->fg.jointype & JT_OUTER ){ + sCtx.iJoin = pItem2[-1].iCursor; + break; + } + } + } + if( sCtx.iJoin>=0 ){ + sqlite3WalkExprList(&w, pItem->u1.pFuncArg); + } } } } @@ -158564,8 +159220,9 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){ if( !noErr ){ sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); + }else if( db->init.busy ){ + sqlite3ErrorMsg(pParse,""); /* Err msg generated by corruptSchema() */ }else{ - assert( !db->init.busy ); sqlite3CodeVerifySchema(pParse, iDb); VVA_ONLY( pParse->ifNotExists = 1; ) } @@ -158689,6 +159346,7 @@ SQLITE_PRIVATE void sqlite3FinishTrigger( DbFixer sFix; /* Fixer object */ int iDb; /* Database containing the trigger */ Token nameToken; /* Trigger name for error reporting */ + i64 n; /* Number of steps */ pParse->pNewTrigger = 0; if( NEVER(pParse->nErr) || !pTrig ) goto triggerfinish_cleanup; @@ -158696,10 +159354,14 @@ SQLITE_PRIVATE void sqlite3FinishTrigger( iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); assert( iDb>=00 && iDbnDb ); pTrig->step_list = pStepList; - while( pStepList ){ + for(n=0; pStepList; n++){ pStepList->pTrig = pTrig; pStepList = pStepList->pNext; } + if( n>pParse->db->aLimit[SQLITE_LIMIT_TRIGGER_STEPS] ){ + sqlite3ErrorMsg(pParse, "trigger \"%w\" contains too many steps", zName); + goto triggerfinish_cleanup; + } sqlite3TokenInit(&nameToken, pTrig->zName); sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken); if( sqlite3FixTriggerStep(&sFix, pTrig->step_list) @@ -159994,26 +160656,37 @@ static void updateVirtualTable( ** integer. In that case, add an OP_RealAffinity opcode to make sure ** it has been converted into REAL. */ -SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){ +static SQLITE_NOINLINE void columnDefaultUncommonCase( + Vdbe *v, /* Byte code under construction */ + Table *pTab, /* The table */ + Column *pCol /* Which column of the table */ +){ + sqlite3_value *pValue = 0; + u8 enc = ENC(sqlite3VdbeDb(v)); + Parse *pParse = sqlite3VdbeParser(v); + assert( !IsView(pTab) ); + sqlite3ValueFromExpr(sqlite3VdbeDb(v), + sqlite3ColumnExprAuth(pTab,pCol,pParse), enc, + pCol->affinity, &pValue); + if( pValue ){ + sqlite3VdbeAppendP4(v, pValue, P4_MEM); + } +} +SQLITE_PRIVATE void sqlite3ColumnDefault( + Vdbe *v, /* Byte code under construction */ + Table *pTab, /* The table */ + int i, /* Which column of the table */ + int iReg /* Register in which results are stored */ +){ Column *pCol; assert( pTab!=0 ); assert( pTab->nCol>i ); pCol = &pTab->aCol[i]; if( pCol->iDflt ){ - sqlite3_value *pValue = 0; - u8 enc = ENC(sqlite3VdbeDb(v)); - assert( !IsView(pTab) ); - VdbeComment((v, "%s.%s", pTab->zName, pCol->zCnName)); - assert( inCol ); - sqlite3ValueFromExpr(sqlite3VdbeDb(v), - sqlite3ColumnExpr(pTab,pCol), enc, - pCol->affinity, &pValue); - if( pValue ){ - sqlite3VdbeAppendP4(v, pValue, P4_MEM); - } + columnDefaultUncommonCase(v,pTab,pCol); } #ifndef SQLITE_OMIT_FLOATING_POINT - if( pCol->affinity==SQLITE_AFF_REAL && !IsVirtual(pTab) ){ + if( pCol->affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg); } #endif @@ -160828,6 +161501,7 @@ SQLITE_PRIVATE void sqlite3Update( sqlite3VdbeAddOp3(v, OP_Column, iEph, iRowidExpr, regNewRowid); } sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid); VdbeCoverage(v); + sqlite3MayAbort(pParse); } /* Compute the old pre-UPDATE content of the row being changed, if that @@ -162797,6 +163471,8 @@ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ if( rc!=SQLITE_OK ){ sqlite3ErrorMsg(pParse, "%s", zErr); pParse->rc = rc; + }else{ + sqlite3MarkAllShadowTablesOf(db, pTab); } sqlite3DbFree(db, zErr); } @@ -163384,6 +164060,17 @@ SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){ } } +/* +** Erase all eponymous virtual table instances associated with database +** handle db. +*/ +SQLITE_PRIVATE void sqlite3VtabEponymousTableClearAll(sqlite3 *db){ + HashElem *pElem; + for(pElem=sqliteHashFirst(&db->aModule); pElem; pElem=sqliteHashNext(pElem)){ + sqlite3VtabEponymousTableClear(db, (Module*)sqliteHashData(pElem)); + } +} + /* ** Return the ON CONFLICT resolution mode in effect for the virtual ** table update operation currently in progress. @@ -164076,10 +164763,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereExprUsageNN(WhereMaskSet*, Expr*); SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*); SQLITE_PRIVATE void sqlite3WhereExprAnalyze(SrcList*, WhereClause*); SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*); - - - - +SQLITE_PRIVATE int sqlite3WhereLoopBloomable(const WhereLoop*); /* ** Bitmasks for the operators on WhereTerm objects. These are all @@ -164719,6 +165403,7 @@ static Expr *removeUnindexableInClauseTerms( ExprList *pRhs = 0; /* New RHS after modifications */ ExprList *pLhs = 0; /* New LHS after mods */ int i; /* Loop counter */ + int nRhs = 0; /* Number of RHS terms added so far */ assert( ExprUseXSelect(pNew) ); pOrigRhs = pSelect->pEList; @@ -164732,6 +165417,9 @@ static Expr *removeUnindexableInClauseTerms( int iField; assert( (pLoop->aLTerm[i]->eOperator & (WO_OR|WO_AND))==0 ); iField = pLoop->aLTerm[i]->u.x.iField - 1; + if( iField!=nRhs ){ + ExprClearProperty(pNew, EP_Subrtn); + } if( NEVER(pOrigRhs->a[iField].pExpr==0) ){ continue; /* Duplicate PK column */ } @@ -164743,6 +165431,7 @@ static Expr *removeUnindexableInClauseTerms( pLhs = sqlite3ExprListAppend(pParse,pLhs,pOrigLhs->a[iField].pExpr); pOrigLhs->a[iField].pExpr = 0; } + nRhs++; } } sqlite3ExprListDelete(db, pOrigRhs); @@ -164842,8 +165531,20 @@ static SQLITE_NOINLINE void codeINTerm( }else{ sqlite3 *db = pParse->db; Expr *pXMod = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX); + if( nEq>1 ){ + /* If this IN(SELECT ...) expression drives more than one column of + ** the index, disable the seek-scan optimization. The reasons for this + ** are that (a) it is only possible to make this happen by populating + ** the sqlite_stat1 table with inconsistent information, and (b) it + ** would require sqlite3FindInIndex() to find an index that is not + ** only unique for the columns in question, but also delivers them + ** in sorted order (requires checking asc/desc, and rejecting cases + ** where the indexed columns are not in the right order). */ + pLoop->wsFlags &= ~WHERE_IN_SEEKSCAN; + } if( !db->mallocFailed ){ - aiMap = (int*)sqlite3DbMallocZero(db, sizeof(int)*nEq); + int nCol = pX->x.pSelect->pEList->nExpr; + aiMap = (int*)sqlite3DbMallocZero(db, sizeof(int)*nCol); eType = sqlite3FindInIndex(pParse, pXMod, IN_INDEX_LOOP, 0, aiMap, &iTab); } sqlite3ExprDelete(db, pXMod); @@ -165090,12 +165791,7 @@ static int codeAllEqualityTerms( testcase( pTerm->wtFlags & TERM_VIRTUAL ); r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, regBase+j); if( r1!=regBase+j ){ - if( nReg==1 ){ - sqlite3ReleaseTempReg(pParse, regBase); - regBase = r1; - }else{ - sqlite3VdbeAddOp2(v, OP_Copy, r1, regBase+j); - } + sqlite3VdbeAddOp2(v, OP_Copy, r1, regBase+j); } if( pTerm->eOperator & WO_IN ){ if( pTerm->pExpr->flags & EP_xIsSelect ){ @@ -165548,6 +166244,7 @@ static SQLITE_NOINLINE void filterPullDown( regRowid = codeEqualityTerm(pParse, pTerm, pLevel, 0, 0, regRowid); sqlite3VdbeAddOp2(pParse->pVdbe, OP_MustBeInt, regRowid, addrNxt); VdbeCoverage(pParse->pVdbe); + assert( sqlite3WhereLoopBloomable(pLoop) ); sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter, addrNxt, regRowid, 1); VdbeCoverage(pParse->pVdbe); @@ -165561,6 +166258,7 @@ static SQLITE_NOINLINE void filterPullDown( r1 = codeAllEqualityTerms(pParse,pLevel,0,0,&zStartAff); codeApplyAffinity(pParse, r1, nEq, zStartAff); sqlite3DbFree(pParse->db, zStartAff); + assert( sqlite3WhereLoopBloomable(pLoop) ); sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter, addrNxt, r1, nEq); VdbeCoverage(pParse->pVdbe); @@ -165591,6 +166289,49 @@ static int whereLoopIsOneRow(WhereLoop *pLoop){ return 0; } +/* +** This is called while coding loop pLevel, which scans FROM clause item +** pTabItem. pE is an expression for which all the prerequisites are +** available. This function tests if pE can be coded as part of the current +** loop, or whether it needs to be deferred to ensure outer joins are +** processed correctly. This function returns non-zero if the expression +** can be coded as part of the loop, or 0 if it must be deferred. +** +** The expression must be deferred if: +** +** * There are any RIGHT joins in the FROM clause and the expression +** was not part of an ON clause, or was part of an ON clause to the +** right of the join. +** +** * The table is the RHS of a LEFT JOIN and the expression was not +** part of an ON clause on an OUTER join, or was part of an ON clause +** on an OUTER join to the right of the join. +*/ +static int whereExprIsReady( + WhereInfo *pWInfo, + WhereLevel *pLevel, + SrcItem *pTabItem, + Expr *pE +){ + u8 jtype = pTabItem->fg.jointype; + if( jtype & (JT_LEFT|JT_LTORJ|JT_RIGHT) ){ + if( !ExprHasProperty(pE,EP_OuterON|EP_InnerON) ){ + /* Defer processing WHERE clause constraints until after outer + ** join processing. tag-20220513a */ + return 0; + }else if( (jtype & JT_LEFT) && !ExprHasProperty(pE,EP_OuterON) ){ + return 0; + }else{ + Bitmask m = sqlite3WhereGetMask(&pWInfo->sMaskSet, pE->w.iJoin); + if( m & pLevel->notReady ){ + /* An ON clause that is not ripe */ + return 0; + } + } + } + return 1; +} + /* ** Generate code for the start of the iLevel-th loop in the WHERE clause ** implementation described by pWInfo. @@ -165670,6 +166411,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( pLevel->iLeftJoin = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin); VdbeComment((v, "init LEFT JOIN match flag")); + if( pTabItem->fg.viaCoroutine ){ + sqlite3VdbeAddOp2(v, OP_NullRow, pTabItem->iCursor, 1); + } } /* Special case of a FROM clause subquery implemented as a co-routine */ @@ -166164,6 +166908,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( VdbeComment((v, "NULL-scan pass ctr")); } if( pLevel->regFilter ){ + assert( sqlite3WhereLoopBloomable(pLoop) ); sqlite3VdbeAddOp4Int(v, OP_Filter, pLevel->regFilter, addrNxt, regBase, nEq); VdbeCoverage(v); @@ -166520,6 +167265,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue; if( ExprHasProperty(pExpr, EP_Subquery) ) continue; /* tag-20220303a */ + if( whereExprIsReady(pWInfo, pLevel, pTabItem, pExpr)==0 ) continue; pExpr = sqlite3ExprDup(db, pExpr, 0); pAndExpr = sqlite3ExprAnd(pParse, pAndExpr, pExpr); } @@ -166760,22 +167506,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } pE = pTerm->pExpr; assert( pE!=0 ); - if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT) ){ - if( !ExprHasProperty(pE,EP_OuterON|EP_InnerON) ){ - /* Defer processing WHERE clause constraints until after outer - ** join processing. tag-20220513a */ - continue; - }else if( (pTabItem->fg.jointype & JT_LEFT)==JT_LEFT - && !ExprHasProperty(pE,EP_OuterON) ){ - continue; - }else{ - Bitmask m = sqlite3WhereGetMask(&pWInfo->sMaskSet, pE->w.iJoin); - if( m & pLevel->notReady ){ - /* An ON clause that is not ripe */ - continue; - } - } - } + if( whereExprIsReady(pWInfo, pLevel, pTabItem, pE)==0 ) continue; if( iLoop==1 && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){ iNext = 2; continue; @@ -166901,8 +167632,10 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( VdbeComment((v, "match against %s", pTab->zName)); sqlite3VdbeAddOp3(v, OP_MakeRecord, r+1, nPk, r); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pRJ->iMatch, r, r+1, nPk); - sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pRJ->regBloom, 0, r+1, nPk); - sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); + if( pRJ->regBloom ){ + sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pRJ->regBloom, 0, r+1, nPk); + sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); + } sqlite3VdbeJumpHere(v, jmp1); sqlite3ReleaseTempRange(pParse, r, nPk+1); } @@ -166926,9 +167659,11 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** loop will run that invokes this subroutine for unmatched rows ** of pTab, with all tables to left begin set to NULL. */ - WhereRightJoin *pRJ = pLevel->pRJ; - sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pRJ->regReturn); - pRJ->addrSubrtn = sqlite3VdbeCurrentAddr(v); + { + WhereRightJoin *pRJ = pLevel->pRJ; + sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pRJ->regReturn); + pRJ->addrSubrtn = sqlite3VdbeCurrentAddr(v); + } assert( pParse->withinRJSubrtn < 255 ); pParse->withinRJSubrtn++; @@ -167046,17 +167781,25 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( pFrom->nAlloc = 1; memcpy(&pFrom->a[0], pTabItem, sizeof(SrcItem)); pFrom->a[0].fg.jointype = 0; - assert( pParse->withinRJSubrtn < 100 ); + if( pParse->withinRJSubrtn >= 100 ){ + /* This limit --------------^^^ + ** is based on an historical assert(). It is not compile-time or + ** run-time configurable. It could perhaps be raised as high as 254, + ** but only an attack robot would ever do even 100 RIGHT JOINS within + ** a single query, so we'll just leave it as it is. */ + sqlite3ErrorMsg(pParse, "too many RIGHT JOINs"); + return; + } pParse->withinRJSubrtn++; pSubWInfo = sqlite3WhereBegin(pParse, pFrom, pSubWhere, 0, 0, 0, WHERE_RIGHT_JOIN, 0); if( pSubWInfo ){ - int iCur = pLevel->iTabCur; - int r = ++pParse->nMem; - int nPk; - int jmp; + int iCur = pLevel->iTabCur; /* Table on RHS of RIGHT JOIN &*/ + int r = ++pParse->nMem; /* Register range to hold primary key */ + int nPk; /* Number of values in the primary key */ + int r2; /* Register holding record for primary key */ int addrCont = sqlite3WhereContinueLabel(pSubWInfo); - Table *pTab = pTabItem->pSTab; + Table *pTab = pTabItem->pSTab; /* Table on RHS of RIGHT JOIN */ if( HasRowid(pTab) ){ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r); nPk = 1; @@ -167070,11 +167813,31 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk); } } - jmp = sqlite3VdbeAddOp4Int(v, OP_Filter, pRJ->regBloom, 0, r, nPk); - VdbeCoverage(v); + + /* Generate code that checks to see if the current row of the RHS table + ** has appeared in any prior output row. */ + if( pRJ->regBloom ){ + sqlite3VdbeAddOp4Int(v, OP_Filter, pRJ->regBloom, + sqlite3VdbeCurrentAddr(v)+2, r, nPk); + VdbeCoverage(v); + } sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, addrCont, r, nPk); VdbeCoverage(v); - sqlite3VdbeJumpHere(v, jmp); + r2 = sqlite3GetTempReg(pParse); + + /* Generate code that inserts the PK of the RHS table into the + ** pRH->iMatch index to indicate that the current row has appeared + ** in the output set. */ + sqlite3VdbeAddOp3(v, OP_MakeRecord, r, nPk, r2); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pRJ->iMatch, r2, r, nPk); + sqlite3ReleaseTempReg(pParse, r2); + if( pRJ->regBloom ){ + sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pRJ->regBloom, 0, r, nPk); + sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); + } + + /* Invoke the subroutine that actually puts the current RHS table row + ** into the output set, with NULLs for the LHS. */ sqlite3VdbeAddOp2(v, OP_Gosub, pRJ->regReturn, pRJ->addrSubrtn); sqlite3WhereEnd(pSubWInfo); } @@ -167300,7 +168063,7 @@ static int isLikeOrGlob( if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){ z = sqlite3_value_text(pVal); } - sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); + sqlite3VdbeReprepareOnBind(pParse->pVdbe, iCol, 0); assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER ); }else if( op==TK_STRING ){ assert( !ExprHasProperty(pRight, EP_IntValue) ); @@ -167405,7 +168168,7 @@ static int isLikeOrGlob( ** reprepare the statement when that parameter is rebound */ if( op==TK_VARIABLE ){ Vdbe *v = pParse->pVdbe; - sqlite3VdbeSetVarmask(v, pRight->iColumn); + sqlite3VdbeReprepareOnBind(v, pRight->iColumn, 0); assert( !ExprHasProperty(pRight, EP_IntValue) ); if( *pisComplete && pRight->u.zToken[1] ){ /* If the rhs of the LIKE expression is a variable, and the current @@ -167995,29 +168758,58 @@ static void exprAnalyzeOrTerm( } } - /* At this point, okToChngToIN is true if original pTerm satisfies - ** case 1. In that case, construct a new virtual term that is - ** pTerm converted into an IN operator. + /* At this point, okToChngToIN is true if original pTerm is a + ** candidate to satisfy case 1, though we are not yet certain that + ** the collating sequences are all compatible. Try to construct a + ** new virtual term that is pTerm converted from an OR operator + ** into an IN operator. + ** + ** During construction, verify that the collating sequences on all + ** subterms of the OR are compatible. Omit the construction of the + ** new IN operator if there are any collating sequence mismatches. */ if( okToChngToIN ){ Expr *pDup; /* A transient duplicate expression */ ExprList *pList = 0; /* The RHS of the IN operator */ Expr *pLeft = 0; /* The LHS of the IN operator */ + CollSeq *pCollSeq = 0; /* Collating sequence to use */ Expr *pNew; /* The complete IN operator */ for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){ + Expr *pThis; if( (pOrTerm->wtFlags & TERM_OK)==0 ) continue; assert( pOrTerm->eOperator & WO_EQ ); assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 ); assert( pOrTerm->leftCursor==iCursor ); assert( pOrTerm->u.x.leftColumn==iColumn ); - pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0); + pThis = pOrTerm->pExpr; + pDup = sqlite3ExprDup(db, pThis->pRight, 0); pList = sqlite3ExprListAppend(pWInfo->pParse, pList, pDup); - pLeft = pOrTerm->pExpr->pLeft; + if( pLeft==0 ){ + pLeft = pThis->pLeft; + pCollSeq = sqlite3ExprCompareCollSeq(pParse, pThis); + }else{ + assert( 0==sqlite3ExprCompare(pParse, + sqlite3ExprSkipCollate(pThis->pLeft), + sqlite3ExprSkipCollate(pLeft), -1) ); + if( pCollSeq!=sqlite3ExprCompareCollSeq(pParse, pThis) ){ + pLeft = 0; /* Collating sequence mismatch */ + break; + } + } + } + if( pLeft==0 ){ + pNew = 0; /* Collating sequence mismatch */ + }else{ + pDup = sqlite3ExprDup(db, pLeft, 0); + if( sqlite3ExprCollSeq(pParse, pDup)!=pCollSeq + && ALWAYS(pCollSeq!=0) + ){ + assert( pCollSeq->zName!=0 ); + pDup = sqlite3ExprAddCollateString(pParse, pDup, pCollSeq->zName); + } + pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0); } - assert( pLeft!=0 ); - pDup = sqlite3ExprDup(db, pLeft, 0); - pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0); if( pNew ){ int idxNew; transferJoinMarkings(pNew, pExpr); @@ -168239,6 +169031,7 @@ static void exprAnalyze( pExpr = pTerm->pExpr; assert( pExpr!=0 ); /* Because malloc() has not failed */ assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE ); +exprAnalyze_restart: pMaskSet->bVarSelect = 0; prereqLeft = sqlite3WhereExprUsage(pMaskSet, pExpr->pLeft); op = pExpr->op; @@ -168405,6 +169198,11 @@ static void exprAnalyze( ** an OR operator. */ else if( pExpr->op==TK_OR && !ExprHasProperty(pExpr, EP_Collate) ){ + Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr); + if( pAlt!=pExpr ){ + pTerm->pExpr = pExpr = sqlite3ExprSkipCollateAndLikely(pAlt); + goto exprAnalyze_restart; + } assert( pWC->op==TK_AND ); exprAnalyzeOrTerm(pSrc, pWC, idxTerm); pTerm = &pWC->a[idxTerm]; @@ -168593,6 +169391,7 @@ static void exprAnalyze( #ifndef SQLITE_OMIT_WINDOWFUNC && pExpr->x.pSelect->pWin==0 #endif + && (pExpr->x.pSelect->selFlags & SF_MinMaxAgg)==0 && pWC->op==TK_AND && pExpr->x.pSelect->pEList->nExpr <= UMXV(pTerm->nChild) /* ^-- See bug 2026-06-04T10:00:49Z */ @@ -168720,7 +169519,7 @@ static void whereAddLimitExpr( Expr *pNew; int iVal = 0; - if( sqlite3ExprIsInteger(pExpr, &iVal, pParse) && iVal>=0 ){ + if( sqlite3ExprIsInteger(pExpr, &iVal, pParse, 0) && iVal>=0 ){ Expr *pVal = sqlite3ExprInt32(db, iVal); if( pVal==0 ) return; pNew = sqlite3PExpr(pParse, TK_MATCH, 0, pVal); @@ -169000,6 +169799,10 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs( if( pItem->fg.isTabFunc==0 ) return; pTab = pItem->pSTab; assert( pTab!=0 ); + if( !IsVirtual(pTab) ){ + sqlite3ErrorMsg(pParse, "'%s' is not a function", pItem->zName); + return; + } pArgs = pItem->u1.pFuncArg; if( pArgs==0 ) return; for(j=k=0; jnExpr; j++){ @@ -169034,6 +169837,16 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs( } } +/* +** Return true if the WhereLoop pLoop can be use a Bloom filter. +** tag-202607231411 +*/ +SQLITE_PRIVATE int sqlite3WhereLoopBloomable(const WhereLoop *pLoop){ + if( pLoop->wsFlags & WHERE_IPK ) return 1; + if( NEVER((pLoop->wsFlags & WHERE_INDEXED)==0) ) return 0; + return sqlite3IndexBloomable(pLoop->u.btree.pIndex, pLoop->u.btree.nEq); +} + /************** End of whereexpr.c *******************************************/ /************** Begin file where.c *******************************************/ /* @@ -169201,7 +170014,7 @@ SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo *pWInfo){ ** If the ONEPASS optimization is used (if this routine returns true) ** then also write the indices of open cursors used by ONEPASS ** into aiCur[0] and aiCur[1]. iaCur[0] gets the cursor of the data -** table and iaCur[1] gets the cursor used by an auxiliary index. +** table and aiCur[1] gets the cursor used by an auxiliary index. ** Either value may be -1, indicating that cursor is not used. ** Any cursors returned will have been opened for writing. ** @@ -170045,7 +170858,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex( 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 useBloomFilter = 1; /* True to also add a Bloom filter */ Expr *pPartial = 0; /* Partial Index Expression */ int iContinue = 0; /* Jump here to skip excluded rows */ SrcList *pTabList; /* The complete FROM clause */ @@ -170172,18 +170985,13 @@ static SQLITE_NOINLINE void constructAutomaticIndex( pIdx->aiColumn[n] = pTerm->u.x.leftColumn; pColl = sqlite3ExprCompareCollSeq(pParse, pX); assert( pColl!=0 || pParse->nErr>0 ); /* TH3 collate01.800 */ + if( !sqlite3IsBinary(pColl) ){ + /* Disallow the use of a Bloom filter if any non-BINARY collating + ** sequence is involved. tag-202607231411 */ + useBloomFilter = 0; + } 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; - } } } } @@ -170253,6 +171061,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex( pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0 ); if( pLevel->regFilter ){ + assert( sqlite3WhereLoopBloomable(pLoop) ); sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, regBase, pLoop->u.btree.nEq); } @@ -170293,9 +171102,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex( ** for pLevel. ** ** If there are inner loops within pLevel that have the WHERE_BLOOMFILTER -** flag set, initialize a Bloomfilter for them as well. Except don't do -** this recursive initialization if the SQLITE_BloomPulldown optimization has -** been turned off. +** flag set, initialize a Bloomfilter for them as well. ** ** When the Bloom filter is initialized, the WHERE_BLOOMFILTER flag is cleared ** from the loop, but the regFilter value is set to a register that implements @@ -170368,6 +171175,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( }else if( sz>10000000 ){ sz = 10000000; } + assert( sqlite3WhereLoopBloomable(pLoop) ); sqlite3VdbeAddOp2(v, OP_Blob, (int)sz, pLevel->regFilter); addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v); @@ -170390,6 +171198,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( int n = pLoop->u.btree.nEq; int r1 = sqlite3GetTempRange(pParse, n); int jj; + assert( pIdx!=0 ); for(jj=0; jjpTable==pItem->pSTab ); sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj); @@ -170402,7 +171211,6 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( VdbeCoverage(v); sqlite3VdbeJumpHere(v, addrTop); pLoop->wsFlags &= ~WHERE_BLOOMFILTER; - if( OptimizationDisabled(pParse->db, SQLITE_BloomPulldown) ) break; while( ++iLevel < pWInfo->nLevel ){ const SrcItem *pTabItem; pLevel = &pWInfo->a[iLevel]; @@ -172082,6 +172890,13 @@ static void whereLoopOutputAdjust( int i, j; LogEst iReduce = 0; /* pLoop->nOut should not exceed nRow-iReduce */ + /* Skip all this if the FROM clause of the query is a single table and + ** there is no ORDER BY. In this case it doesn't matter how accurate + ** the WhereLoop.nOut values are. */ + if( pWC->pWInfo->pTabList->nSrc<=1 && pWC->pWInfo->pOrderBy==0 ){ + return; + } + assert( (pLoop->wsFlags & WHERE_AUTO_INDEX)==0 ); for(i=pWC->nBase, pTerm=pWC->a; i>0; i--, pTerm++){ assert( pTerm!=0 ); @@ -172126,9 +172941,10 @@ static void whereLoopOutputAdjust( && (pTerm->wtFlags & TERM_HIGHTRUTH)==0 /* tag-20200224-1 */ ){ Expr *pRight = pOpExpr->pRight; + Parse *pParse = pWC->pWInfo->pParse; int k = 0; testcase( pOpExpr->op==TK_IS ); - if( sqlite3ExprIsInteger(pRight, &k, 0) && k>=(-1) && k<=1 ){ + if( sqlite3ExprIsInteger(pRight, &k, pParse, 1) && k>=(-1) && k<=1 ){ k = 10; }else{ k = 20; @@ -174045,7 +174861,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ if( IsVirtual(pItem->pSTab) ){ SrcItem *p; for(p=&pItem[1]; pfg.jointype & (JT_OUTER|JT_CROSS)) ){ + if( (p->fg.jointype & (JT_OUTER|JT_CROSS)) ){ mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor); } } @@ -174298,12 +175114,20 @@ static i8 wherePathSatisfiesOrderBy( if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){ Parse *pParse = pWInfo->pParse; CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pOrderBy->a[i].pExpr); - CollSeq *pColl2 = sqlite3ExprCompareCollSeq(pParse, pTerm->pExpr); + const Expr *pCExpr = pTerm->pExpr; + CollSeq *pColl2 = sqlite3ExprCompareCollSeq(pParse, pCExpr); + char affRight; assert( pColl1 ); if( pColl2==0 || sqlite3StrICmp(pColl1->zName, pColl2->zName) ){ continue; } - testcase( pTerm->pExpr->op==TK_IS ); + affRight = sqlite3ExprAffinity(pCExpr->pRight); + /* Left operand must be a column, hence always has affinity */ + assert( sqlite3ExprAffinity(pCExpr->pLeft)!=0 ); + if( affRight!=0 && affRight!=sqlite3ExprAffinity(pCExpr->pLeft) ){ + continue; /* An affinity conversion would be required */ + } + testcase( pCExpr->op==TK_IS ); } obSat |= MASKBIT(i); } @@ -175675,19 +176499,17 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful( pTab->tabFlags |= TF_MaybeReanalyze; if( i>=1 && (pLoop->wsFlags & reqFlags)==reqFlags - /* vvvvvv--- Always the case if WHERE_COLUMN_EQ is defined */ - && ALWAYS((pLoop->wsFlags & (WHERE_IPK|WHERE_INDEXED))!=0) + && sqlite3WhereLoopBloomable(pLoop) + && nSearch > pTab->nRowLogEst ){ - if( nSearch > pTab->nRowLogEst ){ - testcase( pItem->fg.jointype & JT_LEFT ); - pLoop->wsFlags |= WHERE_BLOOMFILTER; - pLoop->wsFlags &= ~WHERE_IDX_ONLY; - WHERETRACE(0xffffffff, ( - "-> 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, - (double)sqlite3LogEstToInt(pTab->nRowLogEst))); - } + testcase( pItem->fg.jointype & JT_LEFT ); + pLoop->wsFlags |= WHERE_BLOOMFILTER; + pLoop->wsFlags &= ~WHERE_IDX_ONLY; + WHERETRACE(0xffffffff, ( + "-> 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, + (double)sqlite3LogEstToInt(pTab->nRowLogEst))); } nSearch += pLoop->nOut; } @@ -176343,8 +177165,8 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( sqlite3VdbeChangeP5(v, bFordelete); } #ifdef SQLITE_ENABLE_COLUMN_USED_MASK - sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, pTabItem->iCursor, 0, 0, - (const u8*)&pTabItem->colUsed, P4_INT64); + sqlite3VdbeAddOp3(v, OP_ColumnsUsed, pTabItem->iCursor, + LOWER32(pTabItem->colUsed), UPPER32(pTabItem->colUsed)); #endif if( ii>=2 && (pTabItem[0].fg.jointype & (JT_LTORJ|JT_LEFT))==0 @@ -176421,10 +177243,15 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( if( (pTabItem->colUsed & MASKBIT(jj))==0 ) continue; colUsed |= ((u64)1)<<(ii<63 ? ii : 63); } - sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, iIndexCur, 0, 0, - (u8*)&colUsed, P4_INT64); + sqlite3VdbeAddOp3(v, OP_ColumnsUsed, iIndexCur, + LOWER32(colUsed),UPPER32(colUsed)); } #endif /* SQLITE_ENABLE_COLUMN_USED_MASK */ +#ifdef SQLITE_ENABLE_CURSOR_HINTS + if( HasRowid(pTab) ){ + sqlite3VdbeAddOp3(v, OP_CursorHint, iIndexCur, 0, pTabItem->iCursor); + } +#endif } } if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb); @@ -176432,15 +177259,15 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( && (pLevel->pRJ = sqlite3WhereMalloc(pWInfo, sizeof(WhereRightJoin)))!=0 ){ WhereRightJoin *pRJ = pLevel->pRJ; + int bBloomable = 0; pRJ->iMatch = pParse->nTab++; - pRJ->regBloom = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom); pRJ->regReturn = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, pRJ->regReturn); assert( pTab==pTabItem->pSTab ); if( HasRowid(pTab) ){ KeyInfo *pInfo; sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1); + bBloomable = 1; pInfo = sqlite3KeyInfoAlloc(pParse->db, 1, 0); if( pInfo ){ pInfo->aColl[0] = 0; @@ -176451,6 +177278,13 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( Index *pPk = sqlite3PrimaryKeyIndex(pTab); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, pPk->nKeyCol); sqlite3VdbeSetP4KeyInfo(pParse, pPk); + bBloomable = sqlite3IndexBloomable(pPk,pPk->nKeyCol); + } + if( bBloomable ){ + pRJ->regBloom = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom); + }else{ + pRJ->regBloom = 0; } pLoop->wsFlags &= ~WHERE_IDX_ONLY; /* The nature of RIGHT JOIN processing is such that it messes up @@ -176636,17 +177470,17 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ VdbeCoverageIf(v, pLevel->op==OP_Next); VdbeCoverageIf(v, pLevel->op==OP_Prev); VdbeCoverageIf(v, pLevel->op==OP_VNext); - if( pLevel->regBignull ){ - sqlite3VdbeResolveLabel(v, pLevel->addrBignull); - sqlite3VdbeAddOp2(v, OP_DecrJumpZero, pLevel->regBignull, pLevel->p2-1); - VdbeCoverage(v); - } #ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT if( addrSeek ){ sqlite3VdbeJumpHere(v, addrSeek); addrSeek = 0; } #endif + if( pLevel->regBignull ){ + sqlite3VdbeResolveLabel(v, pLevel->addrBignull); + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, pLevel->regBignull, pLevel->p2-1); + VdbeCoverage(v); + } } if( (pLoop->wsFlags & WHERE_IN_ABLE)!=0 && pLevel->u.in.nIn>0 ){ struct InLoop *pIn; @@ -176662,16 +177496,14 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 && (pLoop->wsFlags & WHERE_IN_EARLYOUT)!=0; if( pLevel->iLeftJoin ){ - /* For LEFT JOIN queries, cursor pIn->iCur may not have been - ** opened yet. This occurs for WHERE clauses such as - ** "a = ? AND b IN (...)", where the index is on (a, b). If - ** the RHS of the (a=?) is NULL, then the "b IN (...)" may - ** never have been coded, but the body of the loop run to - ** return the null-row. So, if the cursor is not open yet, - ** jump over the OP_Next or OP_Prev instruction about to - ** be coded. */ - sqlite3VdbeAddOp2(v, OP_IfNotOpen, pIn->iCur, - sqlite3VdbeCurrentAddr(v) + 2 + bEarlyOut); + /* For LEFT JOIN queries, cursor pIn->iCur might have been + ** disabled by OP_NullRow. This occurs for WHERE clauses such + ** as "a = ? AND b IN (...)", where the index is on (a, b). + ** When the OP_IfNullRow jump is taken, the pIn->iBase register + ** is NULLed out as a side effect. But as that register is not + ** used when the jump is taken, the side-effect is harmless. */ + sqlite3VdbeAddOp3(v, OP_IfNullRow, pIn->iCur, + sqlite3VdbeCurrentAddr(v) + 2 + bEarlyOut, pIn->iBase); VdbeCoverage(v); } if( bEarlyOut ){ @@ -176740,6 +177572,15 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ } sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur); } + if( ws & WHERE_IN_ABLE ){ + int m; + for(m=0; mu.in.nIn; m++){ + struct InLoop *pIn = &pLevel->u.in.aInLoop[m]; + if( pIn->eEndLoopOp!=OP_Noop ){ + sqlite3VdbeAddOp1(v, OP_NullRow, pIn->iCur); + } + } + } if( pLevel->op==OP_Return ){ sqlite3VdbeAddOp2(v, OP_Gosub, pLevel->p1, pLevel->addrFirst); }else{ @@ -177273,6 +178114,7 @@ static void percent_rankInvFunc( UNUSED_PARAMETER(nArg); assert( nArg==0 ); UNUSED_PARAMETER(apArg); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + assert( p!=0 ); p->nStep++; } static void percent_rankValueFunc(sqlite3_context *pCtx){ @@ -177318,6 +178160,7 @@ static void cume_distInvFunc( UNUSED_PARAMETER(nArg); assert( nArg==0 ); UNUSED_PARAMETER(apArg); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + assert( p!=0 ); p->nStep++; } static void cume_distValueFunc(sqlite3_context *pCtx){ @@ -177374,6 +178217,7 @@ static void ntileInvFunc( assert( nArg==1 ); UNUSED_PARAMETER(nArg); UNUSED_PARAMETER(apArg); p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + assert( p!=0 ); p->iRow++; } static void ntileValueFunc(sqlite3_context *pCtx){ @@ -177731,7 +178575,9 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){ p->pSub = sqlite3ExprListAppend(pParse, p->pSub, pDup); } if( p->pSub ){ - int f = pExpr->flags & EP_Collate; + int f = pExpr->flags & (EP_Collate|EP_OuterON|EP_InnerON); + int iJoin = pExpr->w.iJoin; + assert( ExprHasProperty(pExpr, EP_Static)==0 ); ExprSetProperty(pExpr, EP_Static); sqlite3ExprDelete(pParse->db, pExpr); @@ -177743,6 +178589,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){ pExpr->iTable = p->pWin->iEphCsr; pExpr->y.pTab = p->pTab; pExpr->flags = f; + if( (f & (EP_OuterON|EP_InnerON)) ) pExpr->w.iJoin = iJoin; } if( pParse->db->mallocFailed ) return WRC_Abort; break; @@ -177835,7 +178682,7 @@ static ExprList *exprListAppendList( int iDummy; Expr *pSub; pSub = sqlite3ExprSkipCollateAndLikely(pDup); - if( sqlite3ExprIsInteger(pSub, &iDummy, 0) ){ + if( sqlite3ExprIsInteger(pSub, &iDummy, 0, 0) ){ pSub->op = TK_NULL; pSub->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse); pSub->u.zToken = 0; @@ -184314,6 +185161,7 @@ static YYACTIONTYPE yy_reduce( SrcItem *pOld = yymsp[-3].minor.yy203->a; assert( pOld->fg.fixedSchema==0 ); pNew->zName = pOld->zName; + pOld->zName = 0; assert( pOld->fg.fixedSchema==0 ); if( pOld->fg.isSubquery ){ pNew->fg.isSubquery = 1; @@ -184333,8 +185181,13 @@ static YYACTIONTYPE yy_reduce( pOld->u1.pFuncArg = 0; pOld->fg.isTabFunc = 0; pNew->fg.isTabFunc = 1; + }else if( pOld->fg.isIndexedBy ){ + pNew->u1.zIndexedBy = pOld->u1.zIndexedBy; + pOld->u1.zIndexedBy = 0; + pOld->fg.isIndexedBy = 0; + pNew->fg.isIndexedBy = 1; } - pOld->zName = 0; + pNew->fg.notIndexed = pOld->fg.notIndexed; } sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy203); }else{ @@ -184847,7 +185700,11 @@ static YYACTIONTYPE yy_reduce( } }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 ){ + if( yymsp[-1].minor.yy14->nExpr==1 + && sqlite3ExprIsConstant(pParse,pRHS) + && pRHS->op!=TK_COLLATE + && yymsp[-4].minor.yy454->op!=TK_VECTOR + ){ yymsp[-1].minor.yy14->a[0].pExpr = 0; sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14); pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0); @@ -187218,15 +188075,55 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[]; #endif /* -** Return TRUE if the given SQL string ends in a semicolon. +** Return zero if the given SQL string is complete - if all comments, +** string and blob literals, and quoted identifiers have been closed and +** if the entire string ends with ";" and possibly with ";END;" if the +** string is a CREATE TRIGGER statement. A non-zero return indicates +** that the string is empty or incomplete. Bits of the return value +** indicate what is missing and is needed to close out the statement. ** ** Special handling is require for CREATE TRIGGER statements. ** Whenever the CREATE TRIGGER keywords are seen, the statement ** must end with ";END;". ** +** Let the return code be a value R. R is split up into various +** subfields, at byte boundaries: +** +** R = 0xwwwwwwww00xxyyzz +** +** In other words, zz is the least significant byte, yy is the next +** most significant byte, xx is the third byte, wwwwwwww is the upper +** four bytes of the return value. +** +** zz == SQLITE_OK Input is complete +** zz == SQLITE_ERROR Input is incomplete +** zz == SQLITE_EMPTY Input contains only whitespace +** zz == SQLITE_MISUSE Input is a NULL pointer +** zz != 0 New values for zz may be added in the future +** +** yy == 0x01 Need a semicolon at the end +** yy == 0x02 Need "END" and a semicolon +** yy == 0x03 Need semicolon, "END", and semicolon +** yy != 0 New values for yy may be added in the future +** +** xx == '\'' Incomplete string or blob literal +** xx == '"' Incomplete quoted identifier +** xx == '`' Incompelte MySQL-style quoted identifier +** xx == ']' Incomplete SQLServer-style quoted identifer +** xx == '-' Incomplete SQL-style comment +** xx == '/' Incomplete C-style comment +** xx != 0 New values of xx may be added in the future +** +** wwwwwwww Interpret as a signed integer, the number +** of unmatched "(". Negative means there are +** more ")" and "(". +** +** ((R>>24)&0xff)!=0 New uses for the 4th byte may be added +** in the future +** ** This implementation uses a state machine with 8 states: ** -** (0) INVALID We have not yet seen a non-whitespace character. +** (0) NOTHING We have not yet seen a non-whitespace character. ** ** (1) START At the beginning or end of an SQL statement. This routine ** returns 1 if it ends in the START state and 0 if it ends @@ -187270,9 +188167,11 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[]; ** to recognize the end of a trigger can be omitted. All we have to do ** is look for a semicolon that is not part of an string or comment. */ -SQLITE_API int sqlite3_complete(const char *zSql){ +SQLITE_API sqlite3_int64 sqlite3_incomplete(const char *zSql){ u8 state = 0; /* Current state, using numbers defined in header comment */ u8 token; /* Value of the next token */ + u8 pending = 0; /* unmatched structure character */ + int nParen = 0; /* Nested parentheses */ #ifndef SQLITE_OMIT_TRIGGER /* A complex statement machine used to detect the end of a CREATE TRIGGER @@ -187281,7 +188180,7 @@ SQLITE_API int sqlite3_complete(const char *zSql){ static const u8 trans[8][8] = { /* Token: */ /* State: ** SEMI WS OTHER EXPLAIN CREATE TEMP TRIGGER END */ - /* 0 INVALID: */ { 1, 0, 2, 3, 4, 2, 2, 2, }, + /* 0 NOTHING: */ { 1, 0, 2, 3, 4, 2, 2, 2, }, /* 1 START: */ { 1, 1, 2, 3, 4, 2, 2, 2, }, /* 2 NORMAL: */ { 1, 2, 2, 2, 2, 2, 2, 2, }, /* 3 EXPLAIN: */ { 1, 3, 3, 2, 4, 2, 2, 2, }, @@ -187297,16 +188196,26 @@ SQLITE_API int sqlite3_complete(const char *zSql){ static const u8 trans[3][3] = { /* Token: */ /* State: ** SEMI WS OTHER */ - /* 0 INVALID: */ { 1, 0, 2, }, + /* 0 NOTHING: */ { 1, 0, 2, }, /* 1 START: */ { 1, 1, 2, }, /* 2 NORMAL: */ { 1, 2, 2, }, }; #endif /* SQLITE_OMIT_TRIGGER */ + /* Mapping state number to yy value for the return */ + static const u8 statemap[8] = { + /* 0 NOTHING */ 0, + /* 1 START */ 0, + /* 2 NORMAL */ 1, + /* 3 EXPLAIN */ 1, + /* 4 CREATE */ 1, + /* 5 TRIGGER */ 3, + /* 6 SEMI */ 2, + /* 7 END */ 1, + }; #ifdef SQLITE_ENABLE_API_ARMOR if( zSql==0 ){ - (void)SQLITE_MISUSE_BKPT; - return 0; + return SQLITE_MISUSE_BKPT; } #endif @@ -187331,7 +188240,10 @@ SQLITE_API int sqlite3_complete(const char *zSql){ } zSql += 2; while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; } - if( zSql[0]==0 ) return 0; + if( zSql[0]==0 ){ + pending = '/'; + goto incomplete_finish; + } zSql++; token = tkWS; break; @@ -187342,14 +188254,20 @@ SQLITE_API int sqlite3_complete(const char *zSql){ break; } while( *zSql && *zSql!='\n' ){ zSql++; } - if( *zSql==0 ) return state==1; + if( *zSql==0 ){ + pending = '-'; + goto incomplete_finish; + } token = tkWS; break; } case '[': { /* Microsoft-style identifiers in [...] */ zSql++; while( *zSql && *zSql!=']' ){ zSql++; } - if( *zSql==0 ) return 0; + if( *zSql==0 ){ + pending = ']'; + goto incomplete_finish; + } token = tkOTHER; break; } @@ -187359,7 +188277,20 @@ SQLITE_API int sqlite3_complete(const char *zSql){ int c = *zSql; zSql++; while( *zSql && *zSql!=c ){ zSql++; } - if( *zSql==0 ) return 0; + if( *zSql==0 ){ + pending = c; + goto incomplete_finish; + } + token = tkOTHER; + break; + } + case '(': { + nParen++; + token = tkOTHER; + break; + } + case ')': { + nParen--; token = tkOTHER; break; } @@ -187426,7 +188357,16 @@ SQLITE_API int sqlite3_complete(const char *zSql){ state = trans[state][token]; zSql++; } - return state==1; +incomplete_finish: + if( state==0 && pending==0 ) return SQLITE_EMPTY; + if( state==1 ) nParen = 0; + return (i64)((((u64)nParen)<<32) | + ((u64)pending<<16) | + ((u64)statemap[state]<<8) | + (state>1 || pending!=0)); +} +SQLITE_API int sqlite3_complete(const char *zSql){ + return sqlite3_incomplete(zSql)==0; } #ifndef SQLITE_OMIT_UTF16 @@ -187448,7 +188388,7 @@ SQLITE_API int sqlite3_complete16(const void *zSql){ sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC); zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8); if( zSql8 ){ - rc = sqlite3_complete(zSql8); + rc = sqlite3_incomplete(zSql8)==0; }else{ rc = SQLITE_NOMEM_BKPT; } @@ -187716,17 +188656,29 @@ SQLITE_API char *sqlite3_data_directory = 0; /* ** Initialize SQLite. ** -** This routine must be called to initialize the memory allocation, -** VFS, and mutex subsystems prior to doing any serious work with -** SQLite. But as long as you do not compile with SQLITE_OMIT_AUTOINIT +** The sqlite3_initialize() routine must be called to initialize the +** memory allocation, VFS, and mutex subsystems prior to doing any +** serious work. As long as you do not compile with SQLITE_OMIT_AUTOINIT ** this routine will be called automatically by key routines such as ** sqlite3_open(). ** ** This routine is a no-op except on its very first call for the process, -** or for the first call after a call to sqlite3_shutdown. +** or for the first call after a call to sqlite3_shutdown. Most calls +** to sqlite3_initialize() are, in fact, no-ops. For that reason, the +** routine is broken into two pieces: +** +** sqlite3Initialize() Does the actual work of initialization ** -** The first thread to call this routine runs the initialization to -** completion. If subsequent threads call this routine before the first +** sqlite3_initialize() Checks to see if initialization is needed +** and invokes sqlite3Initialize() if it is. +** +** The sqlite3_initialize() interface is called frequently, but +** sqlite3Initialize() runs rarely. The function is broken up this way +** to avoid wasting CPU cycles with unnecessary stack setup for local +** variables in cases where it is not needed. +** +** The first thread to call sqlite3_initialize() runs the initialization to +** completion. If subsequent threads call sqlite3_initialize() before the first ** thread has finished the initialization process, then the subsequent ** threads must block until the first thread finishes with the initialization. ** @@ -187734,44 +188686,29 @@ SQLITE_API char *sqlite3_data_directory = 0; ** calls to this routine should not block, of course. Otherwise the ** initialization process would never complete. ** -** Let X be the first thread to enter this routine. Let Y be some other -** thread. Then while the initial invocation of this routine by X is -** incomplete, it is required that: +** Let X be the first thread to enter sqlite3_initialize(). Let Y be some +** other thread. While the initial invocation of sqlite3_initialize() by X +** is incomplete, it is required that: ** -** * Calls to this routine from Y must block until the outer-most +** * Calls to sqlite3_initialize() from Y must block until the outer-most ** call by X completes. ** -** * Recursive calls to this routine from thread X return immediately -** without blocking. +** * Recursive calls to sqlite3_initialize() from thread X return +** immediately without blocking. */ -SQLITE_API int sqlite3_initialize(void){ - MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) /* The main static mutex */ - int rc; /* Result code */ +static SQLITE_NOINLINE int sqlite3Initialize(void){ + MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) /* The main static mutex */ + int rc; /* Result code */ #ifdef SQLITE_EXTRA_INIT - int bRunExtraInit = 0; /* Extra initialization needed */ -#endif - -#ifdef SQLITE_OMIT_WSD - rc = sqlite3_wsd_init(4096, 24); - if( rc!=SQLITE_OK ){ - return rc; - } + int bRunExtraInit = 0; /* Extra initialization needed */ #endif /* If the following assert() fails on some obscure processor/compiler - ** combination, the work-around is to set the correct pointer - ** size at compile-time using -DSQLITE_PTRSIZE=n compile-time option */ - assert( SQLITE_PTRSIZE==sizeof(char*) ); - - /* If SQLite is already completely initialized, then this call - ** to sqlite3_initialize() should be a no-op. But the initialization - ** must be complete. So isInit must not be set until the very end - ** of this routine. + ** combination to warn that SQLite has been mis-compiled. If you hit + ** this assert(), that means you need to recompile with the + ** -DSQLITE_PTRSIZE=n compile-time option to set the correct pointer size. */ - if( sqlite3GlobalConfig.isInit ){ - sqlite3MemoryBarrier(); - return SQLITE_OK; - } + assert( SQLITE_PTRSIZE==sizeof(char*) ); /* Make sure the mutex subsystem is initialized. If unable to ** initialize the mutex subsystem, return early with the error. @@ -187919,6 +188856,26 @@ SQLITE_API int sqlite3_initialize(void){ #endif return rc; } +SQLITE_API int sqlite3_initialize(void){ + /* If this build does not support writable static data (WSD) natively + ** then we have to invoke the (application-supplied) WSD initialization + ** routine before doing anything else. */ +#ifdef SQLITE_OMIT_WSD + int rc = sqlite3_wsd_init(4096, 24); + if( rc!=SQLITE_OK ){ + return rc; + } +#endif + + if( sqlite3GlobalConfig.isInit ){ + /* SQLite has already been initialized. Fast early-out. */ + sqlite3MemoryBarrier(); + return SQLITE_OK; + }else{ + /* Invoke sqlite3Initialize() to do the actual work. */ + return sqlite3Initialize(); + } +} /* ** Undo the effects of sqlite3_initialize(). Must not be called while @@ -188079,7 +189036,7 @@ SQLITE_API int sqlite3_config(int op, ...){ break; } case SQLITE_CONFIG_SMALL_MALLOC: { - sqlite3GlobalConfig.bSmallMalloc = va_arg(ap, int); + sqlite3GlobalConfig.bSmallMalloc = va_arg(ap, int)!=0; break; } case SQLITE_CONFIG_PAGECACHE: { @@ -188602,7 +189559,7 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ ** This is the default collating function named "BINARY" which is always ** available. */ -static int binCollFunc( +SQLITE_PRIVATE int sqlite3BinaryCompare( void *NotUsed, int nKey1, const void *pKey1, int nKey2, const void *pKey2 @@ -188634,16 +189591,19 @@ static int rtrimCollFunc( const u8 *pK2 = (const u8*)pKey2; while( nKey1 && pK1[nKey1-1]==' ' ) nKey1--; while( nKey2 && pK2[nKey2-1]==' ' ) nKey2--; - return binCollFunc(pUser, nKey1, pKey1, nKey2, pKey2); + return sqlite3BinaryCompare(pUser, nKey1, pKey1, nKey2, pKey2); } /* ** Return true if CollSeq is the default built-in BINARY. */ +#if !SQLITE_USES_INLINE SQLITE_PRIVATE int sqlite3IsBinary(const CollSeq *p){ - assert( p==0 || p->xCmp!=binCollFunc || strcmp(p->zName,"BINARY")==0 ); - return p==0 || p->xCmp==binCollFunc; + assert( p==0 || p->xCmp!=sqlite3BinaryCompare + || strcmp(p->zName,"BINARY")==0 ); + return p==0 || p->xCmp==sqlite3BinaryCompare; } +#endif /* ** Another built-in collating sequence: NOCASE. @@ -188701,7 +189661,8 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid) } /* -** Return the number of changes in the most recent call to sqlite3_exec(). +** Return the number of changes in the most recently executed DML +** statement. */ SQLITE_API sqlite3_int64 sqlite3_changes64(sqlite3 *db){ i64 iRet; @@ -189594,7 +190555,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc( if( db->nVdbeActive ){ sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to delete/modify user-function due to active statements"); - assert( !db->mallocFailed ); + assert( !db->mallocFailed || db->nVdbeExec>0 ); return SQLITE_BUSY; }else{ sqlite3ExpirePreparedStatements(db, 0); @@ -190535,6 +191496,8 @@ static const int aHardLimit[] = { SQLITE_MAX_TRIGGER_DEPTH, SQLITE_MAX_WORKER_THREADS, SQLITE_MAX_PARSER_DEPTH, + SQLITE_MAX_SCHEMA, + SQLITE_MAX_TRIGGER_STEPS, }; /* @@ -190576,6 +191539,9 @@ static const int aHardLimit[] = { #if SQLITE_MAX_WORKER_THREADS<0 || SQLITE_MAX_WORKER_THREADS>50 # error SQLITE_MAX_WORKER_THREADS must be between 0 and 50 #endif +#if SQLITE_MAX_TRIGGER_STEPS<0 || SQLITE_MAX_TRIGGER_STEPS>65535 +# error SQLITE_MAX_TRIGGER_STEPS must be between 0 and 65535 +#endif /* @@ -190617,7 +191583,9 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ assert( aHardLimit[SQLITE_LIMIT_VARIABLE_NUMBER]==SQLITE_MAX_VARIABLE_NUMBER); assert( aHardLimit[SQLITE_LIMIT_TRIGGER_DEPTH]==SQLITE_MAX_TRIGGER_DEPTH ); assert( aHardLimit[SQLITE_LIMIT_WORKER_THREADS]==SQLITE_MAX_WORKER_THREADS ); - assert( SQLITE_LIMIT_PARSER_DEPTH==(SQLITE_N_LIMIT-1) ); + assert( aHardLimit[SQLITE_LIMIT_SCHEMA]==SQLITE_MAX_SCHEMA ); + assert( aHardLimit[SQLITE_LIMIT_TRIGGER_STEPS]==SQLITE_MAX_TRIGGER_STEPS ); + assert( SQLITE_LIMIT_TRIGGER_STEPS==(SQLITE_N_LIMIT-1) ); if( limitId<0 || limitId>=SQLITE_N_LIMIT ){ @@ -191112,9 +192080,12 @@ static int openDatabase( ** EVIDENCE-OF: R-52786-44878 SQLite defines three built-in collating ** functions: */ - createCollation(db, sqlite3StrBINARY, SQLITE_UTF8, 0, binCollFunc, 0); - createCollation(db, sqlite3StrBINARY, SQLITE_UTF16BE, 0, binCollFunc, 0); - createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, binCollFunc, 0); + createCollation(db, sqlite3StrBINARY, SQLITE_UTF8, 0, + sqlite3BinaryCompare, 0); + createCollation(db, sqlite3StrBINARY, SQLITE_UTF16BE, 0, + sqlite3BinaryCompare, 0); + createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, + sqlite3BinaryCompare, 0); createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0); createCollation(db, "RTRIM", SQLITE_UTF8, 0, rtrimCollFunc, 0); if( db->mallocFailed ){ @@ -195265,7 +196236,10 @@ static int fts3ContentColumns( ** nul-terminator byte. */ nCol = sqlite3_column_count(pStmt); for(i=0; ibase.pVtab; switch( nVal ){ - case 6: nToken = sqlite3_value_int(apVal[5]); + case 6: nToken = sqlite3_value_int64(apVal[5]); /* no break */ deliberate_fall_through - case 5: iCol = sqlite3_value_int(apVal[4]); + case 5: iCol = sqlite3_value_int64(apVal[4]); /* no break */ deliberate_fall_through case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]); /* no break */ deliberate_fall_through @@ -197886,9 +198863,12 @@ static void fts3SnippetFunc( } if( !zEllipsis || !zEnd || !zStart ){ sqlite3_result_error_nomem(pContext); - }else if( nToken==0 ){ + }else if( nToken==0 || iCol>=pTab->nColumn ){ sqlite3_result_text(pContext, "", -1, SQLITE_STATIC); }else if( SQLITE_OK==fts3CursorSeek(pContext, pCsr) ){ + if( iCol<0 ) iCol = -1; + if( nToken<-64 ) nToken = -64; + if( nToken>64 ) nToken = 64; sqlite3Fts3Snippet(pContext, pCsr, zStart, zEnd, zEllipsis, iCol, nToken); } } @@ -200500,6 +201480,14 @@ static int fts3auxDisconnectMethod(sqlite3_vtab *pVtab){ #define FTS4AUX_GE_CONSTRAINT 2 #define FTS4AUX_LE_CONSTRAINT 4 +/* +** Return true if constraint iCons of pInfo uses the "binary" collation +** sequence. Or false it it uses anything else. +*/ +static int fts3auxIsBinary(sqlite3_index_info *pInfo, int iCons){ + return 0==sqlite3_stricmp("binary", sqlite3_vtab_collation(pInfo, iCons)); +} + /* ** xBestIndex - Analyze a WHERE and ORDER BY clause. */ @@ -200527,7 +201515,7 @@ static int fts3auxBestIndexMethod( /* Search for equality and range constraints on the "term" column. ** And equality constraints on the hidden "languageid" column. */ for(i=0; inConstraint; i++){ - if( pInfo->aConstraint[i].usable ){ + if( pInfo->aConstraint[i].usable && fts3auxIsBinary(pInfo, i) ){ int op = pInfo->aConstraint[i].op; int iCol = pInfo->aConstraint[i].iColumn; @@ -200698,7 +201686,7 @@ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){ /* State 3. The integer just read is a column number. */ default: assert( eState==3 ); iCol = (int)v; - if( iCol<1 || iCol>(pFts3->nColumn+1) ){ + if( iCol<1 || iCol>32767 ){ rc = SQLITE_CORRUPT_VTAB; break; } @@ -200773,7 +201761,7 @@ static int fts3auxFilterMethod( pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY; if( isScan ) pCsr->filter.flags |= FTS3_SEGMENT_SCAN; - if( iEq>=0 || iGe>=0 ){ + if( (iEq>=0 || iGe>=0) && sqlite3_value_type(apVal[0])==SQLITE_TEXT ){ const unsigned char *zStr = sqlite3_value_text(apVal[0]); assert( (iEq==0 && iGe==-1) || (iEq==-1 && iGe==0) ); if( zStr ){ @@ -200783,7 +201771,7 @@ static int fts3auxFilterMethod( } } - if( iLe>=0 ){ + if( iLe>=0 && sqlite3_value_type(apVal[0])==SQLITE_TEXT ){ pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iLe])); if( pCsr->zStop==0 ) return SQLITE_NOMEM; pCsr->nStop = (int)strlen(pCsr->zStop); @@ -201466,7 +202454,7 @@ static int getNextNode( iColLen = 0; for(ii=0; iinCol; ii++){ const char *zStr = pParse->azCol[ii]; - int nStr = (int)strlen(zStr); + int nStr = zStr ? (int)strlen(zStr) : 0; if( nInput>nStr && zInput[nStr]==':' && sqlite3_strnicmp(zStr, zInput, nStr)==0 ){ @@ -202181,7 +203169,9 @@ static void fts3ExprTestCommon( ); } - if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ + if( rc==SQLITE_OK && fts3ExprCheckDepth(pExpr, SQLITE_FTS3_MAX_EXPR_DEPTH) ){ + sqlite3_result_error(context, "Expression nested too deep", -1); + }else if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ sqlite3_result_error(context, "Error parsing expression", -1); }else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){ sqlite3_result_error_nomem(context); @@ -203242,10 +204232,11 @@ static int porterNext( if( c->iOffset>iStartOffset ){ int n = c->iOffset-iStartOffset; if( n>c->nAllocated ){ + i64 nNew = n + 20; char *pNew; - c->nAllocated = n+20; - pNew = sqlite3_realloc64(c->zToken, c->nAllocated); + pNew = sqlite3_realloc64(c->zToken, nNew); if( !pNew ) return SQLITE_NOMEM; + c->nAllocated = (int)nNew; c->zToken = pNew; } porter_stemmer(&z[iStartOffset], n, c->zToken, pnBytes); @@ -209773,38 +210764,42 @@ static u64 fts3ChecksumIndex( rc = sqlite3Fts3SegReaderStart(p, &csr, &filter); } - if( rc==SQLITE_OK ){ - while( SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, &csr)) ){ - char *pCsr = csr.aDoclist; - char *pEnd = &pCsr[csr.nDoclist]; + while( rc==SQLITE_OK && SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p,&csr)) ){ + char *pCsr = csr.aDoclist; + char *pEnd = &pCsr[csr.nDoclist]; - i64 iDocid = 0; - i64 iCol = 0; - u64 iPos = 0; + i64 iDocid = 0; + int iCol = 0; + u64 iPos = 0; - pCsr += sqlite3Fts3GetVarint(pCsr, &iDocid); - while( pCsrbDescIdx ){ + iDocid = (i64)((u64)iDocid - iVal); }else{ - pCsr += sqlite3Fts3GetVarintU(pCsr, &iVal); - if( p->bDescIdx ){ - iDocid = (i64)((u64)iDocid - iVal); - }else{ - iDocid = (i64)((u64)iDocid + iVal); - } + iDocid = (i64)((u64)iDocid + iVal); } + } + }else{ + iPos += (iVal - 2); + if( iPos>0x7FFFFFFF ){ + rc = SQLITE_CORRUPT_VTAB; + break; }else{ - iPos += (iVal - 2); cksum = cksum ^ fts3ChecksumEntry( csr.zTerm, csr.nTerm, iLangid, iIndex, iDocid, - (int)iCol, (int)iPos + iCol, (int)iPos ); } } @@ -209831,6 +210826,7 @@ SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk){ u64 cksum1 = 0; /* Checksum based on FTS index contents */ u64 cksum2 = 0; /* Checksum based on %_content contents */ sqlite3_stmt *pAllLangid = 0; /* Statement to return all language-ids */ + int bContentless = (p->zContentTbl && p->zContentTbl[0]=='\0'); /* This block calculates the checksum according to the FTS index. */ rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0); @@ -209850,7 +210846,7 @@ SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk){ } /* This block calculates the checksum according to the %_content table */ - if( rc==SQLITE_OK ){ + if( rc==SQLITE_OK && !bContentless ){ sqlite3_tokenizer_module const *pModule = p->pTokenizer->pModule; sqlite3_stmt *pStmt = 0; char *zSql; @@ -209908,7 +210904,7 @@ SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk){ rc = SQLITE_OK; *pbOk = 0; }else{ - *pbOk = (rc==SQLITE_OK && cksum1==cksum2); + *pbOk = (rc==SQLITE_OK && (bContentless || cksum1==cksum2)); } return rc; } @@ -210501,10 +211497,9 @@ struct StrBuffer { /* ** Allocate a two-slot MatchinfoBuffer object. */ -static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){ +static MatchinfoBuffer *fts3MIBufferNew(i64 nElem, const char *zMatchinfo){ MatchinfoBuffer *pRet; - sqlite3_int64 nByte = sizeof(u32) * (2*(sqlite3_int64)nElem + 1) - + SZ_MATCHINFOBUFFER(1); + sqlite3_int64 nByte = sizeof(u32) * (2*(i64)nElem+1) + SZ_MATCHINFOBUFFER(1); sqlite3_int64 nStr = strlen(zMatchinfo); pRet = sqlite3Fts3MallocZero(nByte + nStr+1); @@ -210898,6 +211893,7 @@ static int fts3BestSnippet( sqlite3_int64 nByte; /* Number of bytes of space to allocate */ int iBestScore = -1; /* Best snippet score found so far */ int i; /* Loop counter */ + Fts3Expr *pExpr = pCsr->pExpr; memset(&sIter, 0, sizeof(sIter)); @@ -210926,9 +211922,12 @@ static int fts3BestSnippet( sIter.nSnippet = nSnippet; sIter.nPhrase = nList; sIter.iCurrent = -1; - rc = sqlite3Fts3ExprIterate( - pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter - ); + rc = sqlite3Fts3ExprIterate(pExpr, fts3SnippetFindPositions, (void*)&sIter); + if( rc==SQLITE_OK ){ + /* Iterate through the expression twice, in case pointers garnered during + ** the first iteration are invalidated by a call to fts5EvalRestart(). */ + rc = sqlite3Fts3ExprIterate(pExpr, fts3SnippetFindPositions, (void*)&sIter); + } if( rc==SQLITE_OK ){ /* Set the *pmSeen output variable. */ @@ -211375,8 +212374,8 @@ static int fts3MatchinfoCheck( return SQLITE_ERROR; } -static size_t fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ - size_t nVal; /* Number of integers output by cArg */ +static i64 fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ + i64 nVal; /* Number of integers output by cArg */ switch( cArg ){ case FTS3_MATCHINFO_NDOC: @@ -211392,16 +212391,16 @@ static size_t fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ break; case FTS3_MATCHINFO_LHITS: - nVal = (size_t)pInfo->nCol * pInfo->nPhrase; + nVal = (i64)pInfo->nCol * pInfo->nPhrase; break; case FTS3_MATCHINFO_LHITS_BM: - nVal = (size_t)pInfo->nPhrase * ((pInfo->nCol + 31) / 32); + nVal = (i64)pInfo->nPhrase * ((pInfo->nCol + 31) / 32); break; default: assert( cArg==FTS3_MATCHINFO_HITS ); - nVal = (size_t)pInfo->nCol * pInfo->nPhrase * 3; + nVal = (i64)pInfo->nCol * pInfo->nPhrase * 3; break; } @@ -211683,7 +212682,7 @@ static int fts3MatchinfoValues( case FTS3_MATCHINFO_LHITS_BM: case FTS3_MATCHINFO_LHITS: { - size_t nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32); + i64 nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32); memset(pInfo->aMatchinfo, 0, nZero); rc = fts3ExprLHitGather(pCsr->pExpr, pInfo); break; @@ -211752,7 +212751,7 @@ static void fts3GetMatchinfo( ** initialize those elements that are constant for every row. */ if( pCsr->pMIBuffer==0 ){ - size_t nMatchinfo = 0; /* Number of u32 elements in match-info */ + i64 nMatchinfo = 0; /* Number of u32 elements in match-info */ int i; /* Used to iterate through zArg */ /* Determine the number of phrases in the query */ @@ -211837,9 +212836,8 @@ SQLITE_PRIVATE void sqlite3Fts3Snippet( return; } - /* Limit the snippet length to 64 tokens. */ - if( nToken<-64 ) nToken = -64; - if( nToken>+64 ) nToken = +64; + /* The snippet length should already have been limited to 64 tokens. */ + assert( nToken>=-64 && nToken<=64 ); for(nSnippet=1; 1; nSnippet++){ @@ -214086,7 +215084,7 @@ static void jsonWrongNumArgs( ** ** Return the number of errors. */ -static int jsonBlobExpand(JsonParse *pParse, u32 N){ +static int jsonBlobExpand(JsonParse *pParse, u64 N){ u8 *aNew; u64 t; assert( N>pParse->nBlobAlloc ); @@ -214114,7 +215112,7 @@ static int jsonBlobExpand(JsonParse *pParse, u32 N){ */ static int jsonBlobMakeEditable(JsonParse *pParse, u32 nExtra){ u8 *aOld; - u32 nSize; + u64 nSize; assert( !pParse->bReadOnly ); if( pParse->oom ) return 0; if( pParse->nBlobAlloc>0 ) return 1; @@ -214135,7 +215133,7 @@ static SQLITE_NOINLINE void jsonBlobExpandAndAppendOneByte( JsonParse *pParse, u8 c ){ - jsonBlobExpand(pParse, pParse->nBlob+1); + jsonBlobExpand(pParse, (u64)pParse->nBlob+1); if( pParse->oom==0 ){ assert( pParse->nBlob+1<=pParse->nBlobAlloc ); pParse->aBlob[pParse->nBlob++] = c; @@ -214162,7 +215160,7 @@ static SQLITE_NOINLINE void jsonBlobExpandAndAppendNode( u64 szPayload, const void *aPayload ){ - if( jsonBlobExpand(pParse, pParse->nBlob+szPayload+9) ) return; + if( jsonBlobExpand(pParse, (u64)pParse->nBlob+(u64)szPayload+9) ) return; jsonBlobAppendNode(pParse, eType, szPayload, aPayload); } @@ -214252,7 +215250,7 @@ static int jsonBlobChangePayloadSize( } delta = nNeeded - nExtra; if( delta ){ - u32 newSize = pParse->nBlob + delta; + u64 newSize = (u64)pParse->nBlob + delta; if( delta>0 ){ if( newSize>pParse->nBlobAlloc && jsonBlobExpand(pParse, newSize) ){ return 0; /* OOM error. Error state recorded in pParse->oom. */ @@ -215051,12 +216049,125 @@ static void jsonReturnStringAsBlob(JsonString *pStr){ } } -/* The byte at index i is a node type-code. This routine +/* +** This a helper routine for jsonbPayloadSize() and +** jsonbPayloadSizeSemiInline(). This routine is called using tail +** recursion to handle the (relatively uncommon) cases where the +** the payload size is a 2, 4, or 8 byte integer. +*/ +static u32 jsonbPayloadSizeWide( + const JsonParse *pParse, /* JSON parsing context */ + u32 i, /* Index of the node type-code */ + u32 *pSz, /* Write payload size here */ + u8 x /* pParse->aBlob[i]>>4 */ +){ + u32 sz; + u32 n; + assert( inBlob ); + assert( x==(pParse->aBlob[i]>>4) ); + assert( x>=13 ); + 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 = ((u32)pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) + + (pParse->aBlob[i+7]<<8) + pParse->aBlob[i+8]; + n = 9; + } + testcase( (i64)i+sz+n > pParse->nBlob ); + testcase( (i64)i+sz+n > pParse->nBlob-pParse->delta + && (i64)i+sz+n > pParse->nBlob ); + testcase( pParse->delta>0 ); + testcase( pParse->delta<0 ); + /* Quirks with -Os and gcov cause the NO_TEST line below to show up as + ** false-positive coverage miss. The testcases() macros above are + ** sufficient to prove that the branch is in fact covered */ + if( (i64)i+sz+n > pParse->nBlob + && (i64)i+sz+n > pParse->nBlob-pParse->delta /*NO_TEST*/ + ){ + *pSz = 0; + return 0; + } + *pSz = sz; + return n; +} + +/* +** This is the main routine for determining the size of a node in JSONB. +** The jsonbPayloadSizeWide() above is a helper. The two routines +** jsonbPayloadSizeInline() and jsonbPayloadSizeSemiInline() below are +** optional optimizations. It is important to keep all these routines in +** sync. Agents reading this code: Help us humans to remember that! +** +** The byte at index i is a node type-code. This routine ** determines the payload size for that node and writes that ** payload size in to *pSz. It returns the offset from i to the ** beginning of the payload. Return 0 on error. */ -static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){ +static u32 jsonbPayloadSize( + const JsonParse *pParse, /* JSON parsing context */ + u32 i, /* Index of the node type-code */ + u32 *pSz /* Write payload size here */ +){ + u8 x; + u32 sz; + u32 n; + if( i>=pParse->nBlob ){ + *pSz = 0; + return 0; + }else if( (x = pParse->aBlob[i]>>4)<=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{ + return jsonbPayloadSizeWide(pParse, i, pSz, x); + } + if( (i64)i+sz+n > pParse->nBlob + && (i64)i+sz+n > pParse->nBlob-pParse->delta + ){ + *pSz = 0; + return 0; + } + *pSz = sz; + return n; +} + +#if SQLITE_USES_INLINE +/* A separate inline version of jsonbPayloadSize(), used in one particulary +** performance-critical place. +*/ +static SQLITE_INLINE u32 jsonbPayloadSizeInline( + const JsonParse *pParse, /* JSON parsing context */ + u32 i, /* Index of the node type-code */ + u32 *pSz /* Write payload size here */ +){ u8 x; u32 sz; u32 n; @@ -215111,8 +216222,62 @@ static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){ *pSz = sz; return n; } +#else /* if !SQLITE_USES_INLINE */ + /* On compilers that do not support in-lining, just call the original + ** jsonbPayloadSize(). It's slower, but it gets the right answer. */ +# define jsonbPayloadSizeInline(a,b,c) jsonbPayloadSize(a,b,c) +#endif +#if SQLITE_USES_INLINE +/* A separate inline version of jsonbPayloadSize() that implements the more +** common paths inline but then calls out to a subroutine for the uncommon +** paths. +** +** * It is guaranteed that the i parameter is a valid index for +** pParse->aBlob[]. There is no possibility of running of the end +** of the allocation. +** +** * Large sizes (greater than 255) are uncommon and are handled +** by a subroutine call to the jsonbPayloadSizeWide(). +*/ +static SQLITE_INLINE u32 jsonbPayloadSizeSemiInline( + const JsonParse *pParse, /* JSON parsing context */ + u32 i, /* Index of the node type-code */ + u32 *pSz /* Write payload size here */ +){ + u8 x; + u32 sz; + u32 n; + assert( inBlob ); + if( (x = pParse->aBlob[i]>>4)<=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{ + return jsonbPayloadSizeWide(pParse,i,pSz,x); + } + if( (i64)i+sz+n > pParse->nBlob + && (i64)i+sz+n > pParse->nBlob-pParse->delta + ){ + *pSz = 0; + return 0; + } + *pSz = sz; + return n; +} +#else /* if !SQLITE_USES_INLINE */ + /* On compilers that do not support in-lining, just call the original + ** jsonbPayloadSize(). It's slower, but it gets the right answer. */ +# define jsonbPayloadSizeSemiInline(a,b,c) jsonbPayloadSize(a,b,c) +#endif + /* ** Translate the binary JSONB representation of JSON beginning at ** pParse->aBlob[i] into a JSON text string. Append the JSON @@ -215133,7 +216298,7 @@ static u32 jsonTranslateBlobToText( ){ u32 sz, n, j, iEnd; - n = jsonbPayloadSize(pParse, i, &sz); + n = jsonbPayloadSizeInline(pParse, i, &sz); if( n==0 ){ pOut->eErr |= JSTRING_MALFORMED; return pParse->nBlob+1; @@ -215278,7 +216443,7 @@ static u32 jsonTranslateBlobToText( 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. + ** whitespace. Note 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] @@ -215413,7 +216578,10 @@ static u32 jsonTranslateBlobToPrettyText( while( pOut->eErr==0 ){ jsonPrettyIndent(pPretty); j = jsonTranslateBlobToPrettyText(pPretty, j); - if( j>=iEnd ) break; + if( j>=iEnd ){ + if( j>iEnd ) pOut->eErr |= JSTRING_MALFORMED; + break; + } jsonAppendRawNZ(pOut, ",\n", 2); } jsonAppendChar(pOut, '\n'); @@ -215473,7 +216641,7 @@ static u32 jsonbArrayCount(JsonParse *pParse, u32 iRoot){ n = jsonbPayloadSize(pParse, iRoot, &sz); iEnd = iRoot+n+sz; for(i=iRoot+n; n>0 && inBlob + d > pParse->nBlobAlloc ){ - jsonBlobExpand(pParse, pParse->nBlob+d); + jsonBlobExpand(pParse, (u64)pParse->nBlob+d); if( pParse->oom ) return; } memmove(&pParse->aBlob[iDel+nIns], @@ -215983,7 +217151,7 @@ static u32 jsonLookupStep( const char *zLabel; x = pParse->aBlob[j] & 0x0f; if( xJSONB_TEXTRAW ) return JSON_LOOKUP_ERROR; - n = jsonbPayloadSize(pParse, j, &sz); + n = jsonbPayloadSizeSemiInline(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; @@ -216005,7 +217173,7 @@ static u32 jsonLookupStep( } j = k+sz; if( ((pParse->aBlob[j])&0x0f)>JSONB_OBJECT ) return JSON_LOOKUP_ERROR; - n = jsonbPayloadSize(pParse, j, &sz); + n = jsonbPayloadSizeSemiInline(pParse, j, &sz); if( n==0 ) return JSON_LOOKUP_ERROR; j += n+sz; } @@ -216094,7 +217262,7 @@ static u32 jsonLookupStep( return rc; } kk--; - n = jsonbPayloadSize(pParse, j, &sz); + n = jsonbPayloadSizeSemiInline(pParse, j, &sz); if( n==0 ) return JSON_LOOKUP_ERROR; j += n+sz; } @@ -216387,8 +217555,7 @@ static int jsonFunctionArgToBlob( break; } case SQLITE_FLOAT: { - double r = sqlite3_value_double(pArg); - if( NEVER(sqlite3IsNaN(r)) ){ + if( NEVER(sqlite3IsNaN(sqlite3_value_double(pArg))) ){ jsonBlobAppendNode(pParse, JSONB_NULL, 0, 0); }else{ int n = sqlite3_value_bytes(pArg); @@ -218194,6 +219361,15 @@ static void jsonAppendPathName(JsonEachCursor *p){ } } +/* Report a "malformed JSON" or OOM error against the cursor. +*/ +static int jsonEachMalformedInput(sqlite3_vtab_cursor *cur){ + sqlite3_free(cur->pVtab->zErrMsg); + cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON"); + jsonEachCursorReset((JsonEachCursor*)cur); + return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; +} + /* Advance the cursor to the next element for json_tree() */ static int jsonEachNext(sqlite3_vtab_cursor *cur){ JsonEachCursor *p = (JsonEachCursor*)cur; @@ -218205,6 +219381,7 @@ static int jsonEachNext(sqlite3_vtab_cursor *cur){ u32 i = jsonSkipLabel(p); x = p->sParse.aBlob[i] & 0x0f; n = jsonbPayloadSize(&p->sParse, i, &sz); + if( n==0 )return jsonEachMalformedInput(cur); if( x==JSONB_OBJECT || x==JSONB_ARRAY ){ JsonParent *pParent; if( p->nParent>=p->nParentAlloc ){ @@ -218250,6 +219427,7 @@ static int jsonEachNext(sqlite3_vtab_cursor *cur){ u32 n, sz = 0; u32 i = jsonSkipLabel(p); n = jsonbPayloadSize(&p->sParse, i, &sz); + if( n==0 )return jsonEachMalformedInput(cur); p->i = i + n + sz; } if( p->eType==JSONB_ARRAY && p->nParent ){ @@ -218363,7 +219541,7 @@ static int jsonEachColumn( break; } default: { - sqlite3_result_text(ctx, p->path.zBuf, p->nRoot, SQLITE_STATIC); + sqlite3_result_text(ctx, p->path.zBuf, p->nRoot, SQLITE_TRANSIENT); break; } case JEACH_JSON: { @@ -218486,7 +219664,7 @@ static int jsonEachFilter( if( p->sParse.oom ){ return SQLITE_NOMEM; } - goto json_each_malformed_input; + return jsonEachMalformedInput(cur); } } if( idxNum==3 ){ @@ -218547,12 +219725,6 @@ static int jsonEachFilter( p->aParent[0].iValue = i; } 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 */ @@ -219162,7 +220334,7 @@ struct RtreeMatchArg { ** ** For best performance, an attempt is made to guess at the byte-order ** using C-preprocessor macros. If that is unsuccessful, or if -** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined +** -DSQLITE_BYTEORDER=0 is set, then byte-order is determined ** at run-time. */ #ifndef SQLITE_BYTEORDER /* Replicate changes at tag-20230904a */ @@ -219218,8 +220390,11 @@ static void readCoord(u8 *p, RtreeCoord *pCoord){ ); #endif } + static i64 readInt64(u8 *p){ -#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 +#if defined(SQLITE_AMALGAMATION) + return (i64)sqlite3Get8byte(p); +#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 u64 x; memcpy(&x, p, 8); return (i64)_byteswap_uint64(x); @@ -219299,6 +220474,18 @@ static int writeInt64(u8 *p, i64 i){ return 8; } +/* +** Translate pVal into a 32-bit integer. If pVal is an integer +** that is larger than 32 bits, the cap it at the largest or +** smallest 32-bit integer. +*/ +static int rtreeValueInt32(sqlite3_value *pVal){ + i64 v64 = sqlite3_value_int64(pVal); + if( v64>2147483647 ) return 2147483647; + if( v64<-2147483648LL ) return (int)-2147483648LL; + return (int)v64; +} + /* ** Increment the reference count of node p. */ @@ -219579,7 +220766,17 @@ static int nodeWrite(Rtree *pRtree, RtreeNode *pNode){ sqlite3_bind_null(p, 2); if( pNode->iNode==0 && rc==SQLITE_OK ){ pNode->iNode = sqlite3_last_insert_rowid(pRtree->db); - nodeHashInsert(pRtree, pNode); + if( pNode->iNode==0 ){ + /* If the SQL statement has succeeded but sqlite3_last_insert_rowid() + ** returns 0, then the shadow table schema has been corrupted somehow + ** (e.g. the %_node table has been replaced by a WITHOUT ROWID table). + ** It would be dangerous to continue in this case as the hash table + ** implementation assumes iNode==0 means that the node is not part + ** of the hash table. */ + rc = SQLITE_CORRUPT_VTAB; + }else{ + nodeHashInsert(pRtree, pNode); + } } } return rc; @@ -221702,12 +222899,6 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){ return rc; } -/* -** Rounding constants for float->double conversion. -*/ -#define RNDTOWARDS (1.0 - 1.0/8388608.0) /* Round towards zero */ -#define RNDAWAY (1.0 + 1.0/8388608.0) /* Round away from zero */ - #if !defined(SQLITE_RTREE_INT_ONLY) /* ** Convert an sqlite3_value into an RtreeValue (presumably a float) @@ -221717,7 +222908,10 @@ static RtreeValue rtreeValueDown(sqlite3_value *v){ double d = sqlite3_value_double(v); float f = (float)d; if( f>d ){ - f = (float)(d*(d<0 ? RNDAWAY : RNDTOWARDS)); + unsigned int x; + memcpy(&x, &f, 4); + x = (x & 0x80000000)!=0 ? x+1 : x-1; + memcpy(&f, &x, 4); } return f; } @@ -221725,12 +222919,40 @@ static RtreeValue rtreeValueUp(sqlite3_value *v){ double d = sqlite3_value_double(v); float f = (float)d; if( fcell.aCoord[ii+1].i ){ rc = rtreeConstraintError(pRtree, ii+1); goto constraint; @@ -222446,12 +223668,14 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ int nData; int errCode; sqlite3_str *pOut; + i64 nDim64; UNUSED_PARAMETER(nArg); memset(&node, 0, sizeof(RtreeNode)); memset(&tree, 0, sizeof(Rtree)); - tree.nDim = (u8)sqlite3_value_int(apArg[0]); - if( tree.nDim<1 || tree.nDim>5 ) return; + nDim64 = sqlite3_value_int64(apArg[0]); + if( nDim64<1 || nDim64>5 ) return; + tree.nDim = (u8)nDim64; tree.nDim2 = tree.nDim*2; tree.nBytesPerCell = 8 + 8 * tree.nDim; node.zData = (u8 *)sqlite3_value_blob(apArg[1]); @@ -223249,7 +224473,7 @@ static GeoPoly *geopolyParseJson(const unsigned char *z, int *pRc){ break; } if( geopolySkipSpace(&s)==']' - && s.nVertex>=4 + && s.nVertex>=4 && s.nVertex<16777216 && s.a[0]==s.a[s.nVertex*2-2] && s.a[1]==s.a[s.nVertex*2-1] && (s.z++, geopolySkipSpace(&s)==0) @@ -223575,6 +224799,8 @@ static double geopolySine(double r){ ** ** Construct a simple, convex, regular polygon centered at X, Y ** with circumradius R and with N sides. +** +** Maximum N is 1000. Maximum R is 1.0e+300. */ static void geopolyRegularFunc( sqlite3_context *context, @@ -223584,12 +224810,12 @@ static void geopolyRegularFunc( double x = sqlite3_value_double(argv[0]); double y = sqlite3_value_double(argv[1]); double r = sqlite3_value_double(argv[2]); - int n = sqlite3_value_int(argv[3]); + i64 n = sqlite3_value_int64(argv[3]); int i; GeoPoly *p; (void)argc; - if( n<3 || r<=0.0 ) return; + if( n<3 || r<=0.0 || r>=1e300 ) return; if( n>1000 ) n = 1000; p = sqlite3_malloc64( sizeof(*p) + (n-1)*2*sizeof(GeoCoord) ); if( p==0 ){ @@ -224854,6 +226080,12 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db){ if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "rtreecheck", -1, utf8, 0,rtreecheck, 0,0); } +#if defined(SQLITE_DEBUG) && !defined(SQLITE_RTREE_INT_ONLY) + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "rtree_round", 2, utf8, 0, + rtreeRoundFunc, 0, 0); + } +#endif /* SQLITE_DEBUG && !SQLITE_RTREE_INT_ONLY */ if( rc==SQLITE_OK ){ #ifdef SQLITE_RTREE_INT_ONLY void *c = (void *)RTREE_COORD_INT32; @@ -225124,6 +226356,9 @@ static const unsigned char icuUtf8Trans1[] = { while( (*zIn & 0xc0)==0x80 ){ \ c = (c<<6) + (0x3f & *(zIn++)); \ } \ + if( c<0x80 \ + || (c&0xFFFFF800)==0xD800 \ + || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \ } #define SQLITE_ICU_SKIP_UTF8(zIn) \ @@ -225535,6 +226770,7 @@ static void icuLoadCollation( } sqlite3_result_error(p, sqlite3_str_value(pStr), -1); sqlite3_free(sqlite3_str_finish(pStr)); + ucol_close(pUCollator); return; } } @@ -227930,15 +229166,27 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){ /* Check that all non-HIDDEN columns in the destination table are also ** present in the input table. Populate the abTblPk[], azTblType[] and - ** aiTblOrder[] arrays at the same time. */ + ** aiTblOrder[] arrays at the same time. + ** + ** RBU does not support tables with GENERATED columns. If the target + ** table has any, return an error. */ if( p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &p->zErrmsg, - sqlite3_mprintf("PRAGMA table_info(%Q)", pIter->zTbl) + sqlite3_mprintf("PRAGMA table_xinfo(%Q)", pIter->zTbl) ); } while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ const char *zName = (const char*)sqlite3_column_text(pStmt, 1); - if( zName==0 ) break; /* An OOM - finalize() below returns S_NOMEM */ + int eHidden = sqlite3_column_int(pStmt, 6); + if( zName==0 ) break; /* An OOM. Bail out */ + if( eHidden==1 ) continue; /* Hidden column. Ignore */ + if( eHidden!=0 ){ + p->rc = SQLITE_ERROR; + p->zErrmsg = sqlite3_mprintf( + "generated columns not supported: %s.%s", pIter->zTbl, zName + ); + break; + } for(i=iOrder; inTblCol; i++){ if( 0==strcmp(zName, pIter->azTblCol[i]) ) break; } @@ -228791,7 +230039,7 @@ static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){ char c = zSql[i]; /* If necessary, grow the pIter->aIdxCol[] array */ - if( iIdxCol==nIdxAlloc ){ + if( iIdxCol>=(nIdxAlloc-1) ){ RbuSpan *aIdxCol = (RbuSpan*)sqlite3_realloc64( pIter->aIdxCol, nIdxAlloc*sizeof(RbuSpan) + 16*sizeof(RbuSpan) ); @@ -230181,7 +231429,12 @@ static void rbuCreateTargetSchema(sqlite3rbu *p){ while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){ const char *zSql = (const char*)sqlite3_column_text(pSql, 0); - p->rc = sqlite3_exec(p->dbMain, zSql, 0, 0, &p->zErrmsg); + sqlite3_stmt *pStmt = 0; + p->rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg, zSql); + if( p->rc==SQLITE_OK ){ + sqlite3_step(pStmt); + rbuFinalize(p, pStmt); + } } rbuFinalize(p, pSql); if( p->rc!=SQLITE_OK ) return; @@ -232588,12 +233841,14 @@ static int statNext(sqlite3_vtab_cursor *pCursor){ while( p->iCellnCell ){ StatCell *pCell = &p->aCell[p->iCell]; while( pCell->iOvflnOvfl ){ - int nUsable, iOvfl; + int nUsable; + int iOvfl = pCell->iOvfl; sqlite3BtreeEnter(pBt); nUsable = sqlite3BtreeGetPageSize(pBt) - sqlite3BtreeGetReserveNoMutex(pBt); sqlite3BtreeLeave(pBt); pCsr->nPage++; + pCsr->iPageno = pCell->aOvfl[iOvfl]; statSizeAndOffset(pCsr); if( pCell->iOvflnOvfl-1 ){ pCsr->nPayload += nUsable - 4; @@ -232601,11 +233856,9 @@ static int statNext(sqlite3_vtab_cursor *pCursor){ pCsr->nPayload += pCell->nLastOvfl; pCsr->nUnused += nUsable - 4 - pCell->nLastOvfl; } - iOvfl = pCell->iOvfl; pCell->iOvfl++; if( !pCsr->isAgg ){ pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0); - pCsr->iPageno = pCell->aOvfl[iOvfl]; pCsr->zPagetype = "overflow"; pCsr->zPath = z = sqlite3_mprintf( "%s%.3x+%.6x", p->zPath, p->iCell, iOvfl @@ -233230,6 +234483,7 @@ static int dbpageUpdate( ){ DbpageTable *pTab = (DbpageTable *)pVtab; Pgno pgno; + sqlite3_int64 pgno64; DbPage *pDbPage = 0; int rc = SQLITE_OK; char *zErr = 0; @@ -233249,11 +234503,11 @@ static int dbpageUpdate( goto update_fail; } if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ - pgno = (Pgno)sqlite3_value_int64(argv[2]); + pgno64 = sqlite3_value_int64(argv[2]); isInsert = 1; }else{ - pgno = (Pgno)sqlite3_value_int64(argv[0]); - if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){ + pgno64 = (Pgno)sqlite3_value_int64(argv[0]); + if( sqlite3_value_int64(argv[1])!=pgno64 ){ zErr = "cannot insert"; goto update_fail; } @@ -233270,10 +234524,11 @@ static int dbpageUpdate( } } pBt = pTab->db->aDb[iDb].pBt; - if( pgno<1 || NEVER(pBt==0) ){ + if( pgno64<1 || pgno64>4294967294U || NEVER(pBt==0) ){ zErr = "bad page number"; goto update_fail; } + pgno = (Pgno)pgno64; szPage = sqlite3BtreeGetPageSize(pBt); if( sqlite3_value_type(argv[3])!=SQLITE_BLOB || sqlite3_value_bytes(argv[3])!=szPage @@ -233607,8 +234862,14 @@ static int carrayColumn( default: { const struct iovec *p = (struct iovec*)pCur->pPtr; assert( pCur->eType==CARRAY_BLOB ); - sqlite3_result_blob(ctx, p[pCur->iRowid-1].iov_base, - (int)p[pCur->iRowid-1].iov_len, SQLITE_TRANSIENT); + p += pCur->iRowid-1; + if( p->iov_len>0x7fffffff ){ + sqlite3_result_error_toobig(ctx); + return SQLITE_TOOBIG; + }else{ + sqlite3_result_blob(ctx, p->iov_base, (int)p->iov_len, + SQLITE_TRANSIENT); + } return SQLITE_OK; } } @@ -234298,7 +235559,9 @@ static int sessionVarintLen(int iVal){ ** bytes read. */ static int sessionVarintGet(const u8 *aBuf, int *piVal){ - return getVarint32(aBuf, *piVal); + int ret = getVarint32(aBuf, *piVal); + *piVal = (*piVal & 0x7FFFFFFF); + return ret; } /* @@ -234313,7 +235576,7 @@ static int sessionVarintGetSafe(const u8 *aBuf, int nBuf, int *piVal){ memcpy(aCopy, aBuf, nBuf); aRead = aCopy; } - return getVarint32(aRead, *piVal); + return sessionVarintGet(aRead, piVal); } /* Load an unaligned and unsigned 32-bit integer */ @@ -236812,6 +238075,33 @@ static int sessionPrepare( return rc; } +/* +** Prepare the statement specified by printf format zFmt and its trailing +** arguments. +*/ +static void sessionPrepareMprintf( + int *pRc, + sqlite3 *db, + sqlite3_stmt **pp, + char **pzErrmsg, + const char *zFmt, + ... +){ + if( *pRc==SQLITE_OK ){ + char *zSql; + va_list ap; + va_start(ap, zFmt); + zSql = sqlite3_vmprintf(zFmt, ap); + if( zSql==0 ){ + *pRc = SQLITE_NOMEM; + }else{ + *pRc = sessionPrepare(db, pp, pzErrmsg, zSql); + sqlite3_free(zSql); + } + va_end(ap); + } +} + /* ** Formulate and prepare a SELECT statement to retrieve a row from table ** zTab in database zDb based on its primary key. i.e. @@ -237655,17 +238945,21 @@ static int sessionChangesetBufferRecord( int eType; rc = sessionInputBuffer(pIn, nByte + 10); if( rc==SQLITE_OK ){ - eType = pIn->aData[pIn->iNext + nByte++]; - if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ - int n; - int nRem = pIn->nData - (pIn->iNext + nByte); - nByte += sessionVarintGetSafe(&pIn->aData[pIn->iNext+nByte], nRem, &n); - nByte += n; - rc = sessionInputBuffer(pIn, nByte); - }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ - nByte += 8; - }else if( eType!=0 && eType!=SQLITE_NULL ){ + if( pIn->iNext+nByte>=pIn->nData ){ rc = SQLITE_CORRUPT_BKPT; + }else{ + eType = pIn->aData[pIn->iNext + nByte++]; + if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ + int n; + int nRem = pIn->nData - (pIn->iNext + nByte); + nByte += sessionVarintGetSafe(&pIn->aData[pIn->iNext+nByte], nRem,&n); + nByte += n; + rc = sessionInputBuffer(pIn, nByte); + }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ + nByte += 8; + }else if( eType!=0 && eType!=SQLITE_NULL ){ + rc = SQLITE_CORRUPT_BKPT; + } } } if( rc==SQLITE_OK && (pIn->iNext+nByte)>pIn->nData ){ @@ -239211,161 +240505,215 @@ static int sessionApplyRetryBuffer( } /* -** Check if table zTab in the "main" database of db is a WITHOUT ROWID -** table. +** Buffer aUnique[] is pApply->nCol entries in size. This function sets +** aUnique[i] to true if column i of table zTab in the "main" database +** of db is part of at least one UNIQUE constraint, or to false otherwise. ** -** If no error occurs, return SQLITE_OK and set output variable (*pbWR) to -** true if zTab is a WITHOUT ROWID table, or false otherwise. Or, if an -** error does occur, return an SQLite error code. The final value of (*pbWR) -** is undefined in this case. +** If the table has a unique index on an expression, or a partial unique +** index, all entries of aUnique[] are set to true. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ -static int sessionTableIsWithoutRowid(sqlite3 *db, const char *zTab, int *pbWR){ - sqlite3_stmt *pList = 0; - char *zSql = 0; +static int sessionUniqueColumns( + sqlite3 *db, /* Database handle */ + const char *zTab, /* Table name */ + SessionApplyCtx *pApply, /* Apply context */ + u8 *aUnique /* OUT: Array of pApply->nCol flags */ +){ + sqlite3_stmt *pList = 0; /* PRAGMA index_list */ int rc = SQLITE_OK; - zSql = sqlite3_mprintf("PRAGMA table_list = %Q", zTab); - if( zSql==0 ){ - rc = SQLITE_NOMEM; - }else{ - rc = sqlite3_prepare_v2(db, zSql, -1, &pList, 0); - sqlite3_free(zSql); - } + /* Ordinary PRAGMA statements are used here instead of the equivalent + ** table-valued functions (pragma_index_list() etc.) so that this works + ** in builds with SQLITE_OMIT_VIRTUALTABLE defined. */ + memset(aUnique, 0, pApply->nCol); + sessionPrepareMprintf(&rc, db, &pList, &pApply->zErr, + "PRAGMA main.index_list(%Q)", zTab + ); + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){ + /* Columns of PRAGMA index_list are (seq, name, unique, origin, partial) */ + const char *zIdx = (const char*)sqlite3_column_text(pList, 1); + int bUnique = sqlite3_column_int(pList, 2); + int bPartial = sqlite3_column_int(pList, 4); + sqlite3_stmt *pInfo = 0; /* PRAGMA index_xinfo */ + if( bUnique==0 ) continue; + sessionPrepareMprintf(&rc, db, &pInfo, &pApply->zErr, + "PRAGMA main.index_xinfo(%Q)", zIdx + ); + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pInfo) ){ + /* Columns of PRAGMA index_xinfo are (seqno, cid, name, desc, coll, key)*/ + int iCid = sqlite3_column_int(pInfo, 1); + const char *zCol = (const char*)sqlite3_column_text(pInfo, 2); + int bKey = sqlite3_column_int(pInfo, 5); + int ii; + if( bKey==0 ) continue; + for(ii=0; iinCol; ii++){ + if( bPartial + || iCid==-2 + || (zCol && 0==sqlite3_stricmp(zCol, pApply->azCol[ii])) + ){ + aUnique[ii] = 1; + } + } + } + if( rc==SQLITE_OK ){ + rc = sqlite3_finalize(pInfo); + }else{ + sqlite3_finalize(pInfo); + } + } if( rc==SQLITE_OK ){ - sqlite3_step(pList); - *pbWR = sqlite3_column_int(pList, 4); rc = sqlite3_finalize(pList); + }else{ + sqlite3_finalize(pList); } return rc; } /* -** Iterator pUp points to an UPDATE change. This function deletes the -** affected row from the database and creates an INSERT statement that -** may be used to reinsert the row as it is after the UPDATE change -** has been applied. +** Iterator pUp points to an UPDATE change. This function updates the +** affected row to set each column modified by the UPDATE change that +** is also part of at least one UNIQUE constraint to a "random" value, +** and creates another UPDATE statement that may be used to later set +** all columns modified by pUp to the actual values required by pUp. +** +** Each random value has the same type as the final value required by +** pUp for the same column: +** +** NULL -> NULL +** INTEGER -> random() +** REAL -> random() +** TEXT -> CAST(random() AS TEXT) +** BLOB -> unhex(hex(random())) +** +** If none of the columns modified by pUp are part of a UNIQUE constraint, +** then SQLITE_CONSTRAINT is returned. ** -** If successful, SQLITE_OK is returned and output variable (*ppInsert) -** is left pointing to a prepared INSERT statement. It is the responsibility +** If successful, SQLITE_OK is returned and output variable (*ppUpdate) +** is left pointing to a prepared UPDATE statement. It is the responsibility ** of the caller to eventually free this statement using sqlite3_finalize(). -** Or, if an error occurs, an SQLite error code is returned and (*ppInsert) +** Or, if an error occurs, an SQLite error code is returned and (*ppUpdate) ** set to NULL. pApply->zErr may be set to an error message in this case. +** Except - it is guaranteed that pApply->zErr is not set if SQLITE_CONSTRAINT +** is returned. */ -static int sessionUpdateToDeleteInsert( +static int sessionUpdateToUpdate( sqlite3 *db, /* Database to write to */ const char *zTab, /* Table name */ SessionApplyCtx *pApply, /* Apply context */ sqlite3_changeset_iter *pUp, /* Iterator pointing to UPDATE change */ - sqlite3_stmt **ppInsert /* OUT: INSERT statement */ + sqlite3_stmt **ppUpdate /* OUT: UPDATE statement */ ){ - sqlite3_stmt *pRet = 0; /* The INSERT statement */ - sqlite3_stmt *pSelect = 0; /* SELECT to read current values of row */ + sqlite3_stmt *pRet = 0; /* UPDATE to set the final values */ + sqlite3_stmt *pRand = 0; /* UPDATE to set random values */ int rc = SQLITE_OK; - int bWR = 0; - - rc = sessionTableIsWithoutRowid(db, zTab, &bWR); - if( rc==SQLITE_OK ){ - char *zSelect = 0; - char *zInsert = 0; - SessionBuffer cols = {0, 0, 0}; - SessionBuffer insbind = {0, 0, 0}; - SessionBuffer pkcols = {0, 0, 0}; - SessionBuffer selbind = {0, 0, 0}; - - const char *zComma = ""; - const char *zComma2 = ""; - int ii; - for(ii=0; iinCol; ii++){ - sessionAppendStr(&cols, zComma, &rc); - sessionAppendIdent(&cols, pApply->azCol[ii], &rc); - sessionAppendStr(&insbind, zComma, &rc); - sessionAppendStr(&insbind, "?", &rc); - zComma = ", "; - - if( pApply->abPK[ii] ){ - sessionAppendStr(&pkcols, zComma2, &rc); - sessionAppendIdent(&pkcols, pApply->azCol[ii], &rc); - sessionAppendStr(&selbind, zComma2, &rc); - sessionAppendPrintf(&selbind, &rc, "?%d", ii+1); - zComma2 = ", "; - } - } - if( bWR==0 ){ - sessionAppendStr(&cols, zComma, &rc); - sessionAppendStr(&cols, SESSIONS_ROWID, &rc); - sessionAppendStr(&insbind, zComma, &rc); - sessionAppendStr(&insbind, "?", &rc); - } - - if( rc==SQLITE_OK ){ - zSelect = sqlite3_mprintf("SELECT %s FROM %Q WHERE (%s) IS (%s)", - cols.aBuf, zTab, pkcols.aBuf, selbind.aBuf - ); - if( zSelect==0 ) rc = SQLITE_NOMEM; - } - if( rc==SQLITE_OK ){ - zInsert = sqlite3_mprintf("INSERT INTO %Q(%s) VALUES(%s)", - zTab, cols.aBuf, insbind.aBuf - ); - if( zInsert==0 ) rc = SQLITE_NOMEM; - } + u8 *aUnique = 0; /* aUnique[i] true if col i is UNIQUE */ + SessionBuffer randset = {0, 0, 0}; + SessionBuffer upset = {0, 0, 0}; + SessionBuffer where = {0, 0, 0}; + int ii; - if( rc==SQLITE_OK ){ - rc = sessionPrepare(db, &pSelect, &pApply->zErr, zSelect); - } - if( rc==SQLITE_OK ){ - rc = sessionPrepare(db, &pRet, &pApply->zErr, zInsert); - } + aUnique = (u8*)sqlite3_malloc64(pApply->nCol); + if( aUnique==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sessionUniqueColumns(db, zTab, pApply, aUnique); + } - sqlite3_free(zSelect); - sqlite3_free(zInsert); - sqlite3_free(cols.aBuf); - sqlite3_free(insbind.aBuf); - sqlite3_free(pkcols.aBuf); - sqlite3_free(selbind.aBuf); + /* Assuming a table structure like this: + ** + ** CREATE TABLE x(a, b UNIQUE, c, d UNIQUE, e, PRIMARY KEY(a, c)); + ** + ** and an UPDATE change that sets column b to an integer, column d to + ** a text value and column e to any value, the two statements prepared + ** are: + ** + ** UPDATE main.x SET b = random(), d = CAST(random() AS TEXT) + ** WHERE a IS ?1 AND c IS ?3 + ** UPDATE main.x SET b = ?2, d = ?4, e = ?5 WHERE a IS ?1 AND c IS ?3 + */ + for(ii=0; rc==SQLITE_OK && iinCol; ii++){ + sqlite3_value *pNew = 0; + if( pApply->abPK[ii] ){ + if( where.nBuf>0 ) sessionAppendStr(&where, " AND ", &rc); + sessionAppendIdent(&where, pApply->azCol[ii], &rc); + sessionAppendPrintf(&where, &rc, " IS ?%d", ii+1); + }else if( (pNew = sessionChangesetNew(pUp, ii))!=0 ){ + if( aUnique[ii] ){ + const char *zRand = 0; + switch( sqlite3_value_type(pNew) ){ + case SQLITE_NULL: zRand = "NULL"; break; + case SQLITE_TEXT: zRand = "CAST(random() AS TEXT)"; break; + case SQLITE_BLOB: zRand = "unhex(hex(random()))"; break; + default: zRand = "random()"; break; + } + if( randset.nBuf>0 ) sessionAppendStr(&randset, ", ", &rc); + sessionAppendIdent(&randset, pApply->azCol[ii], &rc); + sessionAppendStr(&randset, " = ", &rc); + sessionAppendStr(&randset, zRand, &rc); + } + if( upset.nBuf>0 ) sessionAppendStr(&upset, ", ", &rc); + sessionAppendIdent(&upset, pApply->azCol[ii], &rc); + sessionAppendPrintf(&upset, &rc, " = ?%d", ii+1); + } + } + + if( rc==SQLITE_OK && randset.nBuf==0 ){ + /* None of the columns modified by this change are part of a UNIQUE + ** constraint. So setting them to random values cannot help resolve + ** a constraint conflict. Report this as a constraint failure. */ + rc = SQLITE_CONSTRAINT; } + sessionPrepareMprintf(&rc, db, &pRand, &pApply->zErr, + "UPDATE main.\"%w\" SET %s WHERE %s", + zTab, (char*)randset.aBuf, (char*)where.aBuf + ); + sessionPrepareMprintf(&rc, db, &pRet, &pApply->zErr, + "UPDATE main.\"%w\" SET %s WHERE %s", + zTab, (char*)upset.aBuf, (char*)where.aBuf + ); + + /* Bind the PK values to both statements, and the new.* values to pRet. */ if( rc==SQLITE_OK ){ rc = sessionBindRow( - pUp, sqlite3changeset_old, pApply->nCol, pApply->abPK, pSelect + pUp, sqlite3changeset_old, pApply->nCol, pApply->abPK, pRand ); } - - if( rc==SQLITE_OK && sqlite3_step(pSelect)==SQLITE_ROW ){ - int iCol; - for(iCol=0; iColnCol; iCol++){ - sqlite3_value *pVal = pUp->apValue[iCol+pApply->nCol]; - if( pVal==0 ){ - pVal = sqlite3_column_value(pSelect, iCol); - } - rc = sqlite3_bind_value(pRet, iCol+1, pVal); - } - if( bWR==0 ){ - sqlite3_bind_int64(pRet, iCol+1, sqlite3_column_int64(pSelect, iCol)); - } - } - sessionFinalizeStmt(pSelect, &rc); - - /* Delete the row from the database. */ if( rc==SQLITE_OK ){ rc = sessionBindRow( - pUp, sqlite3changeset_old, pApply->nCol, pApply->abPK, pApply->pDelete + pUp, sqlite3changeset_old, pApply->nCol, pApply->abPK, pRet ); - sqlite3_bind_int(pApply->pDelete, pApply->nCol+1, 1); } + for(ii=0; rc==SQLITE_OK && iinCol; ii++){ + sqlite3_value *pNew = sessionChangesetNew(pUp, ii); + if( pApply->abPK[ii]==0 && pNew ){ + rc = sessionBindValue(pRet, ii+1, pNew); + } + } + + /* Evaluate the statement to set each modified column of the row to a random + ** value. If this fails with a constraint error, SQLITE_CONSTRAINT is + ** returned to the caller, but pApply->zErr is not set. */ if( rc==SQLITE_OK ){ - sqlite3_step(pApply->pDelete); - rc = sqlite3_reset(pApply->pDelete); + sqlite3_step(pRand); + rc = sqlite3_reset(pRand); } + sqlite3_finalize(pRand); if( rc!=SQLITE_OK ){ sqlite3_finalize(pRet); pRet = 0; } + *ppUpdate = pRet; + + sqlite3_free(aUnique); + sqlite3_free(randset.aBuf); + sqlite3_free(upset.aBuf); + sqlite3_free(where.aBuf); - *ppInsert = pRet; return rc; } @@ -239382,14 +240730,17 @@ static int sessionUpdateToDeleteInsert( ** 2) For each UPDATE change in the buffer, try the following in a ** savepoint transaction: ** -** a) DELETE the affected row, +** a) UPDATE the affected row, setting each column modified by the +** UPDATE change to a random value, ** b) Attempt step (1) with remaining changes, -** c) Attempt to INSERT a row equivalent to the one that would be -** created by applying this UPDATE change. +** c) Attempt to UPDATE the affected row again, this time setting +** each modified column to the value required by the UPDATE change. ** -** If the INSERT in (c) succeeds, the savepoint is committed and all +** If both (a) and (c) succeed, the savepoint is committed and all ** successfully applied changes are removed from the buffer. Step (2) -** is then repeated. +** is then repeated. Otherwise, if either (a) or (c) fails with +** SQLITE_CONSTRAINT, the savepoint is rolled back and the next UPDATE +** in the buffer is tried. ** ** 3) Once step (2) has been attempted for each UPDATE in the change, ** a final attempt is made to apply each remaining change. This time, @@ -239428,8 +240779,9 @@ static int sessionRetryConstraints( while( rc==SQLITE_OK && pApply->constraints.nBuf && !pApply->bNoUpdateLoop ){ SessionBuffer cons = {0, 0, 0}; sqlite3_changeset_iter *pUp = 0; - sqlite3_stmt *pInsert = 0; + sqlite3_stmt *pUpdate = 0; int iSkip = 0; + int bConstraint = 0; /* True if an SQLITE_CONSTRAINT occurs */ rc = sessionRetryIterInit( &pApply->constraints, bPatchset, zTab, pApply, &pUp @@ -239444,7 +240796,11 @@ static int sessionRetryConstraints( if( iThis==iUpdate ){ rc = sqlite3_exec(db, "SAVEPOINT update_op", 0, 0, 0); if( rc==SQLITE_OK ){ - rc = sessionUpdateToDeleteInsert(db, zTab, pApply, pUp, &pInsert); + rc = sessionUpdateToUpdate(db, zTab, pApply, pUp, &pUpdate); + if( (rc&0xff)==SQLITE_CONSTRAINT ){ + bConstraint = 1; + rc = SQLITE_OK; + } } } sqlite3changeset_finalize(pUp); @@ -239453,6 +240809,9 @@ static int sessionRetryConstraints( if( rc==SQLITE_OK ){ cons = pApply->constraints; + if( bConstraint ){ + memset(&pApply->constraints, 0, sizeof(SessionBuffer)); + } while( rc==SQLITE_OK && pApply->constraints.nBuf>0 ){ SessionBuffer app = pApply->constraints; @@ -239472,9 +240831,16 @@ static int sessionRetryConstraints( iUpdate++; if( rc==SQLITE_OK ){ - sqlite3_step(pInsert); - rc = sqlite3_finalize(pInsert); - if( rc==SQLITE_CONSTRAINT ){ + if( bConstraint==0 ){ + sqlite3_step(pUpdate); + rc = sqlite3_finalize(pUpdate); + pUpdate = 0; + if( (rc&0xff)==SQLITE_CONSTRAINT ){ + bConstraint = 1; + rc = SQLITE_OK; + } + } + if( bConstraint ){ rc = sqlite3_exec(db, "ROLLBACK TO update_op", 0, 0, 0); sqlite3_free(pApply->constraints.aBuf); pApply->constraints = cons; @@ -239485,9 +240851,8 @@ static int sessionRetryConstraints( if( rc==SQLITE_OK ){ rc = sqlite3_exec(db, "RELEASE update_op", 0, 0, 0); } - }else{ - sqlite3_finalize(pInsert); } + sqlite3_finalize(pUpdate); sqlite3_free(cons.aBuf); } @@ -239536,10 +240901,10 @@ static int sessionChangesetApply( int schemaMismatch = 0; int rc = SQLITE_OK; /* Return code */ const char *zTab = 0; /* Name of current table */ - int nTab = 0; /* Result of sqlite3Strlen30(zTab) */ SessionApplyCtx sApply; /* changeset_apply() context object */ int bPatchset; u64 savedFlag = db->flags & SQLITE_FkNoAction; + int bNew = 0; /* True for first entry of new table */ assert( xConflict!=0 ); @@ -239561,15 +240926,16 @@ static int sessionChangesetApply( if( rc==SQLITE_OK ){ rc = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 1", 0, 0, 0); } - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter) ){ + while( rc==SQLITE_OK && SQLITE_ROW==sessionChangesetNext(pIter, 0, 0,&bNew) ){ int nCol; int op; const char *zNew; sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0); - if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){ + if( bNew ){ u8 *abPK; + bNew = 0; rc = sessionRetryConstraints( db, pIter->bPatchset, zTab, &sApply, xConflict, pCtx @@ -239604,7 +240970,6 @@ static int sessionChangesetApply( rc = SQLITE_NOMEM; break; } - nTab = (int)strlen(zTab); sApply.azCol = (const char **)zTab; }else{ int nMinCol = 0; @@ -239657,7 +241022,6 @@ static int sessionChangesetApply( sApply.bStat1 = 0; } } - nTab = sqlite3Strlen30(zTab); } } @@ -240336,7 +241700,7 @@ static int sessionChangesetFindTable( if( pIter ){ sqlite3changeset_pk(pIter, &abPK, &nCol); }else if( !pTab && !pGrp->db ){ - return SQLITE_OK; + return SQLITE_ERROR; } /* If one was not found above, create a new table now */ @@ -240362,7 +241726,7 @@ static int sessionChangesetFindTable( if( rc || pTab->nCol==0 ){ sqlite3_free(pTab->azCol); sqlite3_free(pTab); - return rc; + return rc ? rc : SQLITE_ERROR; } } @@ -241200,44 +242564,40 @@ SQLITE_API int sqlite3changegroup_change_begin( rc = SQLITE_ERROR; }else{ rc = sessionChangesetFindTable(pGrp, zTab, 0, &pTab); + if( pTab==0 && pzErr ){ + *pzErr = sqlite3_mprintf("no such table: %s", zTab); + } } if( rc==SQLITE_OK ){ - if( pTab==0 ){ - if( pzErr ){ - *pzErr = sqlite3_mprintf("no such table: %s", zTab); - } - rc = SQLITE_ERROR; - }else{ - int nReq = pTab->nCol * (eOp==SQLITE_UPDATE ? 2 : 1); - pGrp->cd.pTab = pTab; - pGrp->cd.eOp = eOp; - pGrp->cd.bIndirect = bIndirect; - - if( pGrp->cd.nBufAlloccd.aBuf, nReq * sizeof(SessionBuffer) + int nReq = pTab->nCol * (eOp==SQLITE_UPDATE ? 2 : 1); + pGrp->cd.pTab = pTab; + pGrp->cd.eOp = eOp; + pGrp->cd.bIndirect = bIndirect; + + if( pGrp->cd.nBufAlloccd.aBuf, nReq * sizeof(SessionBuffer) + ); + if( aBuf==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(&aBuf[pGrp->cd.nBufAlloc], 0, + sizeof(SessionBuffer) * (nReq - pGrp->cd.nBufAlloc) ); - if( aBuf==0 ){ - rc = SQLITE_NOMEM; - }else{ - memset(&aBuf[pGrp->cd.nBufAlloc], 0, - sizeof(SessionBuffer) * (nReq - pGrp->cd.nBufAlloc) - ); - pGrp->cd.aBuf = aBuf; - pGrp->cd.nBufAlloc = nReq; - } + pGrp->cd.aBuf = aBuf; + pGrp->cd.nBufAlloc = nReq; } + } #ifdef SQLITE_DEBUG - { - /* Assert that all column values are currently undefined */ - int ii; - for(ii=0; iicd.nBufAlloc; ii++){ - assert( pGrp->cd.aBuf[ii].nBuf==0 ); - } + { + /* Assert that all column values are currently undefined */ + int ii; + for(ii=0; iicd.nBufAlloc; ii++){ + assert( pGrp->cd.aBuf[ii].nBuf==0 ); } -#endif } +#endif } return rc; @@ -241348,7 +242708,7 @@ SQLITE_API int sqlite3changegroup_change_text( const char *pVal, int nVal ){ - int nText = nVal>=0 ? nVal : strlen(pVal); + sqlite3_int64 nText = nVal>=0 ? nVal : strlen(pVal); sqlite3_int64 nByte = 1 + sessionVarintLen(nText) + nText; int rc = SQLITE_OK; SessionBuffer *pBuf = 0; @@ -241400,6 +242760,7 @@ SQLITE_API int sqlite3changegroup_change_finish( char **pzErr ){ int rc = SQLITE_OK; + char *zErr = 0; if( pGrp->cd.pTab ){ SessionBuffer *aBuf = pGrp->cd.aBuf; int ii; @@ -241411,14 +242772,14 @@ SQLITE_API int sqlite3changegroup_change_finish( for(ii=0; iicd.pTab->abPK[ii] ){ if( aBuf[ii].nBuf<=1 ){ - *pzErr = sqlite3_mprintf( + zErr = sqlite3_mprintf( "invalid change: %s value in PK of old.* record", aBuf[ii].nBuf==1 ? "null" : "undefined" ); rc = SQLITE_ERROR; break; }else if( aBuf[ii + nBuf].nBuf>0 ){ - *pzErr = sqlite3_mprintf( + zErr = sqlite3_mprintf( "invalid change: defined value in PK of new.* record" ); rc = SQLITE_ERROR; @@ -241426,7 +242787,7 @@ SQLITE_API int sqlite3changegroup_change_finish( } }else if( pGrp->bPatch==0 && (aBuf[ii].nBuf>0)!=(aBuf[ii+nBuf].nBuf>0) ){ - *pzErr = sqlite3_mprintf( + zErr = sqlite3_mprintf( "invalid change: column %d " "- old.* value is %sdefined but new.* is %sdefined", ii, aBuf[ii].nBuf ? "" : "un", aBuf[ii+nBuf].nBuf ? "" : "un" @@ -241443,14 +242804,14 @@ SQLITE_API int sqlite3changegroup_change_finish( if( (pGrp->cd.eOp==SQLITE_INSERT || pGrp->bPatch==0 || isPK) && aBuf[ii].nBuf==0 ){ - *pzErr = sqlite3_mprintf( + zErr = sqlite3_mprintf( "invalid change: column %d is undefined", ii ); rc = SQLITE_ERROR; break; } if( aBuf[ii].nBuf==1 && isPK ){ - *pzErr = sqlite3_mprintf( + zErr = sqlite3_mprintf( "invalid change: null value in PK" ); rc = SQLITE_ERROR; @@ -241500,6 +242861,11 @@ SQLITE_API int sqlite3changegroup_change_finish( pGrp->cd.pTab = 0; } + if( pzErr ){ + *pzErr = zErr; + }else{ + sqlite3_free(zErr); + } return rc; } @@ -243296,7 +244662,7 @@ static void sqlite3Fts5UnicodeAscii(u8*, u8*); ** at each "%%" line. Also, any "P-a-r-s-e" identifier prefix (without the ** interstitial "-" characters) contained in this template is changed into ** the value of the %name directive from the grammar. Otherwise, the content -** of this template is copied straight through into the generate parser +** of this template is copied straight through into the generated parser ** source file. ** ** The following is the concatenation of all %include directives from the @@ -245025,6 +246391,16 @@ static int fts5HighlightCb( return rc; } +/* +** Return the integer value of pVal, clamped to the range [-1, 0x7FFFFFFF]. +** This is used for the column-number arguments of auxiliary functions, +** so that 64-bit values that are too large or too small to fit in a +** 32-bit signed integer are not truncated to what might be a valid +** column number. +*/ +static int fts5ValueClampedInt(sqlite3_value *pVal){ + return (int)MIN(MAX(sqlite3_value_int64(pVal), -1), 0x7FFFFFFF); +} /* ** Implementation of highlight() function. @@ -245046,7 +246422,7 @@ static void fts5HighlightFunction( return; } - iCol = sqlite3_value_int(apVal[0]); + iCol = fts5ValueClampedInt(apVal[0]); memset(&ctx, 0, sizeof(HighlightContext)); ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]); ctx.zClose = (const char*)sqlite3_value_text(apVal[2]); @@ -245245,7 +246621,7 @@ static void fts5SnippetFunction( nCol = pApi->xColumnCount(pFts); memset(&ctx, 0, sizeof(HighlightContext)); - iCol = sqlite3_value_int(apVal[0]); + iCol = fts5ValueClampedInt(apVal[0]); ctx.zOpen = fts5ValueToText(apVal[1]); ctx.zClose = fts5ValueToText(apVal[2]); ctx.iRangeEnd = -1; @@ -245577,7 +246953,7 @@ static void fts5GetLocaleFunction( return; } - iCol = sqlite3_value_int(apVal[0]); + iCol = fts5ValueClampedInt(apVal[0]); if( iCol<0 || iCol>=pApi->xColumnCount(pFts) ){ sqlite3_result_error_code(pCtx, SQLITE_RANGE); return; @@ -250769,7 +252145,7 @@ static int sqlite3Fts5HashWrite( ** + 5 bytes for the new position offset (32-bit max). */ if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){ - sqlite3_int64 nNew = p->nAlloc * 2; + sqlite3_int64 nNew = (i64)p->nAlloc * 2; Fts5HashEntry *pNew; Fts5HashEntry **pp; pNew = (Fts5HashEntry*)sqlite3_realloc64(p, nNew); @@ -251322,7 +252698,12 @@ static void sqlite3Fts5HashScanEntry( #define FTS5_DATA_ID_B 16 /* Max seg id number 65535 */ #define FTS5_DATA_DLI_B 1 /* Doclist-index flag (1 bit) */ #define FTS5_DATA_HEIGHT_B 5 /* Max dlidx tree height of 32 */ -#define FTS5_DATA_PAGE_B 31 /* Max page number of 2147483648 */ +#define FTS5_DATA_PAGE_B 31 /* 31-bit page numbers */ + +/* Maximum page number within a segment. Declare any structure read from +** the database with a page number greater than this corrupt. It is not +** actually possible to create a database this large. */ +#define FTS5_MAX_PGNO 0x7FFFFF00 #define fts5_dri(segid, dlidx, height, pgno) ( \ ((i64)(segid) << (FTS5_DATA_PAGE_B+FTS5_DATA_HEIGHT_B+FTS5_DATA_DLI_B)) + \ @@ -252235,7 +253616,7 @@ static int fts5StructureDecode( i += fts5GetVarint(&pData[i], &pSeg->nEntry); nOriginCntr = MAX(nOriginCntr, pSeg->iOrigin2); } - if( pSeg->pgnoLastpgnoFirst ){ + if( pSeg->pgnoLastpgnoFirst || pSeg->pgnoLast>FTS5_MAX_PGNO ){ rc = FTS5_CORRUPT; break; } @@ -252739,6 +254120,7 @@ static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){ pLvl->bEof = 1; }else{ u8 *a = pLvl->pData->p; + int nn = pLvl->pData->nn; pLvl->iOff = 0; fts5DlidxLvlNext(pLvl); @@ -252747,7 +254129,7 @@ static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){ int ii = pLvl->iOff; u64 delta = 0; - while( a[ii]==0 ){ + while( iinLvl = i+1; + if( pIter->nLvl > (1<rc = FTS5_CORRUPT; + } } } @@ -254821,6 +256206,7 @@ static void fts5IterSetOutputs_Nocolset(Fts5Iter *pIter, Fts5SegIter *pSeg){ static void fts5IterSetOutputs_ZeroColset(Fts5Iter *pIter, Fts5SegIter *pSeg){ UNUSED_PARAM(pSeg); pIter->base.nData = 0; + pIter->base.bEof = 1; } /* @@ -256551,34 +257937,38 @@ static void fts5DoSecureDelete( if( p->rc==SQLITE_OK ){ const int nMove = nPg - iNextOff; /* Number of bytes to move */ int nShift = iNextOff - iOff; /* Distance to move them */ - + int nNewPg = 0; int iPrevKeyOut = 0; - int iKeyIn = 0; + i64 iKeyIn = 0; if( nMove>0 ){ memmove(&aPg[iOff], &aPg[iNextOff], nMove); } iPgIdx -= nShift; - nPg = iPgIdx; + nNewPg = iPgIdx; fts5PutU16(&aPg[2], iPgIdx); for(iIdx=0; iIdxnPg ){ + FTS5_CORRUPT_IDX(p); + break; + } if( iKeyIn!=iDelKeyOff ){ int iKeyOut = (iKeyIn - (iKeyIn>iOff ? nShift : 0)); - nPg += sqlite3Fts5PutVarint(&aPg[nPg], iKeyOut - iPrevKeyOut); + nNewPg += sqlite3Fts5PutVarint(&aPg[nNewPg], iKeyOut - iPrevKeyOut); iPrevKeyOut = iKeyOut; } } - if( iPgIdx==nPg && nIdx>0 && pSeg->iLeafPgno!=1 ){ + if( p->rc==SQLITE_OK && iPgIdx==nNewPg && 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); + assert_nc( nNewPg>4 || fts5GetU16(aPg)==0 ); + fts5DataWrite(p, FTS5_SEGMENT_ROWID(iSegid,pSeg->iLeafPgno), aPg, nNewPg); } sqlite3_free(aIdx); } @@ -256726,7 +258116,6 @@ static void fts5FlushOneHash(Fts5Index *p){ iOff++; if( iOff=pIter->aEof ){ pIter->aPoslist = 0; }else{ - i64 iDelta; + u64 iDelta; - p += fts5GetVarint(p, (u64*)&iDelta); + p += fts5GetVarint(p, &iDelta); pIter->iRowid += iDelta; /* Read position list size */ @@ -257141,7 +258530,7 @@ static void fts5MergeRowidLists( (void)nBuf; memset(&out, 0, sizeof(out)); assert( nBuf==1 ); - sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n); + sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n + 9); if( p->rc ) return; fts5NextRowid(p1, &i1, &iRowid1); @@ -257149,12 +258538,12 @@ static void fts5MergeRowidLists( while( i1>=0 || i2>=0 ){ if( i1>=0 && (i2<0 || iRowid1iOut ); - fts5BufferSafeAppendVarint(&out, iRowid1 - iOut); + fts5BufferSafeAppendVarint(&out, (u64)iRowid1 - (u64)iOut); iOut = iRowid1; fts5NextRowid(p1, &i1, &iRowid1); }else{ assert( iOut==0 || iRowid2>iOut ); - fts5BufferSafeAppendVarint(&out, iRowid2 - iOut); + fts5BufferSafeAppendVarint(&out, (u64)iRowid2 - (u64)iOut); iOut = iRowid2; if( i1>=0 && iRowid1==iRowid2 ){ fts5NextRowid(p1, &i1, &iRowid1); @@ -259324,6 +260713,9 @@ static int fts5QueryCksum( } /* +** This function is purely an internal test. It does not contribute to +** FTS functionality, or even the integrity-check, in any way. +** ** Check if buffer z[], size n bytes, contains as series of valid utf-8 ** encoded codepoints. If so, return 0. Otherwise, if the buffer does not ** contain valid utf-8, return non-zero. @@ -259345,8 +260737,8 @@ static int fts5TestUtf8(const char *z, int n){ }else if( (z[i] & 0xF8)==0xF0 ){ if( i+3>=n || (z[i+1] & 0xC0)!=0x80 || (z[i+2] & 0xC0)!=0x80 ) return 1; - if( (z[i+2] & 0xC0)!=0x80 ) return 1; - i += 3; + if( (z[i+3] & 0xC0)!=0x80 ) return 1; + i += 4; }else{ return 1; } @@ -264240,7 +265632,7 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2026-07-24 19:02:57 bf7c7f30031888f4e796e429ab3978879485813aaca6f641c7b33e4e09459bcc", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2026-10-09 15:46:58 be8d059e9a49089ab2dce5ed26dd87aaf598fdc5fbe0b107c0dd758464bcd5e3", -1, SQLITE_TRANSIENT); } /* @@ -265133,6 +266525,64 @@ static void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage *pStorage){ pStorage->pSavedRow = 0; } +/* +** Load the contents of the "averages" record from disk into the +** p->nTotalRow and p->aTotalSize[] variables. If successful, and if +** argument bCache is true, set the p->bTotalsValid flag to indicate +** that the contents of aTotalSize[] and nTotalRow are valid until +** further notice. +** +** Return SQLITE_OK if successful, or an SQLite error code if an error +** occurs. +*/ +static int fts5StorageLoadTotals(Fts5Storage *p, int bCache){ + int rc = SQLITE_OK; + if( p->bTotalsValid==0 ){ + rc = sqlite3Fts5IndexGetAverages(p->pIndex, &p->nTotalRow, p->aTotalSize); + p->bTotalsValid = bCache; + } + return rc; +} + +/* +** Store the current contents of the p->nTotalRow and p->aTotalSize[] +** variables in the "averages" record on disk. +** +** Return SQLITE_OK if successful, or an SQLite error code if an error +** occurs. +*/ +static int fts5StorageSaveTotals(Fts5Storage *p){ + int nCol = p->pConfig->nCol; + int i; + Fts5Buffer buf; + int rc = SQLITE_OK; + memset(&buf, 0, sizeof(buf)); + + sqlite3Fts5BufferAppendVarint(&rc, &buf, p->nTotalRow); + for(i=0; iaTotalSize[i]); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IndexSetAverages(p->pIndex, buf.p, buf.n); + } + sqlite3_free(buf.p); + + return rc; +} + +static int fts5StorageDecodeSizeArray( + int *aCol, int nCol, /* Array to populate */ + const u8 *aBlob, int nBlob /* Record to read varints from */ +){ + int i; + int iOff = 0; + for(i=0; i=nBlob ) return 1; + iOff += fts5GetVarint32(&aBlob[iOff], aCol[i]); + } + return (iOff!=nBlob); +} + /* ** 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 @@ -265149,19 +266599,41 @@ static int fts5StorageContentlessDelete(Fts5Storage *p, i64 iDel){ || p->pConfig->eContent==FTS5_CONTENT_UNINDEXED ); + rc = fts5StorageLoadTotals(p, 1); + if( rc!=SQLITE_OK ) return rc; + /* 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 ){ + int rc2; sqlite3_bind_int64(pLookup, 1, iDel); if( SQLITE_ROW==sqlite3_step(pLookup) ){ - iOrigin = sqlite3_column_int64(pLookup, 1); + int *aCol = (int*)sqlite3_malloc64(p->pConfig->nCol * sizeof(int)); + if( aCol==0 ){ + rc = SQLITE_NOMEM; + }else{ + const u8 *aBlob = sqlite3_column_blob(pLookup, 0); + int nBlob = sqlite3_column_bytes(pLookup, 0); + int ii; + if( fts5StorageDecodeSizeArray(aCol, p->pConfig->nCol, aBlob, nBlob) ){ + rc = SQLITE_CORRUPT_VTAB; + }else{ + for(ii=0; iipConfig->nCol; ii++){ + p->aTotalSize[ii] -= aCol[ii]; + } + } + sqlite3_free(aCol); + } + iOrigin = sqlite3_column_int(pLookup, 1); } - rc = sqlite3_reset(pLookup); + rc2 = sqlite3_reset(pLookup); + if( rc==SQLITE_OK ) rc = rc2; } if( rc==SQLITE_OK && iOrigin!=0 ){ rc = sqlite3Fts5IndexContentlessDelete(p->pIndex, iOrigin, iDel); + p->nTotalRow--; } return rc; @@ -265202,51 +266674,6 @@ static int fts5StorageInsertDocsize( return rc; } -/* -** Load the contents of the "averages" record from disk into the -** p->nTotalRow and p->aTotalSize[] variables. If successful, and if -** argument bCache is true, set the p->bTotalsValid flag to indicate -** that the contents of aTotalSize[] and nTotalRow are valid until -** further notice. -** -** Return SQLITE_OK if successful, or an SQLite error code if an error -** occurs. -*/ -static int fts5StorageLoadTotals(Fts5Storage *p, int bCache){ - int rc = SQLITE_OK; - if( p->bTotalsValid==0 ){ - rc = sqlite3Fts5IndexGetAverages(p->pIndex, &p->nTotalRow, p->aTotalSize); - p->bTotalsValid = bCache; - } - return rc; -} - -/* -** Store the current contents of the p->nTotalRow and p->aTotalSize[] -** variables in the "averages" record on disk. -** -** Return SQLITE_OK if successful, or an SQLite error code if an error -** occurs. -*/ -static int fts5StorageSaveTotals(Fts5Storage *p){ - int nCol = p->pConfig->nCol; - int i; - Fts5Buffer buf; - int rc = SQLITE_OK; - memset(&buf, 0, sizeof(buf)); - - sqlite3Fts5BufferAppendVarint(&rc, &buf, p->nTotalRow); - for(i=0; iaTotalSize[i]); - } - if( rc==SQLITE_OK ){ - rc = sqlite3Fts5IndexSetAverages(p->pIndex, buf.p, buf.n); - } - sqlite3_free(buf.p); - - return rc; -} - /* ** Remove a row from the FTS table. */ @@ -265908,19 +267335,6 @@ static void sqlite3Fts5StorageStmtRelease( } } -static int fts5StorageDecodeSizeArray( - int *aCol, int nCol, /* Array to populate */ - const u8 *aBlob, int nBlob /* Record to read varints from */ -){ - int i; - int iOff = 0; - for(i=0; i=nBlob ) return 1; - iOff += fts5GetVarint32(&aBlob[iOff], aCol[i]); - } - return (iOff!=nBlob); -} - /* ** Argument aCol points to an array of integers containing one entry for ** each table column. This function reads the %_docsize record for the @@ -266763,9 +268177,9 @@ static int fts5Porter_Ostar(char *zStem, int nStem){ for(i=0; inConstraint; i++){ struct sqlite3_index_constraint *p = &pInfo->aConstraint[i]; if( p->usable==0 ) continue; - if( p->iColumn==0 ){ /* term column */ + if( p->iColumn==0 && fts5VocabIsBinary(pInfo, i) ){ /* term column */ if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ) iTermEq = i; if( p->op==SQLITE_INDEX_CONSTRAINT_LE ) iTermLe = i; if( p->op==SQLITE_INDEX_CONSTRAINT_LT ) iTermLe = i; @@ -269289,6 +270711,26 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ return rc; } +/* +** If value pVal is an SQLITE_TEXT value, return a pointer to a buffer +** containing the UTF-8 representation of the value, and set output +** parameter (*pnText) to the size of the buffer contents in bytes. Or, +** if pVal is some other type of value, return NULL and set (*pnText) +** to 0 before returning. +*/ +static const char *fts5VocabValueText(sqlite3_value *pVal, int *pnText){ + const char *zRet = 0; + int nRet = 0; + + if( sqlite3_value_type(pVal)==SQLITE_TEXT ){ + zRet = (const char*)sqlite3_value_text(pVal); + nRet = sqlite3_value_bytes(pVal); + } + + *pnText = nRet; + return zRet; +} + /* ** This is the xFilter implementation for the virtual table. */ @@ -269316,24 +270758,30 @@ static int fts5VocabFilterMethod( UNUSED_PARAM2(zUnused, nUnused); fts5VocabResetCursor(pCsr); - if( idxNum & FTS5_VOCAB_TERM_EQ ) pEq = apVal[iVal++]; - if( idxNum & FTS5_VOCAB_TERM_GE ) pGe = apVal[iVal++]; - if( idxNum & FTS5_VOCAB_TERM_LE ) pLe = apVal[iVal++]; + if( idxNum & FTS5_VOCAB_TERM_EQ ){ + pEq = apVal[iVal++]; + if( sqlite3_value_type(pEq)!=SQLITE_TEXT ) pEq = 0; + } + if( idxNum & FTS5_VOCAB_TERM_GE ){ + pGe = apVal[iVal++]; + if( sqlite3_value_type(pGe)!=SQLITE_TEXT ) pGe = 0; + } + if( idxNum & FTS5_VOCAB_TERM_LE ){ + pLe = apVal[iVal++]; + if( sqlite3_value_type(pLe)!=SQLITE_TEXT ) pLe = 0; + } pCsr->colUsed = (idxNum & FTS5_VOCAB_COLUSED_MASK); if( pEq ){ - zTerm = (const char *)sqlite3_value_text(pEq); - nTerm = sqlite3_value_bytes(pEq); + zTerm = fts5VocabValueText(pEq, &nTerm); f = FTS5INDEX_QUERY_NOTOKENDATA; }else{ if( pGe ){ - zTerm = (const char *)sqlite3_value_text(pGe); - nTerm = sqlite3_value_bytes(pGe); + zTerm = fts5VocabValueText(pGe, &nTerm); } if( pLe ){ - const char *zCopy = (const char *)sqlite3_value_text(pLe); + const char *zCopy = fts5VocabValueText(pLe, &pCsr->nLeTerm); if( zCopy==0 ) zCopy = ""; - pCsr->nLeTerm = sqlite3_value_bytes(pLe); pCsr->zLeTerm = sqlite3_malloc64((i64)pCsr->nLeTerm+1); if( pCsr->zLeTerm==0 ){ rc = SQLITE_NOMEM; @@ -270093,10 +271541,10 @@ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } #define SQLITE3MC_VERSION_H_ #define SQLITE3MC_VERSION_MAJOR 2 -#define SQLITE3MC_VERSION_MINOR 5 +#define SQLITE3MC_VERSION_MINOR 6 #define SQLITE3MC_VERSION_RELEASE 1 #define SQLITE3MC_VERSION_SUBRELEASE 0 -#define SQLITE3MC_VERSION_STRING "SQLite3 Multiple Ciphers 2.5.1" +#define SQLITE3MC_VERSION_STRING "SQLite3 Multiple Ciphers 2.6.1" #endif /* SQLITE3MC_VERSION_H_ */ /*** End of #include "sqlite3mc_version.h" ***/ @@ -270255,12 +271703,12 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.53.4" -#define SQLITE_VERSION_NUMBER 3053004 -#define SQLITE_SOURCE_ID "2026-07-24 19:02:57 bf7c7f30031888f4e796e429ab3978879485813aaca6f641c7b33e4e09459bcc" -#define SQLITE_SCM_BRANCH "branch-3.53" -#define SQLITE_SCM_TAGS "release version-3.53.4" -#define SQLITE_SCM_DATETIME "2026-07-24T19:02:57.525Z" +#define SQLITE_VERSION "3.54.0" +#define SQLITE_VERSION_NUMBER 3054000 +#define SQLITE_SOURCE_ID "2026-10-09 15:46:58 be8d059e9a49089ab2dce5ed26dd87aaf598fdc5fbe0b107c0dd758464bcd5e3" +#define SQLITE_SCM_BRANCH "trunk" +#define SQLITE_SCM_TAGS "release major-release version-3.54.0" +#define SQLITE_SCM_DATETIME "2026-10-09T15:46:58.543Z" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -270572,7 +272020,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_FULL 13 /* Insertion failed because database is full */ #define SQLITE_CANTOPEN 14 /* Unable to open the database file */ #define SQLITE_PROTOCOL 15 /* Database lock protocol error */ -#define SQLITE_EMPTY 16 /* Internal use only */ +#define SQLITE_EMPTY 16 /* No content */ #define SQLITE_SCHEMA 17 /* The database schema changed */ #define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ #define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ @@ -273069,8 +274517,9 @@ SQLITE_API int sqlite3_is_interrupted(sqlite3*); ** These routines are useful during command-line input to determine if the ** currently entered text seems to form a complete SQL statement or ** if additional input is needed before sending the text into -** SQLite for parsing. ^These routines return 1 if the input string -** appears to be a complete SQL statement. ^A statement is judged to be +** SQLite for parsing. ^The sqlite3_complete(X) and sqlite3_complete16(X) +** routines return 1 if the input string X appears to be a complete SQL +** statement. ^A statement is judged to be ** complete if it ends with a semicolon token and is not a prefix of a ** well-formed CREATE TRIGGER statement. ^Semicolons that are embedded within ** string literals or quoted identifier names or comments are not @@ -273078,11 +274527,25 @@ SQLITE_API int sqlite3_is_interrupted(sqlite3*); ** embedded) and thus do not count as a statement terminator. ^Whitespace ** and comments that follow the final semicolon are ignored. ** -** ^These routines return 0 if the statement is incomplete. ^If a -** memory allocation fails, then SQLITE_NOMEM is returned. +** ^The sqlite3_complete(X) and sqlite3_complete16(X) routines return 0 +** if the statement is incomplete. ^If a memory allocation fails, then +** SQLITE_NOMEM is returned. ** -** ^These routines do not parse the SQL statements and thus -** will not detect syntactically incorrect SQL. +** The [sqlite3_incomplete(X)] routine is similar to [sqlite3_complete(X)] +** except that sqlite3_incomplete(X) returns SQLITE_OK if the input X is +** complete, SQLITE_EMPTY if input X consists entirely of whitespace and/or +** comments, SQLITE_MISUSE if X is a NULL pointer, and some other non-zero +** value if X is incomplete. The non-zero return from +** sqlite3_incomplete(X) contains additional information about what is +** needed to complete the input X. See the header comment on the +** implemenation of the sqlite3_incomplete() routine for a full description +** of its non-zero return values. The sqlite3_incomplete(X) interface +** is only available for UTF-8 text. +** +** ^None of these routines do a full parse the SQL statements and thus +** will not detect syntactically incorrect SQL. They only determine if +** input text has properly terminated comments, string literals, and +** quoted identifiers, and if the statement ends with a semicolon. ** ** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior ** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked @@ -273090,14 +274553,15 @@ SQLITE_API int sqlite3_is_interrupted(sqlite3*); ** then the return value from sqlite3_complete16() will be non-zero ** regardless of whether or not the input SQL is complete.)^ ** -** The input to [sqlite3_complete()] must be a zero-terminated -** UTF-8 string. +** The X input to [sqlite3_complete(X)] and [sqlite3_incomplete(X)] +** must be a zero-terminated UTF-8 string. ** ** The input to [sqlite3_complete16()] must be a zero-terminated ** UTF-16 string in native byte order. */ SQLITE_API int sqlite3_complete(const char *sql); SQLITE_API int sqlite3_complete16(const void *sql); +SQLITE_API sqlite3_int64 sqlite3_incomplete(const char *sql); /* ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors @@ -273510,7 +274974,7 @@ SQLITE_API void sqlite3_randomness(int N, void *P); ** ** ^The first parameter to the authorizer callback is a copy of the third ** parameter to the sqlite3_set_authorizer() interface. ^The second parameter -** to the callback is an integer [SQLITE_COPY | action code] that specifies +** to the callback is an integer [SQLITE_READ | action code] that specifies ** the particular action to be authorized. ^The third through sixth parameters ** to the callback are either NULL pointers or zero-terminated strings ** that contain additional details about the action to be authorized. @@ -273553,21 +275017,33 @@ SQLITE_API void sqlite3_randomness(int N, void *P); ** previous call.)^ ^Disable the authorizer by installing a NULL callback. ** The authorizer is disabled by default. ** -** The authorizer callback must not do anything that will modify +**

    Limitations And Caveats

      +** +**
    • The authorizer callback must not do anything that will modify ** the database connection that invoked the authorizer callback. ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their ** database connections for the meaning of "modify" in this paragraph. ** -** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the +**
    • ^When [sqlite3_prepare_v2()] is used to prepare a statement, the ** statement might be re-prepared during [sqlite3_step()] due to a ** schema change. Hence, the application should ensure that the ** correct authorizer callback remains in place during the [sqlite3_step()]. ** -** ^Note that the authorizer callback is invoked only during +**
    • ^The authorizer callback is invoked only during ** [sqlite3_prepare()] or its variants. Authorization is not ** performed during statement evaluation in [sqlite3_step()], unless ** as stated in the previous paragraph, sqlite3_step() invokes ** sqlite3_prepare_v2() to reprepare a statement after a schema change. +** +**
    • Authorizer callbacks for the expressions of a +** [generated column] are invoked when the schema is parsed (and specifically +** when the [CREATE TABLE] statement that contains the generated column is +** parsed) not when the generated column is used in a DML statement. +** This is deliberate, as one of the purposes of generated columns +** is to give schema designers the ability to provide gated access +** to privileged columns and/or functions. +** +**
    */ SQLITE_API int sqlite3_set_authorizer( sqlite3*, @@ -273608,6 +275084,11 @@ SQLITE_API int sqlite3_set_authorizer( ** is the name of the inner-most trigger or view that is responsible for ** the access attempt or NULL if this access attempt is directly from ** top-level SQL code. +** +** The case of strings in the 3rd through the 6th argument to the +** authorization callback is arbitrary. Authorization callbacks +** implementations should use [sqlite3_stricmp()] or similar when +** doing comparisons against those values. */ /******************************************* 3rd ************ 4th ***********/ #define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */ @@ -273642,9 +275123,14 @@ SQLITE_API int sqlite3_set_authorizer( #define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */ #define SQLITE_FUNCTION 31 /* NULL Function Name */ #define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ -#define SQLITE_COPY 0 /* No longer used */ #define SQLITE_RECURSIVE 33 /* NULL NULL */ +/* +** Note: The SQLITE_COPY macro (with value 0) used to be one of the +** action codes above. That macro has now been repurposed as a possible +** value to the 3rd argument to sqlite3_result_str(). +*/ + /* ** CAPI3REF: Deprecated Tracing And Profiling Functions ** DEPRECATED @@ -274151,8 +275637,7 @@ SQLITE_API int sqlite3_open_v2( ** ** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a ** 64-bit signed integer and returns that integer, or D if P does not -** exist. If the value of P is something other than an integer, then -** zero is returned. +** exist or if the value of P is something other than an integer. ** ** The sqlite3_uri_key(F,N) returns a pointer to the name (not ** the value) of the N-th query parameter for filename F, or a NULL @@ -274513,6 +275998,14 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** [[SQLITE_LIMIT_WORKER_THREADS]] ^(
    SQLITE_LIMIT_WORKER_THREADS
    **
    The maximum number of auxiliary worker threads that a single ** [prepared statement] may start.
    )^ +** +** [[SQLITE_LIMIT_SCHEMA]] ^(
    SQLITE_LIMIT_SCHEMA
    +**
    The maximum number of objects (tables, indexes, triggers, and views) +** defined by the database schema.
    )^ +** +** [[SQLITE_LIMIT_TRIGGER_STEPS]] ^(
    SQLITE_LIMIT_TRIGGER_STEPS
    +**
    The maximum number of SQL statements that can be contained within +** a single trigger.
    )^ ** */ #define SQLITE_LIMIT_LENGTH 0 @@ -274528,6 +276021,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); #define SQLITE_LIMIT_TRIGGER_DEPTH 10 #define SQLITE_LIMIT_WORKER_THREADS 11 #define SQLITE_LIMIT_PARSER_DEPTH 12 +#define SQLITE_LIMIT_SCHEMA 13 +#define SQLITE_LIMIT_TRIGGER_STEPS 14 /* ** CAPI3REF: Prepare Flags @@ -274639,6 +276134,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** the nul-terminator. ** Note that nByte measures the length of the input in bytes, not ** characters, even for the UTF-16 interfaces. +** For the sqlite3_prepare16() and sqlite3_prepare16_v2() interfaces, +** the nByte value must be even or undefined behavior can result. ** ** ^If pzTail is not NULL then *pzTail is made to point to the first byte ** past the end of the first SQL statement in zSql. These routines only @@ -275385,7 +276882,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** [prepared statement]. ^In the "v2" interface, ** the more specific error code is returned directly by sqlite3_step(). ** -** [SQLITE_MISUSE] means that the this routine was called inappropriately. +** [SQLITE_MISUSE] means that this routine was called inappropriately. ** Perhaps it was called on a [prepared statement] that has ** already been [sqlite3_finalize | finalized] or on one that had ** previously returned [SQLITE_ERROR] or [SQLITE_DONE]. Or it could @@ -276558,7 +278055,11 @@ typedef void (*sqlite3_destructor_type)(void*); ** ** ^The sqlite3_result_zeroblob(C,N) and sqlite3_result_zeroblob64(C,N) ** interfaces set the result of the application-defined function to be -** a BLOB containing all zero bytes and N bytes in size. +** a BLOB containing all zero bytes and N bytes in size. The +** zeroblob64(C,N) interface returns a [result code], which is normally +** [SQLITE_OK] but might be some other value if the requested operation +** could not be complete, for example if insufficient memory is available +** or if the value of N is out of range. ** ** ^The sqlite3_result_double() interface sets the result from ** an application-defined function to be a floating point value specified @@ -278896,8 +280397,8 @@ SQLITE_API int sqlite3_keyword_check(const char*,int); **
  • ^The sqlite3_str object is created using [sqlite3_str_new()]. **
  • ^Text is appended to the sqlite3_str object using various ** methods, such as [sqlite3_str_appendf()]. -**
  • ^The sqlite3_str object is destroyed and the string it created -** is returned using the [sqlite3_str_finish()] interface. +**
  • The sqlite3_str object is destroyed and the string it created +** is returned using [sqlite3_str_finish()] or [sqlite3_result_str()]. ** */ typedef struct sqlite3_str sqlite3_str; @@ -278949,6 +280450,40 @@ SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3*); SQLITE_API char *sqlite3_str_finish(sqlite3_str*); SQLITE_API void sqlite3_str_free(sqlite3_str*); +/* +** CAPI3REF: Return A Dynamic String From an SQL Function +** +** The [sqlite3_result_str(C,S,F)] interface causes the +** [sqlite3_str|dynamic string] S to become the return value for the +** application-defined function or virtual table that uses +** [sqlite3_context] C. The F flag can be one of [SQLITE_COPY] +** or [SQLITE_XFER] or [SQLITE_FINISH]. +** +** If the dynamic string is invalid or incomplete due to an out-of-memory +** or string-too-large error, then this routine transfers that error +** over to the SQL function. +** +** If the F argument is SQLITE_COPY, then a copy of the dynamic string +** content is made and the dynamic string object is unchanged. +** If the F argument is SQLITE_XFER, then ownership of the content +** in the dynamic is transferred to the SQL function (via a pointer copy +** rather than a string copy) and the dynamic string is reset to an +** empty string. The SQLITE_FINISH value for F works like SQLITE_RESET +** except that it also invokes the [sqlite3_str_free(S)] destructor +** on the dynamic string object. +*/ +SQLITE_API void sqlite3_result_str(sqlite3_context*, sqlite3_str*, int); + +/* +** CAPI3REF: Control Flags For sqlite3_result_str() +** +** The following integers can be used as the third "F" argument +** to [sqlite3_result_str(C,S,F)]. +*/ +#define SQLITE_COPY 0 /* Results copied. Dynamic string unchanged */ +#define SQLITE_XFER 1 /* Results transfered. Dynamic string reset */ +#define SQLITE_FINISH 2 /* Like SQLITE_XFER, plus dynamic string freed */ + /* ** CAPI3REF: Add Content To A Dynamic String ** METHOD: sqlite3_str @@ -281314,8 +282849,19 @@ SQLITE_API unsigned char *sqlite3_serialize( ** used. The serialized database P is N bytes in size. M is the size ** of the buffer P, which might be larger than N. If M is larger than ** N, and the SQLITE_DESERIALIZE_READONLY bit is not set in F, then -** SQLite is permitted to add content to the in-memory database as -** long as the total size does not exceed M bytes. +** SQLite is permitted to add content to the in-memory database, in +** page-sized chunks, as long as the total size does not exceed M bytes. +** +** The parameter M must be greater than or equal to N. Ideally, M +** should have a value which is N+(512×K)+20 where K determines how +** must extra space is available to hold new content as the database +** grows. K can be 0 if the database is read-only. +** +** If the database content in P is malformed in a malicious way then +** it is possible that SQLite might try to read a few more than N bytes +** from P. If the veracity of the database content P is uncertain, +** then applications are advised to allocate about 20 extra bytes on +** the end of the P buffer to avoid a memory error. ** ** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will ** invoke sqlite3_free() on the serialization buffer when the database @@ -284840,7 +286386,7 @@ struct sqlite3_api_routines { const char * (*libversion)(void); int (*libversion_number)(void); void *(*malloc)(int); - char * (*mprintf)(const char*,...); + char *(SQLITE_CDECL*mprintf)(const char*,...); int (*open)(const char*,sqlite3**); int (*open16)(const void*,sqlite3**); int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); @@ -284861,11 +286407,11 @@ struct sqlite3_api_routines { void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*)); void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*)); void (*result_value)(sqlite3_context*,sqlite3_value*); - void * (*rollback_hook)(sqlite3*,void(*)(void*),void*); + void *(*rollback_hook)(sqlite3*,void(*)(void*),void*); int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, const char*,const char*),void*); void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); - char * (*xsnprintf)(int,char*,const char*,...); + char *(SQLITE_CDECL*xsnprintf)(int,char*,const char*,...); int (*step)(sqlite3_stmt*); int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, char const**,char const**,int*,int*,int*); @@ -284929,7 +286475,7 @@ struct sqlite3_api_routines { int (*xthreadsafe)(void); void (*result_zeroblob)(sqlite3_context*,int); void (*result_error_code)(sqlite3_context*,int); - int (*test_control)(int, ...); + int (SQLITE_CDECL*test_control)(int, ...); void (*randomness)(int,void*); sqlite3 *(*context_db_handle)(sqlite3_context*); int (*extended_result_codes)(sqlite3*,int); @@ -284949,11 +286495,11 @@ struct sqlite3_api_routines { void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*), void(*xDestroy)(void*)); - int (*db_config)(sqlite3*,int,...); + int (SQLITE_CDECL*db_config)(sqlite3*,int,...); sqlite3_mutex *(*db_mutex)(sqlite3*); int (*db_status)(sqlite3*,int,int*,int*,int); int (*extended_errcode)(sqlite3*); - void (*log)(int,const char*,...); + void (SQLITE_CDECL*log)(int,const char*,...); sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64); const char *(*sourceid)(void); int (*stmt_status)(sqlite3_stmt*,int,int); @@ -284963,7 +286509,7 @@ struct sqlite3_api_routines { int (*wal_checkpoint)(sqlite3*,const char*); void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); - int (*vtab_config)(sqlite3*,int op,...); + int (SQLITE_CDECL*vtab_config)(sqlite3*,int op,...); int (*vtab_on_conflict)(sqlite3*); /* Version 3.7.16 and later */ int (*close_v2)(sqlite3*); @@ -285032,7 +286578,7 @@ struct sqlite3_api_routines { int (*keyword_check)(const char*,int); sqlite3_str *(*str_new)(sqlite3*); char *(*str_finish)(sqlite3_str*); - void (*str_appendf)(sqlite3_str*, const char *zFormat, ...); + void (SQLITE_CDECL*str_appendf)(sqlite3_str*, const char *zFormat, ...); void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list); void (*str_append)(sqlite3_str*, const char *zIn, int N); void (*str_appendall)(sqlite3_str*, const char *zIn); @@ -285107,6 +286653,9 @@ struct sqlite3_api_routines { void (*str_free)(sqlite3_str*); int (*carray_bind)(sqlite3_stmt*,int,void*,int,int,void(*)(void*)); int (*carray_bind_v2)(sqlite3_stmt*,int,void*,int,int,void(*)(void*),void*); + /* Version 3.54.0 and later */ + sqlite3_int64 (*incomplete)(const char*); + void (*result_str)(sqlite3_context*,sqlite3_str*,int); }; /* @@ -285450,6 +286999,9 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_str_free sqlite3_api->str_free #define sqlite3_carray_bind sqlite3_api->carray_bind #define sqlite3_carray_bind_v2 sqlite3_api->carray_bind_v2 +/* Version 3.54.0 and later */ +#define sqlite3_incomplete sqlite3_api->incomplete +#define sqlite3_result_str sqlite3_api->result_str #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) @@ -285647,6 +287199,495 @@ SQLITE_PRIVATE int sqlite3mcGetMemorySecurity(); #endif +/* +** Check for hardware features +*/ +/* #include "hwcheck.c" */ +/*** Begin of #include "hwcheck.c" ***/ +/* +** Name: hwcheck.c +** Purpose: Check hardware features +** Author: Ulrich Telle +** Copyright: (c) 2026 Ulrich Telle +** License: MIT +*/ + +/* +** Identify target architecture +*/ + +#if defined(__ARM_NEON) || defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) +# define SQLITE3MC_TARGET_ARM 1 +# if defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) +# define SQLITE3MC_TARGET_ARM64 1 +# endif +#elif defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) +# define SQLITE3MC_TARGET_X86 1 +# if defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) +# define SQLITE3MC_TARGET_X86_64 1 +# endif +#elif defined(__powerpc__) || defined(__PPC__) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) +# define SQLITE3MC_TARGET_PPC 1 +#elif defined(__wasm__) || defined(__wasi__) +# define SQLITE3MC_TARGET_WASM 1 +#else +# define SQLITE3MC_TARGET_UNKNOWN 1 +#endif + +/* +** Define SQLITE3MC_COMPILER_HAS_ATTRIBUTE / SQLITE3MC_FUNC_ISA etc. +*/ + +#if defined(__has_attribute) + #define SQLITE3MC_COMPILER_HAS_ATTRIBUTE(x) __has_attribute(x) + #define SQLITE3MC_COMPILER_ATTRIBUTE(x) __attribute__((x)) +#else + #define SQLITE3MC_COMPILER_HAS_ATTRIBUTE(x) 0 + #define SQLITE3MC_COMPILER_ATTRIBUTE(x) /**/ +#endif + +#if !defined(SQLITE3MC_FORCE_INLINE) + #if SQLITE3MC_COMPILER_HAS_ATTRIBUTE(always_inline) + #define SQLITE3MC_FORCE_INLINE inline SQLITE3MC_COMPILER_ATTRIBUTE(always_inline) + #elif defined(_MSC_VER) + #define SQLITE3MC_FORCE_INLINE __forceinline + #else + #define SQLITE3MC_FORCE_INLINE inline + #endif +#endif + +#if SQLITE3MC_COMPILER_HAS_ATTRIBUTE(target) + #define SQLITE3MC_FUNC_ISA(isa) SQLITE3MC_COMPILER_ATTRIBUTE(target(isa)) +#else + #define SQLITE3MC_FUNC_ISA(isa) +#endif + +#define SQLITE3MC_FUNC_ISA_INLINE(isa) SQLITE3MC_FUNC_ISA(isa) SQLITE3MC_FORCE_INLINE + +/* +** Determine hardware support for AES +*/ + +#define AES_HARDWARE_NONE 0 +#define AES_HARDWARE_NI 1 +#define AES_HARDWARE_NEON 2 + +#ifndef SQLITE3MC_OMIT_AES_HARDWARE_SUPPORT +/* +** Use AES hardware, if available +*/ + +# if defined(__clang__) + /* --- CLang --- */ +# if __has_attribute(target) && __has_include() && (defined(__x86_64__) || defined(__i386__)) +# define HAS_AES_HARDWARE AES_HARDWARE_NI +# elif __has_attribute(target) && __has_include() && (defined(__aarch64__)) +# define HAS_AES_HARDWARE AES_HARDWARE_NEON + /* Crypto extension in AArch64 can be enabled using __attribute__((target)) */ +# define USE_ATTR_TARGET_AARCH64 +# endif +# elif defined(__GNUC__) + /* --- GNU C/C++ */ +# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) && (defined(__x86_64__) || defined(__i386__)) +# define HAS_AES_HARDWARE AES_HARDWARE_NI +# elif defined(__ARM_FEATURE_CRYPTO) && defined(__aarch64__) +# define HAS_AES_HARDWARE AES_HARDWARE_NEON +# elif (__GNUC__ >= 6) && defined(__aarch64__) +# define HAS_AES_HARDWARE AES_HARDWARE_NEON +# define USE_ATTR_TARGET_AARCH64 +# endif +# elif defined (_MSC_VER) + /* --- Visual C/C++ --- */ +# if defined(_M_ARM64) || defined(_M_ARM64EC) + /* Architecture: ARM 64-bit */ +# define HAS_AES_HARDWARE AES_HARDWARE_NEON + /* Use header instead of */ +# define USE_ARM64_NEON_H +# elif (defined(_M_X64) || defined(_M_IX86)) && _MSC_FULL_VER >= 150030729 + /* Architecture: x86 or x86_64 */ +# define HAS_AES_HARDWARE AES_HARDWARE_NI +# elif defined _M_ARM + /* Architecture: ARM 32-bit */ +# define HAS_AES_HARDWARE AES_HARDWARE_NEON + /* The following #define is required to enable intrinsic definitions + that do not omit one of the parameters for vaes[ed]q_u8 */ +# define _ARM_USE_NEW_NEON_INTRINSICS +# endif +# elif defined(__ARM_FEATURE_CRYPTO) +# define HAS_AES_HARDWARE AES_HARDWARE_NEON +# elif defined(SQLITE3MC_TARGET_WASM) +# define HAS_AES_HARDWARE AES_HARDWARE_NONE +# else +# define HAS_AES_HARDWARE AES_HARDWARE_NONE +# endif +#else /* SQLITE3MC_OMIT_AES_HARDWARE_SUPPORT defined */ + /* Omit AES hardware support */ +# define HAS_AES_HARDWARE AES_HARDWARE_NONE +#endif /* SQLITE3MC_OMIT_AES_HARDWARE_SUPPORT */ + +/* +** Determine CPU features at runtime +*/ + +#define SQLITE3MC_CPU_NONE 0x0000 +#define SQLITE3MC_CPU_SSE2 0x0001 +#define SQLITE3MC_CPU_SSSE3 0x0002 +#define SQLITE3MC_CPU_SSE41 0x0004 +#define SQLITE3MC_CPU_SSE42 0x0008 +#define SQLITE3MC_CPU_AVX 0x0010 +#define SQLITE3MC_CPU_AVX2 0x0020 +#define SQLITE3MC_CPU_AVX512F 0x0040 +#define SQLITE3MC_CPU_AESNI 0x0080 +#define SQLITE3MC_CPU_NEON 0x0100 +#define SQLITE3MC_CPU_ARMCRYPTO 0x0200 +#define SQLITE3MC_CPU_ALTIVEC 0x0400 + +#if defined(SQLITE3MC_TARGET_ARM) +/* +** ARM +*/ + +# if defined(__linux__) + +#include +#include + +static int +aesHardwareAvailableOnPlatform() +{ +#if defined HWCAP_AES + return getauxval(AT_HWCAP) & HWCAP_AES; +#elif defined HWCAP2_AES + return getauxval(AT_HWCAP2) & HWCAP2_AES; +#else + return 0; +#endif +} + +# elif (defined(__FreeBSD__) || defined(__OpenBSD__) /*|| defined(__NetBSD__)*/) && defined(__aarch64__) + +#include + +/* + * Feature detection for elf_aux_info(): + * - FreeBSD: Available since version 12.0 (__FreeBSD_version >= 1200000) + * - OpenBSD: Available since Version 7.6 (OpenBSD >= 202410) + */ +#if (defined(__FreeBSD__) && defined(__FreeBSD_version) && __FreeBSD_version >= 1200000) || \ + (defined(__OpenBSD__) && defined(OpenBSD) && OpenBSD >= 202410) +#define HAVE_ELF_AUX_INFO 1 +#include +#endif + +#ifndef HWCAP_AES +# define HWCAP_AES (1UL << 3) +#endif + +static int +aesHardwareAvailableOnPlatform() +{ +#ifdef HAVE_ELF_AUX_INFO + unsigned long hwcap; + if (elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)) != 0) + return 0; + return (hwcap & HWCAP_AES) != 0; +#else + return 0; +#endif +} + +# elif defined(__APPLE__) && defined(__aarch64__) /* macOS/iOS Apple Silicon */ + +static int +aesHardwareAvailableOnPlatform() +{ + return 1; /* ARMv8-Crypto mandatory on Apple Silicon */ +} + +# elif defined(_WIN32) && (defined _M_ARM || defined _M_ARM64 || defined(_M_ARM64EC)) + +static int +aesHardwareAvailableOnPlatform() +{ + return (int) IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); +} + +# else + +static int +aesHardwareAvailableOnPlatform() +{ + return 0; +} + +# endif +#endif + +#if defined(SQLITE3MC_TARGET_ARM) + +static unsigned int +mcCpuFeaturesArm(void) +{ + unsigned int features = SQLITE3MC_CPU_NONE; +#if defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) + features |= SQLITE3MC_CPU_NEON; /* mandatory on AArch64 architecture */ +#elif defined(__ARM_NEON) + features |= SQLITE3MC_CPU_NEON; /* 32-Bit: selected as compile target */ +#endif + if (aesHardwareAvailableOnPlatform()) + features |= SQLITE3MC_CPU_ARMCRYPTO; + return features; +} + +#elif defined(SQLITE3MC_TARGET_X86) +/* +** Intel +*/ + +/* Define SQLITE3MC_COMPILER_HAS_ATTRIBUTE */ +#if defined(__has_attribute) + #define SQLITE3MC_COMPILER_HAS_ATTRIBUTE(x) __has_attribute(x) + #define SQLITE3MC_COMPILER_ATTRIBUTE(x) __attribute__((x)) +#else + #define SQLITE3MC_COMPILER_HAS_ATTRIBUTE(x) 0 + #define SQLITE3MC_COMPILER_ATTRIBUTE(x) /**/ +#endif + +/* Define SQLITE3MC_FORCE_INLINE */ +#if !defined(SQLITE3MC_FORCE_INLINE) + #if SQLITE3MC_COMPILER_HAS_ATTRIBUTE(always_inline) + #define SQLITE3MC_FORCE_INLINE inline SQLITE3MC_COMPILER_ATTRIBUTE(always_inline) + #elif defined(_MSC_VER) + #define SQLITE3MC_FORCE_INLINE __forceinline + #else + #define SQLITE3MC_FORCE_INLINE inline + #endif +#endif + +/* Define SQLITE3MC_FUNC_ISA */ +#if SQLITE3MC_COMPILER_HAS_ATTRIBUTE(target) + #define SQLITE3MC_FUNC_ISA(isa) SQLITE3MC_COMPILER_ATTRIBUTE(target(isa)) +#else + #define SQLITE3MC_FUNC_ISA(isa) +#endif + +/* Define SQLITE3MC_FUNC_ISA_INLINE */ +#define SQLITE3MC_FUNC_ISA_INLINE(isa) SQLITE3MC_FUNC_ISA(isa) SQLITE3MC_FORCE_INLINE + + +#if defined(__clang__) || defined(__GNUC__) +#include +#include + +SQLITE3MC_FUNC_ISA("xsave") +static unsigned int +mcCpuFeaturesX86(void) +{ + unsigned int features = SQLITE3MC_CPU_NONE; + unsigned int eax, ebx, ecx, edx; + + if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) + { + if (edx & (1u << 26)) features |= SQLITE3MC_CPU_SSE2; + if (ecx & (1u << 9)) features |= SQLITE3MC_CPU_SSSE3; + if (ecx & (1u << 19)) features |= SQLITE3MC_CPU_SSE41; + if (ecx & (1u << 20)) features |= SQLITE3MC_CPU_SSE42; + /* Bisherige AES-Bedingung (Bit 25 UND Bit 19) bleibt inhaltlich erhalten, + ergibt sich jetzt aus AESNI- und SSE41-Flag gemeinsam */ + if (ecx & (1u << 25)) features |= SQLITE3MC_CPU_AESNI; + + if (ecx & (1u << 27)) /* OSXSAVE */ + { + unsigned long long xcr0 = _xgetbv(0); + int osAvx = (xcr0 & 0x6) == 0x6; + int osAvx512 = (xcr0 & 0xE6) == 0xE6; + + if (osAvx && (ecx & (1u << 28))) features |= SQLITE3MC_CPU_AVX; + + if (__get_cpuid_count(7, 0, &eax, &ebx, &ecx, &edx)) + { + if (osAvx && (ebx & (1u << 5))) features |= SQLITE3MC_CPU_AVX2; + if (osAvx512 && (ebx & (1u << 16))) features |= SQLITE3MC_CPU_AVX512F; + } + } + } + return features; +} +#elif defined(_MSC_VER) +#include + +static unsigned int +mcCpuFeaturesX86(void) +{ + unsigned int features = SQLITE3MC_CPU_NONE; + int cpuInfo[4]; + + __cpuid(cpuInfo, 1); + if (cpuInfo[3] & (1u << 26)) features |= SQLITE3MC_CPU_SSE2; + if (cpuInfo[2] & (1u << 9)) features |= SQLITE3MC_CPU_SSSE3; + if (cpuInfo[2] & (1u << 19)) features |= SQLITE3MC_CPU_SSE41; + if (cpuInfo[2] & (1u << 20)) features |= SQLITE3MC_CPU_SSE42; + if (cpuInfo[2] & (1u << 25)) features |= SQLITE3MC_CPU_AESNI; + + if (cpuInfo[2] & (1u << 27)) /* OSXSAVE */ + { + unsigned long long xcr0 = _xgetbv(0); + int osAvx = (xcr0 & 0x6) == 0x6; + int osAvx512 = (xcr0 & 0xE6) == 0xE6; + + if (osAvx && (cpuInfo[2] & (1u << 28))) features |= SQLITE3MC_CPU_AVX; + + __cpuidex(cpuInfo, 7, 0); + if (osAvx && (cpuInfo[1] & (1u << 5))) features |= SQLITE3MC_CPU_AVX2; + if (osAvx512 && (cpuInfo[1] & (1u << 16))) features |= SQLITE3MC_CPU_AVX512F; + } + return features; +} +#else +/* Unknown compiler: no hardware detection, safe fallback */ +static unsigned int +mcCpuFeaturesX86(void) +{ + return SQLITE3MC_CPU_NONE; +} +#endif + +#elif defined(SQLITE3MC_TARGET_PPC) +/* +** PowerPC / POWER +*/ + +static unsigned int +mcCpuFeaturesPpc(void) +{ +#if defined(__ALTIVEC__) && defined(__CRYPTO__) + return SQLITE3MC_CPU_ALTIVEC; +#else + return SQLITE3MC_CPU_NONE; +#endif +} + +#elif defined(SQLITE3MC_TARGET_WASM) +/* +** WASM +*/ + +static unsigned int +mcCpuFeaturesWasm(void) +{ +#if defined(__wasm_simd128__) && defined(__SSSE3__) + return SQLITE3MC_CPU_SSE2 | SQLITE3MC_CPU_SSSE3; /* functional equivalent level: 128-bit generic SIMD */ +#else + return SQLITE3MC_CPU_NONE; +#endif +} + +#endif + +static unsigned int +mcCpuFeaturesDetect(void) +{ +#if defined(SQLITE3MC_TARGET_WASM) + return mcCpuFeaturesWasm(); +#elif defined(SQLITE3MC_TARGET_ARM) + return mcCpuFeaturesArm(); +#elif defined(SQLITE3MC_TARGET_X86) + unsigned int features = mcCpuFeaturesX86(); +# if defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) + features |= SQLITE3MC_CPU_SSE2; +# endif + return features; +#elif defined(SQLITE3MC_TARGET_PPC) + return mcCpuFeaturesPpc(); +#else + return SQLITE3MC_CPU_NONE; +#endif +} + +static unsigned int +sqlite3mcCpuFeatures(void) +{ + static int mcCpuFeaturesCached = -1; /* -1 = not yet determined */ + if (mcCpuFeaturesCached < 0) + mcCpuFeaturesCached = (int) mcCpuFeaturesDetect(); + return (unsigned int) mcCpuFeaturesCached; +} + +/* +** The top-level selection function, caching the results of +** aesHardwareCheck() so it only has to run once. +*/ +static int +aesHardwareAvailable() +{ + static int initialized = 0; + static int hwAvailable = 0; + if (!initialized) + { +#if HAS_AES_HARDWARE == AES_HARDWARE_NONE + hwAvailable = 0; +#else + unsigned int features = sqlite3mcCpuFeatures(); + int x86Ok = (features & (SQLITE3MC_CPU_AESNI | SQLITE3MC_CPU_SSE42)) + == (SQLITE3MC_CPU_AESNI | SQLITE3MC_CPU_SSE42); + int armOk = (features & SQLITE3MC_CPU_ARMCRYPTO) != 0; + hwAvailable = x86Ok || armOk; +#endif + initialized = 1; + } + return hwAvailable; +} + +typedef struct _FeatureTag +{ + int flag; + const char* name; +} FeatureTag; + +static const char* +sqlite3mcHardwareInfo() +{ + FeatureTag featureTags[] = + { + { SQLITE3MC_CPU_SSE2, "sse2" }, + { SQLITE3MC_CPU_SSSE3, "ssse3" }, + { SQLITE3MC_CPU_SSE41, "sse41" }, + { SQLITE3MC_CPU_SSE42, "sse42" }, + { SQLITE3MC_CPU_AVX, "avx" }, + { SQLITE3MC_CPU_AVX2, "avx2" }, + { SQLITE3MC_CPU_AVX512F, "avx512f" }, + { SQLITE3MC_CPU_AESNI, "aesni" }, + { SQLITE3MC_CPU_NEON, "neon" }, + { SQLITE3MC_CPU_ARMCRYPTO, "armcrypto" }, + { SQLITE3MC_CPU_ALTIVEC, "altivec" }, + { 0, "" } /* Sentinel, do NOT delete */ + }; + static char hwInfoBuf[256]; + static int hwInfoBuilt = 0; + + if (!hwInfoBuilt) + { + int k = 0; + int offset = 0; + int writeDelim = 0; + unsigned int features = sqlite3mcCpuFeatures(); + while (featureTags[k].flag != 0) + { + if (features & featureTags[k].flag) + { + offset += snprintf(hwInfoBuf + offset, sizeof(hwInfoBuf) - offset, + (writeDelim == 0) ? "%s" : ",%s", featureTags[k].name); + if (offset >= sizeof(hwInfoBuf)) break; + writeDelim = 1; + } + ++k; + } + } + return hwInfoBuf; +} +/*** End of #include "hwcheck.c" ***/ + + /* ** Crypto algorithms */ @@ -287476,6 +289517,5826 @@ int main() /*** End of #include "sha2.c" ***/ +/* Prototypes for several crypto functions to make pedantic compilers happy */ +SQLITE_PRIVATE void chacha20_xor(void* data, size_t n, const uint8_t key[32], const uint8_t nonce[12], uint32_t counter); +SQLITE_PRIVATE void poly1305(const uint8_t* msg, size_t n, const uint8_t key[32], uint8_t tag[16]); +SQLITE_PRIVATE int poly1305_tagcmp(const uint8_t tag1[16], const uint8_t tag2[16]); +SQLITE_PRIVATE void chacha20_rng(void* out, size_t n); + +SQLITE_PRIVATE void sqlite3mcSecureZeroMemory(void* v, size_t n); + +/* Hardware accelerated implementation of chacha20-poly1305 */ +/* #include "chacha20/libchacha20.c" */ +/*** Begin of #include "chacha20/libchacha20.c" ***/ +#define SODIUM_STATIC + +static void +sodium_misuse() +{ + /* + ** This function does intentionally nothing. + ** It is called from sodium code, if the message length exceeds + ** the allowed maximum. + ** This never happens in the SQLite3MC context, because we are + ** dealing at most with 64k pages. + */ +} + +static void +randombytes_buf(void* const buf, const size_t size) +{ + /* We use our own random number generator */ + chacha20_rng(buf, size); +} + +static void +sodium_memzero(void* const pnt, const size_t len) +{ + /* We use our own function to securely zero out memory */ + sqlite3mcSecureZeroMemory(pnt, len); +} + +/* +** Context structure for Sodium's ChaCha20 implementation +** Definition moved here from the individual implementation files. +*/ +typedef struct chacha_ctx { + uint32_t input[16]; +} chacha_ctx; + +/* #include "src/stream_chacha20.c" */ +/*** Begin of #include "src/stream_chacha20.c" ***/ +/* #include "crypto_stream_chacha20.h" */ +/*** Begin of #include "crypto_stream_chacha20.h" ***/ +#ifndef crypto_stream_chacha20_H +#define crypto_stream_chacha20_H + +/* + * WARNING: This is just a stream cipher. It is NOT authenticated encryption. + * While it provides some protection against eavesdropping, it does NOT + * provide any security against active attacks. + * Unless you know what you're doing, what you are looking for is probably + * the crypto_box functions. + */ + +#include +#include +/* #include "export.h" */ +/*** Begin of #include "export.h" ***/ + +#ifndef sodium_export_H +#define sodium_export_H + +#include +#include +#include + +#if !defined(__clang__) && !defined(__GNUC__) +# ifdef __attribute__ +# undef __attribute__ +# endif +# define __attribute__(a) +#endif + +#ifdef SODIUM_STATIC +# define SODIUM_EXPORT +# define SODIUM_EXPORT_WEAK +#else +# if defined(_MSC_VER) +# ifdef SODIUM_DLL_EXPORT +# define SODIUM_EXPORT __declspec(dllexport) +# else +# define SODIUM_EXPORT __declspec(dllimport) +# endif +# else +# if defined(__SUNPRO_C) +# ifndef __GNU_C__ +# define SODIUM_EXPORT __attribute__ (visibility(__global)) +# else +# define SODIUM_EXPORT __attribute__ __global +# endif +# elif defined(_MSG_VER) +# define SODIUM_EXPORT extern __declspec(dllexport) +# else +# define SODIUM_EXPORT __attribute__ ((visibility ("default"))) +# endif +# endif +# if defined(__ELF__) && !defined(SODIUM_DISABLE_WEAK_FUNCTIONS) +# define SODIUM_EXPORT_WEAK SODIUM_EXPORT __attribute__((weak)) +# else +# define SODIUM_EXPORT_WEAK SODIUM_EXPORT +# endif +#endif + +#ifndef CRYPTO_ALIGN +# if defined(__INTEL_COMPILER) || defined(_MSC_VER) +# define CRYPTO_ALIGN(x) __declspec(align(x)) +# else +# define CRYPTO_ALIGN(x) __attribute__ ((aligned(x))) +# endif +#endif + +#define SODIUM_MIN(A, B) ((A) < (B) ? (A) : (B)) +#define SODIUM_SIZE_MAX SODIUM_MIN(UINT64_MAX, SIZE_MAX) + +#endif +/*** End of #include "export.h" ***/ + + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_stream_chacha20_KEYBYTES 32U +#define crypto_stream_chacha20_NONCEBYTES 8U +#define crypto_stream_chacha20_MESSAGEBYTES_MAX SODIUM_SIZE_MAX + +/* ChaCha20 with a 64-bit nonce and a 64-bit counter, as originally designed */ + +SODIUM_EXPORT +int crypto_stream_chacha20_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint64_t ic, + const unsigned char *k) + __attribute__ ((nonnull(1, 4, 6))); + +/* ChaCha20 with a 96-bit nonce and a 32-bit counter (IETF) */ + +#define crypto_stream_chacha20_ietf_KEYBYTES 32U +#define crypto_stream_chacha20_ietf_NONCEBYTES 12U +#define crypto_stream_chacha20_ietf_MESSAGEBYTES_MAX \ + SODIUM_MIN(SODIUM_SIZE_MAX, 64ULL * (1ULL << 32)) + +SODIUM_EXPORT +int crypto_stream_chacha20_ietf_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint32_t ic, + const unsigned char *k) + __attribute__ ((nonnull(1, 4, 6))); + +/* Aliases */ + +#define crypto_stream_chacha20_IETF_KEYBYTES crypto_stream_chacha20_ietf_KEYBYTES +#define crypto_stream_chacha20_IETF_NONCEBYTES crypto_stream_chacha20_ietf_NONCEBYTES +#define crypto_stream_chacha20_IETF_MESSAGEBYTES_MAX crypto_stream_chacha20_ietf_MESSAGEBYTES_MAX + +#ifdef __cplusplus +} +#endif + +#endif +/*** End of #include "crypto_stream_chacha20.h" ***/ + +/* #include "private/chacha20_ietf_ext.h" */ +/*** Begin of #include "private/chacha20_ietf_ext.h" ***/ +#ifndef chacha20_ietf_ext_H +#define chacha20_ietf_ext_H + +#include + +/* The ietf_ext variant allows the internal counter to overflow into the IV */ + +int crypto_stream_chacha20_ietf_ext(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k); + +int crypto_stream_chacha20_ietf_ext_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint32_t ic, + const unsigned char *k); +#endif + +/*** End of #include "private/chacha20_ietf_ext.h" ***/ + +/* #include "private/common.h" */ +/*** Begin of #include "private/common.h" ***/ +#ifndef common_H +#define common_H 1 + +/* Remove warning using "&& 0" */ +/* The development code (ChaCha20 AVX512F and NEON) are not enabled by default, but can be selected */ +#if !defined(_MSC_VER) && !defined(DEV_MODE) && 0 +# warning *** This is unstable, untested, development code. +# warning *** It might not compile. It might not work as expected. +# warning *** It might be totally insecure. +# warning *** Do not use this except if you are planning to contribute code. +# warning *** Use releases available at https://download.libsodium.org/libsodium/releases/ instead. +# warning *** Alternatively, use the "stable" branch in the git repository. +#endif + +#if !defined(_MSC_VER) && (!defined(CONFIGURED) || CONFIGURED != 1) && 0 +# warning *** The library is being compiled using an undocumented method. +# warning *** This is not supported. It has not been tested, it might not +# warning *** work as expected, and performance is likely to be suboptimal. +#endif + +#include +#include +#include + +#define COMPILER_ASSERT(X) (void) sizeof(char[(X) ? 1 : -1]) + +#if defined(__SIZEOF_INT128__) +# if defined(__SIZEOF_INT128__) +typedef unsigned __int128 uint128_t; +# else +typedef unsigned uint128_t __attribute__((mode(TI))); +# endif +#if !defined(HAVE_TI_MODE) +#define HAVE_TI_MODE 1 +#endif +#endif + +#ifdef _MSC_VER + +# define SODIUM_ROTL32(X, B) _rotl((X), (B)) +# define SODIUM_ROTL64(X, B) _rotl64((X), (B)) +# define SODIUM_ROTR32(X, B) _rotr((X), (B)) +# define SODIUM_ROTR64(X, B) _rotr64((X), (B)) + +#else + +# define SODIUM_ROTL32(X, B) sodium_rotl32((X), (B)) +static inline uint32_t +sodium_rotl32(const uint32_t x, const int b) +{ + return (x << b) | (x >> (32 - b)); +} + +# define SODIUM_ROTL64(X, B) sodium_rotl64((X), (B)) +static inline uint64_t +sodium_rotl64(const uint64_t x, const int b) +{ + return (x << b) | (x >> (64 - b)); +} + +# define SODIUM_ROTR32(X, B) sodium_rotr32((X), (B)) +static inline uint32_t +sodium_rotr32(const uint32_t x, const int b) +{ + return (x >> b) | (x << (32 - b)); +} + +# define SODIUM_ROTR64(X, B) sodium_rotr64((X), (B)) +static inline uint64_t +sodium_rotr64(const uint64_t x, const int b) +{ + return (x >> b) | (x << (64 - b)); +} + +#endif /* _MSC_VER */ + +#define SODIUM_LOAD64_LE(SRC) sodium_load64_le(SRC) +static inline uint64_t +sodium_load64_le(const uint8_t src[8]) +{ +#ifdef NATIVE_LITTLE_ENDIAN + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +#else + uint64_t w = (uint64_t) src[0]; + w |= (uint64_t) src[1] << 8; + w |= (uint64_t) src[2] << 16; + w |= (uint64_t) src[3] << 24; + w |= (uint64_t) src[4] << 32; + w |= (uint64_t) src[5] << 40; + w |= (uint64_t) src[6] << 48; + w |= (uint64_t) src[7] << 56; + return w; +#endif +} + +#define SODIUM_STORE64_LE(DST, W) sodium_store64_le((DST), (W)) +static inline void +sodium_store64_le(uint8_t dst[8], uint64_t w) +{ +#ifdef NATIVE_LITTLE_ENDIAN + memcpy(dst, &w, sizeof w); +#else + dst[0] = (uint8_t) w; w >>= 8; + dst[1] = (uint8_t) w; w >>= 8; + dst[2] = (uint8_t) w; w >>= 8; + dst[3] = (uint8_t) w; w >>= 8; + dst[4] = (uint8_t) w; w >>= 8; + dst[5] = (uint8_t) w; w >>= 8; + dst[6] = (uint8_t) w; w >>= 8; + dst[7] = (uint8_t) w; +#endif +} + +#define SODIUM_LOAD32_LE(SRC) sodium_load32_le(SRC) +static inline uint32_t +sodium_load32_le(const uint8_t src[4]) +{ +#ifdef NATIVE_LITTLE_ENDIAN + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + uint32_t w = (uint32_t) src[0]; + w |= (uint32_t) src[1] << 8; + w |= (uint32_t) src[2] << 16; + w |= (uint32_t) src[3] << 24; + return w; +#endif +} + +#define SODIUM_STORE32_LE(DST, W) sodium_store32_le((DST), (W)) +static inline void +sodium_store32_le(uint8_t dst[4], uint32_t w) +{ +#ifdef NATIVE_LITTLE_ENDIAN + memcpy(dst, &w, sizeof w); +#else + dst[0] = (uint8_t) w; w >>= 8; + dst[1] = (uint8_t) w; w >>= 8; + dst[2] = (uint8_t) w; w >>= 8; + dst[3] = (uint8_t) w; +#endif +} + +/* ----- */ + +#define SODIUM_LOAD64_BE(SRC) sodium_load64_be(SRC) +static inline uint64_t +sodium_load64_be(const uint8_t src[8]) +{ +#ifdef NATIVE_BIG_ENDIAN + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +#else + uint64_t w = (uint64_t) src[7]; + w |= (uint64_t) src[6] << 8; + w |= (uint64_t) src[5] << 16; + w |= (uint64_t) src[4] << 24; + w |= (uint64_t) src[3] << 32; + w |= (uint64_t) src[2] << 40; + w |= (uint64_t) src[1] << 48; + w |= (uint64_t) src[0] << 56; + return w; +#endif +} + +#define SODIUM_STORE64_BE(DST, W) sodium_store64_be((DST), (W)) +static inline void +sodium_store64_be(uint8_t dst[8], uint64_t w) +{ +#ifdef NATIVE_BIG_ENDIAN + memcpy(dst, &w, sizeof w); +#else + dst[7] = (uint8_t) w; w >>= 8; + dst[6] = (uint8_t) w; w >>= 8; + dst[5] = (uint8_t) w; w >>= 8; + dst[4] = (uint8_t) w; w >>= 8; + dst[3] = (uint8_t) w; w >>= 8; + dst[2] = (uint8_t) w; w >>= 8; + dst[1] = (uint8_t) w; w >>= 8; + dst[0] = (uint8_t) w; +#endif +} + +#define SODIUM_LOAD32_BE(SRC) sodium_load32_be(SRC) +static inline uint32_t +sodium_load32_be(const uint8_t src[4]) +{ +#ifdef NATIVE_BIG_ENDIAN + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + uint32_t w = (uint32_t) src[3]; + w |= (uint32_t) src[2] << 8; + w |= (uint32_t) src[1] << 16; + w |= (uint32_t) src[0] << 24; + return w; +#endif +} + +#define SODIUM_STORE32_BE(DST, W) sodium_store32_be((DST), (W)) +static inline void +sodium_store32_be(uint8_t dst[4], uint32_t w) +{ +#ifdef NATIVE_BIG_ENDIAN + memcpy(dst, &w, sizeof w); +#else + dst[3] = (uint8_t) w; w >>= 8; + dst[2] = (uint8_t) w; w >>= 8; + dst[1] = (uint8_t) w; w >>= 8; + dst[0] = (uint8_t) w; +#endif +} + +#define SODIUM_XOR_BUF(OUT, IN, N) sodium_xor_buf((OUT), (IN), (N)) +static inline void +sodium_xor_buf(unsigned char *out, const unsigned char *in, size_t n) +{ + size_t i; + + for (i = 0; i < n; i++) { + out[i] ^= in[i]; + } +} + +#if !defined(__clang__) && !defined(__GNUC__) +# ifdef __attribute__ +# undef __attribute__ +# endif +# define __attribute__(a) +#endif + +#ifndef CRYPTO_ALIGN +# if defined(__INTEL_COMPILER) || defined(_MSC_VER) +# define CRYPTO_ALIGN(x) __declspec(align(x)) +# else +# define CRYPTO_ALIGN(x) __attribute__ ((aligned(x))) +# endif +#endif + +#ifdef _MSC_VER + +# if defined(_M_X64) || defined(_M_IX86) +# include + +#if 0 +# define HAVE_INTRIN_H 1 +# define HAVE_MMINTRIN_H 1 +# define HAVE_EMMINTRIN_H 1 +# define HAVE_PMMINTRIN_H 1 +# define HAVE_TMMINTRIN_H 1 +# define HAVE_SMMINTRIN_H 1 +# define HAVE_AVXINTRIN_H 1 +# if _MSC_VER >= 1600 +# define HAVE_WMMINTRIN_H 1 +# endif +# if _MSC_VER >= 1700 && defined(_M_X64) +# define HAVE_AVX2INTRIN_H 1 +# endif +# if _MSC_VER >= 1910 && defined(_M_X64) +# define HAVE_AVX512FINTRIN_H 1 +# endif +#endif + +# elif defined(_M_ARM64) + +# ifndef __ARM_ARCH +# define __ARM_ARCH 1 +# endif +# ifndef __ARM_NEON +# define __ARM_NEON 1 +# endif +# define HAVE_ARMCRYPTO 1 + +# endif /* _MSC_VER */ + +#elif defined(HAVE_INTRIN_H) +# include +#endif + +#endif +/*** End of #include "private/common.h" ***/ + +/* #include "stream_chacha20.h" */ +/*** Begin of #include "stream_chacha20.h" ***/ +#ifndef stream_chacha20_H +#define stream_chacha20_H + +#include + +typedef struct crypto_stream_chacha20_implementation { + int (*stream_xor_ic)(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint64_t ic, + const unsigned char *k); + int (*stream_ietf_ext_xor_ic)(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint32_t ic, + const unsigned char *k); +} crypto_stream_chacha20_implementation; + +int crypto_stream_chacha20_pick_best_implementation(void); + +#endif +/*** End of #include "stream_chacha20.h" ***/ + + +#if defined(__GNUC__) +# pragma GCC push_options +#endif + +/* libsodium reference implementation */ +/* #include "ref/chacha20_ref.c" */ +/*** Begin of #include "ref/chacha20_ref.c" ***/ + +/* + chacha-merged.c version 20080118 + D. J. Bernstein + Public domain. + */ + +#include +#include +#include + +/* #include "../crypto_stream_chacha20.h" */ + +/* #include "../private/common.h" */ + + +/* #include "../stream_chacha20.h" */ + +/* #include "chacha20_ref.h" */ +/*** Begin of #include "chacha20_ref.h" ***/ + +#include + +/* #include "../stream_chacha20.h" */ + +/* #include "../crypto_stream_chacha20.h" */ + + +extern struct crypto_stream_chacha20_implementation + crypto_stream_chacha20_ref_implementation; +/*** End of #include "chacha20_ref.h" ***/ + + +#define SODIUM_U32C(v) (v##U) +#define SODIUM_U32V(v) ((uint32_t)(v) &SODIUM_U32C(0xFFFFFFFF)) + +#define SODIUM_ROTATE(v, c) (SODIUM_ROTL32(v, c)) +#define SODIUM_XOR(v, w) ((v) ^ (w)) +#define SODIUM_PLUS(v, w) (SODIUM_U32V((v) + (w))) +#define SODIUM_PLUSONE(v) (SODIUM_PLUS((v), 1)) + +#define SODIUM_QUARTERROUND(a, b, c, d) \ + a = SODIUM_PLUS(a, b); \ + d = SODIUM_ROTATE(SODIUM_XOR(d, a), 16); \ + c = SODIUM_PLUS(c, d); \ + b = SODIUM_ROTATE(SODIUM_XOR(b, c), 12); \ + a = SODIUM_PLUS(a, b); \ + d = SODIUM_ROTATE(SODIUM_XOR(d, a), 8); \ + c = SODIUM_PLUS(c, d); \ + b = SODIUM_ROTATE(SODIUM_XOR(b, c), 7); + +static void +sodium_chacha_keysetup(chacha_ctx *ctx, const uint8_t *k) +{ + ctx->input[0] = SODIUM_U32C(0x61707865); + ctx->input[1] = SODIUM_U32C(0x3320646e); + ctx->input[2] = SODIUM_U32C(0x79622d32); + ctx->input[3] = SODIUM_U32C(0x6b206574); + ctx->input[4] = SODIUM_LOAD32_LE(k + 0); + ctx->input[5] = SODIUM_LOAD32_LE(k + 4); + ctx->input[6] = SODIUM_LOAD32_LE(k + 8); + ctx->input[7] = SODIUM_LOAD32_LE(k + 12); + ctx->input[8] = SODIUM_LOAD32_LE(k + 16); + ctx->input[9] = SODIUM_LOAD32_LE(k + 20); + ctx->input[10] = SODIUM_LOAD32_LE(k + 24); + ctx->input[11] = SODIUM_LOAD32_LE(k + 28); +} + +static void +sodium_chacha_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter) +{ + ctx->input[12] = counter == NULL ? 0 : SODIUM_LOAD32_LE(counter + 0); + ctx->input[13] = counter == NULL ? 0 : SODIUM_LOAD32_LE(counter + 4); + ctx->input[14] = SODIUM_LOAD32_LE(iv + 0); + ctx->input[15] = SODIUM_LOAD32_LE(iv + 4); +} + +static void +sodium_chacha_ietf_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter) +{ + ctx->input[12] = counter == NULL ? 0 : SODIUM_LOAD32_LE(counter); + ctx->input[13] = SODIUM_LOAD32_LE(iv + 0); + ctx->input[14] = SODIUM_LOAD32_LE(iv + 4); + ctx->input[15] = SODIUM_LOAD32_LE(iv + 8); +} + +static void +sodium_chacha20_encrypt_bytes(chacha_ctx *ctx, const uint8_t *m, uint8_t *c, + unsigned long long bytes) +{ + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, + x15; + uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, + j15; + uint8_t *ctarget = NULL; + uint8_t tmp[64]; + unsigned int i; + + if (!bytes) { + return; /* LCOV_EXCL_LINE */ + } + j0 = ctx->input[0]; + j1 = ctx->input[1]; + j2 = ctx->input[2]; + j3 = ctx->input[3]; + j4 = ctx->input[4]; + j5 = ctx->input[5]; + j6 = ctx->input[6]; + j7 = ctx->input[7]; + j8 = ctx->input[8]; + j9 = ctx->input[9]; + j10 = ctx->input[10]; + j11 = ctx->input[11]; + j12 = ctx->input[12]; + j13 = ctx->input[13]; + j14 = ctx->input[14]; + j15 = ctx->input[15]; + + for (;;) { + if (bytes < 64) { + memset(tmp, 0, 64); + for (i = 0; i < bytes; ++i) { + tmp[i] = m[i]; + } + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 20; i > 0; i -= 2) { + SODIUM_QUARTERROUND(x0, x4, x8, x12) + SODIUM_QUARTERROUND(x1, x5, x9, x13) + SODIUM_QUARTERROUND(x2, x6, x10, x14) + SODIUM_QUARTERROUND(x3, x7, x11, x15) + SODIUM_QUARTERROUND(x0, x5, x10, x15) + SODIUM_QUARTERROUND(x1, x6, x11, x12) + SODIUM_QUARTERROUND(x2, x7, x8, x13) + SODIUM_QUARTERROUND(x3, x4, x9, x14) + } + x0 = SODIUM_PLUS(x0, j0); + x1 = SODIUM_PLUS(x1, j1); + x2 = SODIUM_PLUS(x2, j2); + x3 = SODIUM_PLUS(x3, j3); + x4 = SODIUM_PLUS(x4, j4); + x5 = SODIUM_PLUS(x5, j5); + x6 = SODIUM_PLUS(x6, j6); + x7 = SODIUM_PLUS(x7, j7); + x8 = SODIUM_PLUS(x8, j8); + x9 = SODIUM_PLUS(x9, j9); + x10 = SODIUM_PLUS(x10, j10); + x11 = SODIUM_PLUS(x11, j11); + x12 = SODIUM_PLUS(x12, j12); + x13 = SODIUM_PLUS(x13, j13); + x14 = SODIUM_PLUS(x14, j14); + x15 = SODIUM_PLUS(x15, j15); + + x0 = SODIUM_XOR(x0, SODIUM_LOAD32_LE(m + 0)); + x1 = SODIUM_XOR(x1, SODIUM_LOAD32_LE(m + 4)); + x2 = SODIUM_XOR(x2, SODIUM_LOAD32_LE(m + 8)); + x3 = SODIUM_XOR(x3, SODIUM_LOAD32_LE(m + 12)); + x4 = SODIUM_XOR(x4, SODIUM_LOAD32_LE(m + 16)); + x5 = SODIUM_XOR(x5, SODIUM_LOAD32_LE(m + 20)); + x6 = SODIUM_XOR(x6, SODIUM_LOAD32_LE(m + 24)); + x7 = SODIUM_XOR(x7, SODIUM_LOAD32_LE(m + 28)); + x8 = SODIUM_XOR(x8, SODIUM_LOAD32_LE(m + 32)); + x9 = SODIUM_XOR(x9, SODIUM_LOAD32_LE(m + 36)); + x10 = SODIUM_XOR(x10, SODIUM_LOAD32_LE(m + 40)); + x11 = SODIUM_XOR(x11, SODIUM_LOAD32_LE(m + 44)); + x12 = SODIUM_XOR(x12, SODIUM_LOAD32_LE(m + 48)); + x13 = SODIUM_XOR(x13, SODIUM_LOAD32_LE(m + 52)); + x14 = SODIUM_XOR(x14, SODIUM_LOAD32_LE(m + 56)); + x15 = SODIUM_XOR(x15, SODIUM_LOAD32_LE(m + 60)); + + j12 = SODIUM_PLUSONE(j12); + /* LCOV_EXCL_START */ + if (!j12) { + j13 = SODIUM_PLUSONE(j13); + } + /* LCOV_EXCL_STOP */ + + SODIUM_STORE32_LE(c + 0, x0); + SODIUM_STORE32_LE(c + 4, x1); + SODIUM_STORE32_LE(c + 8, x2); + SODIUM_STORE32_LE(c + 12, x3); + SODIUM_STORE32_LE(c + 16, x4); + SODIUM_STORE32_LE(c + 20, x5); + SODIUM_STORE32_LE(c + 24, x6); + SODIUM_STORE32_LE(c + 28, x7); + SODIUM_STORE32_LE(c + 32, x8); + SODIUM_STORE32_LE(c + 36, x9); + SODIUM_STORE32_LE(c + 40, x10); + SODIUM_STORE32_LE(c + 44, x11); + SODIUM_STORE32_LE(c + 48, x12); + SODIUM_STORE32_LE(c + 52, x13); + SODIUM_STORE32_LE(c + 56, x14); + SODIUM_STORE32_LE(c + 60, x15); + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0; i < (unsigned int) bytes; ++i) { + ctarget[i] = c[i]; /* ctarget cannot be NULL */ + } + } + ctx->input[12] = j12; + ctx->input[13] = j13; + + return; + } + bytes -= 64; + c += 64; + m += 64; + } +} + +static int +sodium_stream_ref_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, uint64_t ic, + const unsigned char *k) +{ + struct chacha_ctx ctx; + uint8_t ic_bytes[8]; + uint32_t ic_high; + uint32_t ic_low; + + if (!mlen) { + return 0; + } + ic_high = SODIUM_U32V(ic >> 32); + ic_low = SODIUM_U32V(ic); + SODIUM_STORE32_LE(&ic_bytes[0], ic_low); + SODIUM_STORE32_LE(&ic_bytes[4], ic_high); + sodium_chacha_keysetup(&ctx, k); + sodium_chacha_ivsetup(&ctx, n, ic_bytes); + sodium_chacha20_encrypt_bytes(&ctx, m, c, mlen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +static int +sodium_stream_ietf_ext_ref_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + uint32_t ic, const unsigned char *k) +{ + struct chacha_ctx ctx; + uint8_t ic_bytes[4]; + + if (!mlen) { + return 0; + } + SODIUM_STORE32_LE(ic_bytes, ic); + sodium_chacha_keysetup(&ctx, k); + sodium_chacha_ietf_ivsetup(&ctx, n, ic_bytes); + sodium_chacha20_encrypt_bytes(&ctx, m, c, mlen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +struct crypto_stream_chacha20_implementation + crypto_stream_chacha20_ref_implementation = { + .stream_xor_ic = sodium_stream_ref_xor_ic, + .stream_ietf_ext_xor_ic = sodium_stream_ietf_ext_ref_xor_ic + }; +/*** End of #include "ref/chacha20_ref.c" ***/ + + +#if defined(SQLITE3MC_TARGET_X86) || (defined(SQLITE3MC_TARGET_WASM) && defined(__wasm_simd128__) && defined(__SSSE3__)) +/* Original order: avx512, avx2, ssse3 */ +/* # include "dolbeau/chacha20_dolbeau-ssse3.c" */ +/*** Begin of # include "dolbeau/chacha20_dolbeau-ssse3.c" ***/ + +#include +#include +#include + +/* #include "../crypto_stream_chacha20.h" */ + +/* #include "../private/common.h" */ + + +#if defined(SQLITE3MC_TARGET_X86) || defined(SQLITE3MC_TARGET_WASM) + +# ifdef __clang__ +# pragma clang attribute push(__attribute__((target("sse2,ssse3"))), apply_to = function) +# elif defined(__GNUC__) +# pragma GCC target("sse2,ssse3") +# endif + +# include +# include +/* # include "../private/sse2_64_32.h" */ +/*** Begin of # include "../private/sse2_64_32.h" ***/ +#ifndef sse2_64_32_H +#define sse2_64_32_H 1 + +/* #include "common.h" */ + + +#if !(defined(__amd64) || defined(__amd64__) || defined(__x86_64__) || \ + defined(_M_X64)) + +# include +# include + +# ifndef _mm_set_epi64x +# define _mm_set_epi64x(Q0, Q1) sodium__mm_set_epi64x((Q0), (Q1)) +static inline __m128i +sodium__mm_set_epi64x(int64_t q1, int64_t q0) +{ + union { int64_t as64; int32_t as32[2]; } x0, x1; + x0.as64 = q0; x1.as64 = q1; + return _mm_set_epi32(x1.as32[1], x1.as32[0], x0.as32[1], x0.as32[0]); +} +# endif + +# ifndef _mm_set1_epi64x +# define _mm_set1_epi64x(Q) sodium__mm_set1_epi64x(Q) +static inline __m128i +sodium__mm_set1_epi64x(int64_t q) +{ + return _mm_set_epi64x(q, q); +} +# endif + +# ifndef _mm_cvtsi64_si128 +# define _mm_cvtsi64_si128(Q) sodium__mm_cvtsi64_si128(Q) +static inline __m128i +sodium__mm_cvtsi64_si128(int64_t q) +{ + union { int64_t as64; int32_t as32[2]; } x; + x.as64 = q; + return _mm_setr_epi32(x.as32[0], x.as32[1], 0, 0); +} +# endif + +#endif + +#endif +/*** End of # include "../private/sse2_64_32.h" ***/ + + +/* # include "../stream_chacha20.h" */ + +/* # include "chacha20_dolbeau-ssse3.h" */ +/*** Begin of # include "chacha20_dolbeau-ssse3.h" ***/ + +#include + +/* #include "../stream_chacha20.h" */ + +/* #include "../crypto_stream_chacha20.h" */ + + +extern struct crypto_stream_chacha20_implementation + crypto_stream_chacha20_dolbeau_ssse3_implementation; +/*** End of # include "chacha20_dolbeau-ssse3.h" ***/ + + +#ifdef DOLBEAU_ROUNDS +# undef DOLBEAU_ROUNDS +# define DOLBEAU_ROUNDS 20 +#else +# define DOLBEAU_ROUNDS 20 +#endif + +static void +dolbeau_ssse3_chacha_keysetup(chacha_ctx *ctx, const uint8_t *k) +{ + ctx->input[0] = 0x61707865; + ctx->input[1] = 0x3320646e; + ctx->input[2] = 0x79622d32; + ctx->input[3] = 0x6b206574; + ctx->input[4] = SODIUM_LOAD32_LE(k + 0); + ctx->input[5] = SODIUM_LOAD32_LE(k + 4); + ctx->input[6] = SODIUM_LOAD32_LE(k + 8); + ctx->input[7] = SODIUM_LOAD32_LE(k + 12); + ctx->input[8] = SODIUM_LOAD32_LE(k + 16); + ctx->input[9] = SODIUM_LOAD32_LE(k + 20); + ctx->input[10] = SODIUM_LOAD32_LE(k + 24); + ctx->input[11] = SODIUM_LOAD32_LE(k + 28); +} + +static void +dolbeau_ssse3_chacha_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter) +{ + ctx->input[12] = counter == NULL ? 0 : SODIUM_LOAD32_LE(counter + 0); + ctx->input[13] = counter == NULL ? 0 : SODIUM_LOAD32_LE(counter + 4); + ctx->input[14] = SODIUM_LOAD32_LE(iv + 0); + ctx->input[15] = SODIUM_LOAD32_LE(iv + 4); +} + +static void +dolbeau_ssse3_chacha_ietf_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter) +{ + ctx->input[12] = counter == NULL ? 0 : SODIUM_LOAD32_LE(counter); + ctx->input[13] = SODIUM_LOAD32_LE(iv + 0); + ctx->input[14] = SODIUM_LOAD32_LE(iv + 4); + ctx->input[15] = SODIUM_LOAD32_LE(iv + 8); +} + +static void +dolbeau_ssse3_chacha20_encrypt_bytes(chacha_ctx *ctx, const uint8_t *m, uint8_t *c, + unsigned long long bytes) +{ + uint32_t * const x = &ctx->input[0]; + + if (!bytes) { + return; /* LCOV_EXCL_LINE */ + } +/* # include "u4.h" */ +/*** Begin of # include "u4.h" ***/ + +#define VEC4_ROT(A, IMM) \ + _mm_or_si128(_mm_slli_epi32(A, IMM), _mm_srli_epi32(A, (32 - IMM))) + +/* same, but replace 2 of the shift/shift/or "rotation" by byte shuffles (8 & + * 16) (better) */ +#define VEC4_QUARTERROUND_SHUFFLE(A, B, C, D) \ + x_##A = _mm_add_epi32(x_##A, x_##B); \ + t_##A = _mm_xor_si128(x_##D, x_##A); \ + x_##D = _mm_shuffle_epi8(t_##A, rot16); \ + x_##C = _mm_add_epi32(x_##C, x_##D); \ + t_##C = _mm_xor_si128(x_##B, x_##C); \ + x_##B = VEC4_ROT(t_##C, 12); \ + x_##A = _mm_add_epi32(x_##A, x_##B); \ + t_##A = _mm_xor_si128(x_##D, x_##A); \ + x_##D = _mm_shuffle_epi8(t_##A, rot8); \ + x_##C = _mm_add_epi32(x_##C, x_##D); \ + t_##C = _mm_xor_si128(x_##B, x_##C); \ + x_##B = VEC4_ROT(t_##C, 7) + +#define VEC4_QUARTERROUND(A, B, C, D) VEC4_QUARTERROUND_SHUFFLE(A, B, C, D) + +if (bytes >= 256) { + /* constant for shuffling bytes (replacing multiple-of-8 rotates) */ + __m128i rot16 = + _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + __m128i rot8 = + _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3); + + __m128i x_0 = _mm_set1_epi32(x[0]); + __m128i x_1 = _mm_set1_epi32(x[1]); + __m128i x_2 = _mm_set1_epi32(x[2]); + __m128i x_3 = _mm_set1_epi32(x[3]); + __m128i x_4 = _mm_set1_epi32(x[4]); + __m128i x_5 = _mm_set1_epi32(x[5]); + __m128i x_6 = _mm_set1_epi32(x[6]); + __m128i x_7 = _mm_set1_epi32(x[7]); + __m128i x_8 = _mm_set1_epi32(x[8]); + __m128i x_9 = _mm_set1_epi32(x[9]); + __m128i x_10 = _mm_set1_epi32(x[10]); + __m128i x_11 = _mm_set1_epi32(x[11]); + __m128i x_12; + __m128i x_13; + __m128i x_14 = _mm_set1_epi32(x[14]); + __m128i x_15 = _mm_set1_epi32(x[15]); + __m128i orig0 = x_0; + __m128i orig1 = x_1; + __m128i orig2 = x_2; + __m128i orig3 = x_3; + __m128i orig4 = x_4; + __m128i orig5 = x_5; + __m128i orig6 = x_6; + __m128i orig7 = x_7; + __m128i orig8 = x_8; + __m128i orig9 = x_9; + __m128i orig10 = x_10; + __m128i orig11 = x_11; + __m128i orig12; + __m128i orig13; + __m128i orig14 = x_14; + __m128i orig15 = x_15; + __m128i t_0, t_1, t_2, t_3, t_4, t_5, t_6, t_7, t_8, t_9, t_10, t_11, t_12, + t_13, t_14, t_15; + + uint32_t in12, in13; + int i; + + while (bytes >= 256) { + const __m128i addv12 = _mm_set_epi64x(1, 0); + const __m128i addv13 = _mm_set_epi64x(3, 2); + __m128i t12, t13; + uint64_t in1213; + + x_0 = orig0; + x_1 = orig1; + x_2 = orig2; + x_3 = orig3; + x_4 = orig4; + x_5 = orig5; + x_6 = orig6; + x_7 = orig7; + x_8 = orig8; + x_9 = orig9; + x_10 = orig10; + x_11 = orig11; + x_14 = orig14; + x_15 = orig15; + + in12 = x[12]; + in13 = x[13]; + in1213 = ((uint64_t) in12) | (((uint64_t) in13) << 32); + t12 = _mm_set1_epi64x(in1213); + t13 = _mm_set1_epi64x(in1213); + + x_12 = _mm_add_epi64(addv12, t12); + x_13 = _mm_add_epi64(addv13, t13); + + t12 = _mm_unpacklo_epi32(x_12, x_13); + t13 = _mm_unpackhi_epi32(x_12, x_13); + + x_12 = _mm_unpacklo_epi32(t12, t13); + x_13 = _mm_unpackhi_epi32(t12, t13); + + orig12 = x_12; + orig13 = x_13; + + in1213 += 4; + + x[12] = in1213 & 0xFFFFFFFF; + x[13] = (in1213 >> 32) & 0xFFFFFFFF; + + for (i = 0; i < DOLBEAU_ROUNDS; i += 2) { + VEC4_QUARTERROUND(0, 4, 8, 12); + VEC4_QUARTERROUND(1, 5, 9, 13); + VEC4_QUARTERROUND(2, 6, 10, 14); + VEC4_QUARTERROUND(3, 7, 11, 15); + VEC4_QUARTERROUND(0, 5, 10, 15); + VEC4_QUARTERROUND(1, 6, 11, 12); + VEC4_QUARTERROUND(2, 7, 8, 13); + VEC4_QUARTERROUND(3, 4, 9, 14); + } + +#define ONEQUAD_TRANSPOSE(A, B, C, D) \ + { \ + __m128i t0, t1, t2, t3; \ + \ + x_##A = _mm_add_epi32(x_##A, orig##A); \ + x_##B = _mm_add_epi32(x_##B, orig##B); \ + x_##C = _mm_add_epi32(x_##C, orig##C); \ + x_##D = _mm_add_epi32(x_##D, orig##D); \ + t_##A = _mm_unpacklo_epi32(x_##A, x_##B); \ + t_##B = _mm_unpacklo_epi32(x_##C, x_##D); \ + t_##C = _mm_unpackhi_epi32(x_##A, x_##B); \ + t_##D = _mm_unpackhi_epi32(x_##C, x_##D); \ + x_##A = _mm_unpacklo_epi64(t_##A, t_##B); \ + x_##B = _mm_unpackhi_epi64(t_##A, t_##B); \ + x_##C = _mm_unpacklo_epi64(t_##C, t_##D); \ + x_##D = _mm_unpackhi_epi64(t_##C, t_##D); \ + \ + t0 = _mm_xor_si128(x_##A, _mm_loadu_si128((const __m128i*) (m + 0))); \ + _mm_storeu_si128((__m128i*) (c + 0), t0); \ + t1 = _mm_xor_si128(x_##B, _mm_loadu_si128((const __m128i*) (m + 64))); \ + _mm_storeu_si128((__m128i*) (c + 64), t1); \ + t2 = \ + _mm_xor_si128(x_##C, _mm_loadu_si128((const __m128i*) (m + 128))); \ + _mm_storeu_si128((__m128i*) (c + 128), t2); \ + t3 = \ + _mm_xor_si128(x_##D, _mm_loadu_si128((const __m128i*) (m + 192))); \ + _mm_storeu_si128((__m128i*) (c + 192), t3); \ + } + +#define ONEQUAD(A, B, C, D) ONEQUAD_TRANSPOSE(A, B, C, D) + + ONEQUAD(0, 1, 2, 3); + m += 16; + c += 16; + ONEQUAD(4, 5, 6, 7); + m += 16; + c += 16; + ONEQUAD(8, 9, 10, 11); + m += 16; + c += 16; + ONEQUAD(12, 13, 14, 15); + m -= 48; + c -= 48; + +#undef ONEQUAD +#undef ONEQUAD_TRANSPOSE + + bytes -= 256; + c += 256; + m += 256; + } +} +#undef VEC4_ROT +#undef VEC4_QUARTERROUND +#undef VEC4_QUARTERROUND_SHUFFLE +/*** End of # include "u4.h" ***/ + +/* # include "u1.h" */ +/*** Begin of # include "u1.h" ***/ +while (bytes >= 64) { + __m128i x_0, x_1, x_2, x_3; + __m128i t_1; + const __m128i rot16 = + _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + const __m128i rot8 = + _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3); + + uint32_t in12; + uint32_t in13; + int i; + + x_0 = _mm_loadu_si128((const __m128i*) (x + 0)); + x_1 = _mm_loadu_si128((const __m128i*) (x + 4)); + x_2 = _mm_loadu_si128((const __m128i*) (x + 8)); + x_3 = _mm_loadu_si128((const __m128i*) (x + 12)); + + for (i = 0; i < DOLBEAU_ROUNDS; i += 2) { + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_3 = _mm_shuffle_epi8(x_3, rot16); + + x_2 = _mm_add_epi32(x_2, x_3); + x_1 = _mm_xor_si128(x_1, x_2); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 12); + t_1 = _mm_srli_epi32(t_1, 20); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_0 = _mm_shuffle_epi32(x_0, 0x93); + x_3 = _mm_shuffle_epi8(x_3, rot8); + + x_2 = _mm_add_epi32(x_2, x_3); + x_3 = _mm_shuffle_epi32(x_3, 0x4e); + x_1 = _mm_xor_si128(x_1, x_2); + x_2 = _mm_shuffle_epi32(x_2, 0x39); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 7); + t_1 = _mm_srli_epi32(t_1, 25); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_3 = _mm_shuffle_epi8(x_3, rot16); + + x_2 = _mm_add_epi32(x_2, x_3); + x_1 = _mm_xor_si128(x_1, x_2); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 12); + t_1 = _mm_srli_epi32(t_1, 20); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_0 = _mm_shuffle_epi32(x_0, 0x39); + x_3 = _mm_shuffle_epi8(x_3, rot8); + + x_2 = _mm_add_epi32(x_2, x_3); + x_3 = _mm_shuffle_epi32(x_3, 0x4e); + x_1 = _mm_xor_si128(x_1, x_2); + x_2 = _mm_shuffle_epi32(x_2, 0x93); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 7); + t_1 = _mm_srli_epi32(t_1, 25); + x_1 = _mm_xor_si128(x_1, t_1); + } + x_0 = _mm_add_epi32(x_0, _mm_loadu_si128((const __m128i*) (x + 0))); + x_1 = _mm_add_epi32(x_1, _mm_loadu_si128((const __m128i*) (x + 4))); + x_2 = _mm_add_epi32(x_2, _mm_loadu_si128((const __m128i*) (x + 8))); + x_3 = _mm_add_epi32(x_3, _mm_loadu_si128((const __m128i*) (x + 12))); + x_0 = _mm_xor_si128(x_0, _mm_loadu_si128((const __m128i*) (m + 0))); + x_1 = _mm_xor_si128(x_1, _mm_loadu_si128((const __m128i*) (m + 16))); + x_2 = _mm_xor_si128(x_2, _mm_loadu_si128((const __m128i*) (m + 32))); + x_3 = _mm_xor_si128(x_3, _mm_loadu_si128((const __m128i*) (m + 48))); + _mm_storeu_si128((__m128i*) (c + 0), x_0); + _mm_storeu_si128((__m128i*) (c + 16), x_1); + _mm_storeu_si128((__m128i*) (c + 32), x_2); + _mm_storeu_si128((__m128i*) (c + 48), x_3); + + in12 = x[12]; + in13 = x[13]; + in12++; + if (in12 == 0) { + in13++; + } + x[12] = in12; + x[13] = in13; + + bytes -= 64; + c += 64; + m += 64; +} +/*** End of # include "u1.h" ***/ + +/* # include "u0.h" */ +/*** Begin of # include "u0.h" ***/ +if (bytes > 0) { + __m128i x_0, x_1, x_2, x_3; + __m128i t_1; + const __m128i rot16 = + _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + const __m128i rot8 = + _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3); + uint8_t partialblock[64]; + + unsigned int i; + + x_0 = _mm_loadu_si128((const __m128i*) (x + 0)); + x_1 = _mm_loadu_si128((const __m128i*) (x + 4)); + x_2 = _mm_loadu_si128((const __m128i*) (x + 8)); + x_3 = _mm_loadu_si128((const __m128i*) (x + 12)); + + for (i = 0; i < DOLBEAU_ROUNDS; i += 2) { + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_3 = _mm_shuffle_epi8(x_3, rot16); + + x_2 = _mm_add_epi32(x_2, x_3); + x_1 = _mm_xor_si128(x_1, x_2); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 12); + t_1 = _mm_srli_epi32(t_1, 20); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_0 = _mm_shuffle_epi32(x_0, 0x93); + x_3 = _mm_shuffle_epi8(x_3, rot8); + + x_2 = _mm_add_epi32(x_2, x_3); + x_3 = _mm_shuffle_epi32(x_3, 0x4e); + x_1 = _mm_xor_si128(x_1, x_2); + x_2 = _mm_shuffle_epi32(x_2, 0x39); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 7); + t_1 = _mm_srli_epi32(t_1, 25); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_3 = _mm_shuffle_epi8(x_3, rot16); + + x_2 = _mm_add_epi32(x_2, x_3); + x_1 = _mm_xor_si128(x_1, x_2); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 12); + t_1 = _mm_srli_epi32(t_1, 20); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_0 = _mm_shuffle_epi32(x_0, 0x39); + x_3 = _mm_shuffle_epi8(x_3, rot8); + + x_2 = _mm_add_epi32(x_2, x_3); + x_3 = _mm_shuffle_epi32(x_3, 0x4e); + x_1 = _mm_xor_si128(x_1, x_2); + x_2 = _mm_shuffle_epi32(x_2, 0x93); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 7); + t_1 = _mm_srli_epi32(t_1, 25); + x_1 = _mm_xor_si128(x_1, t_1); + } + x_0 = _mm_add_epi32(x_0, _mm_loadu_si128((const __m128i*) (x + 0))); + x_1 = _mm_add_epi32(x_1, _mm_loadu_si128((const __m128i*) (x + 4))); + x_2 = _mm_add_epi32(x_2, _mm_loadu_si128((const __m128i*) (x + 8))); + x_3 = _mm_add_epi32(x_3, _mm_loadu_si128((const __m128i*) (x + 12))); + _mm_storeu_si128((__m128i*) (partialblock + 0), x_0); + _mm_storeu_si128((__m128i*) (partialblock + 16), x_1); + _mm_storeu_si128((__m128i*) (partialblock + 32), x_2); + _mm_storeu_si128((__m128i*) (partialblock + 48), x_3); + + for (i = 0; i < bytes; i++) { + c[i] = m[i] ^ partialblock[i]; + } + + sodium_memzero(partialblock, sizeof partialblock); +} +/*** End of # include "u0.h" ***/ + +} + +static int +dolbeau_ssse3_stream_ref_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, uint64_t ic, + const unsigned char *k) +{ + struct chacha_ctx ctx; + uint8_t ic_bytes[8]; + uint32_t ic_high; + uint32_t ic_low; + + if (!mlen) { + return 0; + } + ic_high = (uint32_t) (ic >> 32); + ic_low = (uint32_t) ic; + SODIUM_STORE32_LE(&ic_bytes[0], ic_low); + SODIUM_STORE32_LE(&ic_bytes[4], ic_high); + dolbeau_ssse3_chacha_keysetup(&ctx, k); + dolbeau_ssse3_chacha_ivsetup(&ctx, n, ic_bytes); + dolbeau_ssse3_chacha20_encrypt_bytes(&ctx, m, c, mlen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +static int +dolbeau_ssse3_stream_ietf_ext_ref_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + uint32_t ic, const unsigned char *k) +{ + struct chacha_ctx ctx; + uint8_t ic_bytes[4]; + + if (!mlen) { + return 0; + } + SODIUM_STORE32_LE(ic_bytes, ic); + dolbeau_ssse3_chacha_keysetup(&ctx, k); + dolbeau_ssse3_chacha_ietf_ivsetup(&ctx, n, ic_bytes); + dolbeau_ssse3_chacha20_encrypt_bytes(&ctx, m, c, mlen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +struct crypto_stream_chacha20_implementation + crypto_stream_chacha20_dolbeau_ssse3_implementation = { + .stream_xor_ic = dolbeau_ssse3_stream_ref_xor_ic, + .stream_ietf_ext_xor_ic = dolbeau_ssse3_stream_ietf_ext_ref_xor_ic + }; + +# ifdef __clang__ +# pragma clang attribute pop +# endif + +#endif +/*** End of # include "dolbeau/chacha20_dolbeau-ssse3.c" ***/ + +#if defined(SQLITE3MC_TARGET_X86) +/* # include "dolbeau/chacha20_dolbeau-avx2.c" */ +/*** Begin of # include "dolbeau/chacha20_dolbeau-avx2.c" ***/ + +#include +#include +#include + +/* #include "../crypto_stream_chacha20.h" */ + +/* #include "../private/common.h" */ + + +#if defined(SQLITE3MC_TARGET_X86) + +# ifdef __clang__ +# pragma clang attribute push(__attribute__((target("sse2,ssse3,sse4.1,avx2"))), apply_to = function) +# elif defined(__GNUC__) +# pragma GCC target("sse2,ssse3,sse4.1,avx2") +# endif + +# include +# include +# include +# include +/* # include "../private/sse2_64_32.h" */ + + +/* # include "../stream_chacha20.h" */ + +/* # include "chacha20_dolbeau-avx2.h" */ +/*** Begin of # include "chacha20_dolbeau-avx2.h" ***/ + +#include + +/* #include "../stream_chacha20.h" */ + +/* #include "../crypto_stream_chacha20.h" */ + + +extern struct crypto_stream_chacha20_implementation + crypto_stream_chacha20_dolbeau_avx2_implementation; +/*** End of # include "chacha20_dolbeau-avx2.h" ***/ + + +#ifdef DOLBEAU_ROUNDS +# undef DOLBEAU_ROUNDS +# define DOLBEAU_ROUNDS 20 +#else +# define DOLBEAU_ROUNDS 20 +#endif + +static void +dolbeau_avx2_chacha_keysetup(chacha_ctx *ctx, const uint8_t *k) +{ + ctx->input[0] = 0x61707865; + ctx->input[1] = 0x3320646e; + ctx->input[2] = 0x79622d32; + ctx->input[3] = 0x6b206574; + ctx->input[4] = SODIUM_LOAD32_LE(k + 0); + ctx->input[5] = SODIUM_LOAD32_LE(k + 4); + ctx->input[6] = SODIUM_LOAD32_LE(k + 8); + ctx->input[7] = SODIUM_LOAD32_LE(k + 12); + ctx->input[8] = SODIUM_LOAD32_LE(k + 16); + ctx->input[9] = SODIUM_LOAD32_LE(k + 20); + ctx->input[10] = SODIUM_LOAD32_LE(k + 24); + ctx->input[11] = SODIUM_LOAD32_LE(k + 28); +} + +static void +dolbeau_avx2_chacha_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter) +{ + ctx->input[12] = counter == NULL ? 0 : SODIUM_LOAD32_LE(counter + 0); + ctx->input[13] = counter == NULL ? 0 : SODIUM_LOAD32_LE(counter + 4); + ctx->input[14] = SODIUM_LOAD32_LE(iv + 0); + ctx->input[15] = SODIUM_LOAD32_LE(iv + 4); +} + +static void +dolbeau_avx2_chacha_ietf_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter) +{ + ctx->input[12] = counter == NULL ? 0 : SODIUM_LOAD32_LE(counter); + ctx->input[13] = SODIUM_LOAD32_LE(iv + 0); + ctx->input[14] = SODIUM_LOAD32_LE(iv + 4); + ctx->input[15] = SODIUM_LOAD32_LE(iv + 8); +} + +static void +dolbeau_avx2_chacha20_encrypt_bytes(chacha_ctx *ctx, const uint8_t *m, uint8_t *c, + unsigned long long bytes) +{ + uint32_t * const x = &ctx->input[0]; + + if (!bytes) { + return; /* LCOV_EXCL_LINE */ + } +/* # include "u8.h" */ +/*** Begin of # include "u8.h" ***/ + +#define VEC8_ROT(A, IMM) \ + _mm256_or_si256(_mm256_slli_epi32(A, IMM), _mm256_srli_epi32(A, (32 - IMM))) + +/* same, but replace 2 of the shift/shift/or "rotation" by byte shuffles (8 & + * 16) (better) */ +#define VEC8_QUARTERROUND_SHUFFLE(A, B, C, D) \ + x_##A = _mm256_add_epi32(x_##A, x_##B); \ + t_##A = _mm256_xor_si256(x_##D, x_##A); \ + x_##D = _mm256_shuffle_epi8(t_##A, rot16); \ + x_##C = _mm256_add_epi32(x_##C, x_##D); \ + t_##C = _mm256_xor_si256(x_##B, x_##C); \ + x_##B = VEC8_ROT(t_##C, 12); \ + x_##A = _mm256_add_epi32(x_##A, x_##B); \ + t_##A = _mm256_xor_si256(x_##D, x_##A); \ + x_##D = _mm256_shuffle_epi8(t_##A, rot8); \ + x_##C = _mm256_add_epi32(x_##C, x_##D); \ + t_##C = _mm256_xor_si256(x_##B, x_##C); \ + x_##B = VEC8_ROT(t_##C, 7) + +#define VEC8_QUARTERROUND(A, B, C, D) VEC8_QUARTERROUND_SHUFFLE(A, B, C, D) + +#define VEC8_LINE1(A, B, C, D) \ + x_##A = _mm256_add_epi32(x_##A, x_##B); \ + x_##D = _mm256_shuffle_epi8(_mm256_xor_si256(x_##D, x_##A), rot16) +#define VEC8_LINE2(A, B, C, D) \ + x_##C = _mm256_add_epi32(x_##C, x_##D); \ + x_##B = VEC8_ROT(_mm256_xor_si256(x_##B, x_##C), 12) +#define VEC8_LINE3(A, B, C, D) \ + x_##A = _mm256_add_epi32(x_##A, x_##B); \ + x_##D = _mm256_shuffle_epi8(_mm256_xor_si256(x_##D, x_##A), rot8) +#define VEC8_LINE4(A, B, C, D) \ + x_##C = _mm256_add_epi32(x_##C, x_##D); \ + x_##B = VEC8_ROT(_mm256_xor_si256(x_##B, x_##C), 7) + +#define VEC8_ROUND_SEQ(A1, B1, C1, D1, A2, B2, C2, D2, A3, B3, C3, D3, A4, B4, \ + C4, D4) \ + VEC8_LINE1(A1, B1, C1, D1); \ + VEC8_LINE1(A2, B2, C2, D2); \ + VEC8_LINE1(A3, B3, C3, D3); \ + VEC8_LINE1(A4, B4, C4, D4); \ + VEC8_LINE2(A1, B1, C1, D1); \ + VEC8_LINE2(A2, B2, C2, D2); \ + VEC8_LINE2(A3, B3, C3, D3); \ + VEC8_LINE2(A4, B4, C4, D4); \ + VEC8_LINE3(A1, B1, C1, D1); \ + VEC8_LINE3(A2, B2, C2, D2); \ + VEC8_LINE3(A3, B3, C3, D3); \ + VEC8_LINE3(A4, B4, C4, D4); \ + VEC8_LINE4(A1, B1, C1, D1); \ + VEC8_LINE4(A2, B2, C2, D2); \ + VEC8_LINE4(A3, B3, C3, D3); \ + VEC8_LINE4(A4, B4, C4, D4) + +#define VEC8_ROUND_HALF(A1, B1, C1, D1, A2, B2, C2, D2, A3, B3, C3, D3, A4, \ + B4, C4, D4) \ + VEC8_LINE1(A1, B1, C1, D1); \ + VEC8_LINE1(A2, B2, C2, D2); \ + VEC8_LINE2(A1, B1, C1, D1); \ + VEC8_LINE2(A2, B2, C2, D2); \ + VEC8_LINE3(A1, B1, C1, D1); \ + VEC8_LINE3(A2, B2, C2, D2); \ + VEC8_LINE4(A1, B1, C1, D1); \ + VEC8_LINE4(A2, B2, C2, D2); \ + VEC8_LINE1(A3, B3, C3, D3); \ + VEC8_LINE1(A4, B4, C4, D4); \ + VEC8_LINE2(A3, B3, C3, D3); \ + VEC8_LINE2(A4, B4, C4, D4); \ + VEC8_LINE3(A3, B3, C3, D3); \ + VEC8_LINE3(A4, B4, C4, D4); \ + VEC8_LINE4(A3, B3, C3, D3); \ + VEC8_LINE4(A4, B4, C4, D4) + +#define VEC8_ROUND_HALFANDHALF(A1, B1, C1, D1, A2, B2, C2, D2, A3, B3, C3, D3, \ + A4, B4, C4, D4) \ + VEC8_LINE1(A1, B1, C1, D1); \ + VEC8_LINE1(A2, B2, C2, D2); \ + VEC8_LINE2(A1, B1, C1, D1); \ + VEC8_LINE2(A2, B2, C2, D2); \ + VEC8_LINE1(A3, B3, C3, D3); \ + VEC8_LINE1(A4, B4, C4, D4); \ + VEC8_LINE2(A3, B3, C3, D3); \ + VEC8_LINE2(A4, B4, C4, D4); \ + VEC8_LINE3(A1, B1, C1, D1); \ + VEC8_LINE3(A2, B2, C2, D2); \ + VEC8_LINE4(A1, B1, C1, D1); \ + VEC8_LINE4(A2, B2, C2, D2); \ + VEC8_LINE3(A3, B3, C3, D3); \ + VEC8_LINE3(A4, B4, C4, D4); \ + VEC8_LINE4(A3, B3, C3, D3); \ + VEC8_LINE4(A4, B4, C4, D4) + +#define VEC8_ROUND(A1, B1, C1, D1, A2, B2, C2, D2, A3, B3, C3, D3, A4, B4, C4, \ + D4) \ + VEC8_ROUND_SEQ(A1, B1, C1, D1, A2, B2, C2, D2, A3, B3, C3, D3, A4, B4, C4, \ + D4) + +if (bytes >= 512) { + /* constant for shuffling bytes (replacing multiple-of-8 rotates) */ + __m256i rot16 = + _mm256_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2, + 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + __m256i rot8 = + _mm256_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3, + 14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3); + uint32_t in12, in13; + + /* the naive way seems as fast (if not a bit faster) than the vector way */ + __m256i x_0 = _mm256_set1_epi32(x[0]); + __m256i x_1 = _mm256_set1_epi32(x[1]); + __m256i x_2 = _mm256_set1_epi32(x[2]); + __m256i x_3 = _mm256_set1_epi32(x[3]); + __m256i x_4 = _mm256_set1_epi32(x[4]); + __m256i x_5 = _mm256_set1_epi32(x[5]); + __m256i x_6 = _mm256_set1_epi32(x[6]); + __m256i x_7 = _mm256_set1_epi32(x[7]); + __m256i x_8 = _mm256_set1_epi32(x[8]); + __m256i x_9 = _mm256_set1_epi32(x[9]); + __m256i x_10 = _mm256_set1_epi32(x[10]); + __m256i x_11 = _mm256_set1_epi32(x[11]); + __m256i x_12; + __m256i x_13; + __m256i x_14 = _mm256_set1_epi32(x[14]); + __m256i x_15 = _mm256_set1_epi32(x[15]); + + __m256i orig0 = x_0; + __m256i orig1 = x_1; + __m256i orig2 = x_2; + __m256i orig3 = x_3; + __m256i orig4 = x_4; + __m256i orig5 = x_5; + __m256i orig6 = x_6; + __m256i orig7 = x_7; + __m256i orig8 = x_8; + __m256i orig9 = x_9; + __m256i orig10 = x_10; + __m256i orig11 = x_11; + __m256i orig12; + __m256i orig13; + __m256i orig14 = x_14; + __m256i orig15 = x_15; + __m256i t_0, t_1, t_2, t_3, t_4, t_5, t_6, t_7, t_8, t_9, t_10, t_11, t_12, + t_13, t_14, t_15; + + while (bytes >= 512) { + const __m256i addv12 = _mm256_set_epi64x(3, 2, 1, 0); + const __m256i addv13 = _mm256_set_epi64x(7, 6, 5, 4); + const __m256i permute = _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0); + __m256i t12, t13; + + uint64_t in1213; + int i; + + x_0 = orig0; + x_1 = orig1; + x_2 = orig2; + x_3 = orig3; + x_4 = orig4; + x_5 = orig5; + x_6 = orig6; + x_7 = orig7; + x_8 = orig8; + x_9 = orig9; + x_10 = orig10; + x_11 = orig11; + x_14 = orig14; + x_15 = orig15; + + in12 = x[12]; + in13 = x[13]; + in1213 = ((uint64_t) in12) | (((uint64_t) in13) << 32); + x_12 = x_13 = _mm256_broadcastq_epi64(_mm_cvtsi64_si128(in1213)); + + t12 = _mm256_add_epi64(addv12, x_12); + t13 = _mm256_add_epi64(addv13, x_13); + + x_12 = _mm256_unpacklo_epi32(t12, t13); + x_13 = _mm256_unpackhi_epi32(t12, t13); + + t12 = _mm256_unpacklo_epi32(x_12, x_13); + t13 = _mm256_unpackhi_epi32(x_12, x_13); + + /* required because unpack* are intra-lane */ + x_12 = _mm256_permutevar8x32_epi32(t12, permute); + x_13 = _mm256_permutevar8x32_epi32(t13, permute); + + orig12 = x_12; + orig13 = x_13; + + in1213 += 8; + + x[12] = in1213 & 0xFFFFFFFF; + x[13] = (in1213 >> 32) & 0xFFFFFFFF; + + for (i = 0; i < DOLBEAU_ROUNDS; i += 2) { + VEC8_ROUND(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); + VEC8_ROUND(0, 5, 10, 15, 1, 6, 11, 12, 2, 7, 8, 13, 3, 4, 9, 14); + } + +#define ONEQUAD_TRANSPOSE(A, B, C, D) \ + { \ + __m128i t0, t1, t2, t3; \ + x_##A = _mm256_add_epi32(x_##A, orig##A); \ + x_##B = _mm256_add_epi32(x_##B, orig##B); \ + x_##C = _mm256_add_epi32(x_##C, orig##C); \ + x_##D = _mm256_add_epi32(x_##D, orig##D); \ + t_##A = _mm256_unpacklo_epi32(x_##A, x_##B); \ + t_##B = _mm256_unpacklo_epi32(x_##C, x_##D); \ + t_##C = _mm256_unpackhi_epi32(x_##A, x_##B); \ + t_##D = _mm256_unpackhi_epi32(x_##C, x_##D); \ + x_##A = _mm256_unpacklo_epi64(t_##A, t_##B); \ + x_##B = _mm256_unpackhi_epi64(t_##A, t_##B); \ + x_##C = _mm256_unpacklo_epi64(t_##C, t_##D); \ + x_##D = _mm256_unpackhi_epi64(t_##C, t_##D); \ + t0 = _mm_xor_si128(_mm256_extracti128_si256(x_##A, 0), \ + _mm_loadu_si128((const __m128i*) (m + 0))); \ + _mm_storeu_si128((__m128i*) (c + 0), t0); \ + t1 = _mm_xor_si128(_mm256_extracti128_si256(x_##B, 0), \ + _mm_loadu_si128((const __m128i*) (m + 64))); \ + _mm_storeu_si128((__m128i*) (c + 64), t1); \ + t2 = _mm_xor_si128(_mm256_extracti128_si256(x_##C, 0), \ + _mm_loadu_si128((const __m128i*) (m + 128))); \ + _mm_storeu_si128((__m128i*) (c + 128), t2); \ + t3 = _mm_xor_si128(_mm256_extracti128_si256(x_##D, 0), \ + _mm_loadu_si128((const __m128i*) (m + 192))); \ + _mm_storeu_si128((__m128i*) (c + 192), t3); \ + t0 = _mm_xor_si128(_mm256_extracti128_si256(x_##A, 1), \ + _mm_loadu_si128((const __m128i*) (m + 256))); \ + _mm_storeu_si128((__m128i*) (c + 256), t0); \ + t1 = _mm_xor_si128(_mm256_extracti128_si256(x_##B, 1), \ + _mm_loadu_si128((const __m128i*) (m + 320))); \ + _mm_storeu_si128((__m128i*) (c + 320), t1); \ + t2 = _mm_xor_si128(_mm256_extracti128_si256(x_##C, 1), \ + _mm_loadu_si128((const __m128i*) (m + 384))); \ + _mm_storeu_si128((__m128i*) (c + 384), t2); \ + t3 = _mm_xor_si128(_mm256_extracti128_si256(x_##D, 1), \ + _mm_loadu_si128((const __m128i*) (m + 448))); \ + _mm_storeu_si128((__m128i*) (c + 448), t3); \ + } + +#define ONEQUAD(A, B, C, D) ONEQUAD_TRANSPOSE(A, B, C, D) + +#define ONEQUAD_UNPCK(A, B, C, D) \ + { \ + x_##A = _mm256_add_epi32(x_##A, orig##A); \ + x_##B = _mm256_add_epi32(x_##B, orig##B); \ + x_##C = _mm256_add_epi32(x_##C, orig##C); \ + x_##D = _mm256_add_epi32(x_##D, orig##D); \ + t_##A = _mm256_unpacklo_epi32(x_##A, x_##B); \ + t_##B = _mm256_unpacklo_epi32(x_##C, x_##D); \ + t_##C = _mm256_unpackhi_epi32(x_##A, x_##B); \ + t_##D = _mm256_unpackhi_epi32(x_##C, x_##D); \ + x_##A = _mm256_unpacklo_epi64(t_##A, t_##B); \ + x_##B = _mm256_unpackhi_epi64(t_##A, t_##B); \ + x_##C = _mm256_unpacklo_epi64(t_##C, t_##D); \ + x_##D = _mm256_unpackhi_epi64(t_##C, t_##D); \ + } + +#define ONEOCTO(A, B, C, D, A2, B2, C2, D2) \ + { \ + ONEQUAD_UNPCK(A, B, C, D); \ + ONEQUAD_UNPCK(A2, B2, C2, D2); \ + t_##A = _mm256_permute2x128_si256(x_##A, x_##A2, 0x20); \ + t_##A2 = _mm256_permute2x128_si256(x_##A, x_##A2, 0x31); \ + t_##B = _mm256_permute2x128_si256(x_##B, x_##B2, 0x20); \ + t_##B2 = _mm256_permute2x128_si256(x_##B, x_##B2, 0x31); \ + t_##C = _mm256_permute2x128_si256(x_##C, x_##C2, 0x20); \ + t_##C2 = _mm256_permute2x128_si256(x_##C, x_##C2, 0x31); \ + t_##D = _mm256_permute2x128_si256(x_##D, x_##D2, 0x20); \ + t_##D2 = _mm256_permute2x128_si256(x_##D, x_##D2, 0x31); \ + t_##A = _mm256_xor_si256( \ + t_##A, _mm256_loadu_si256((const __m256i*) (m + 0))); \ + t_##B = _mm256_xor_si256( \ + t_##B, _mm256_loadu_si256((const __m256i*) (m + 64))); \ + t_##C = _mm256_xor_si256( \ + t_##C, _mm256_loadu_si256((const __m256i*) (m + 128))); \ + t_##D = _mm256_xor_si256( \ + t_##D, _mm256_loadu_si256((const __m256i*) (m + 192))); \ + t_##A2 = _mm256_xor_si256( \ + t_##A2, _mm256_loadu_si256((const __m256i*) (m + 256))); \ + t_##B2 = _mm256_xor_si256( \ + t_##B2, _mm256_loadu_si256((const __m256i*) (m + 320))); \ + t_##C2 = _mm256_xor_si256( \ + t_##C2, _mm256_loadu_si256((const __m256i*) (m + 384))); \ + t_##D2 = _mm256_xor_si256( \ + t_##D2, _mm256_loadu_si256((const __m256i*) (m + 448))); \ + _mm256_storeu_si256((__m256i*) (c + 0), t_##A); \ + _mm256_storeu_si256((__m256i*) (c + 64), t_##B); \ + _mm256_storeu_si256((__m256i*) (c + 128), t_##C); \ + _mm256_storeu_si256((__m256i*) (c + 192), t_##D); \ + _mm256_storeu_si256((__m256i*) (c + 256), t_##A2); \ + _mm256_storeu_si256((__m256i*) (c + 320), t_##B2); \ + _mm256_storeu_si256((__m256i*) (c + 384), t_##C2); \ + _mm256_storeu_si256((__m256i*) (c + 448), t_##D2); \ + } + + ONEOCTO(0, 1, 2, 3, 4, 5, 6, 7); + m += 32; + c += 32; + ONEOCTO(8, 9, 10, 11, 12, 13, 14, 15); + m -= 32; + c -= 32; + +#undef ONEQUAD +#undef ONEQUAD_TRANSPOSE +#undef ONEQUAD_UNPCK +#undef ONEOCTO + + bytes -= 512; + c += 512; + m += 512; + } +} +#undef VEC8_ROT +#undef VEC8_QUARTERROUND +#undef VEC8_QUARTERROUND_NAIVE +#undef VEC8_QUARTERROUND_SHUFFLE +#undef VEC8_QUARTERROUND_SHUFFLE2 +#undef VEC8_LINE1 +#undef VEC8_LINE2 +#undef VEC8_LINE3 +#undef VEC8_LINE4 +#undef VEC8_ROUND +#undef VEC8_ROUND_SEQ +#undef VEC8_ROUND_HALF +#undef VEC8_ROUND_HALFANDHALF +/*** End of # include "u8.h" ***/ + +/* # include "u4.h" */ +/*** Begin of # include "u4.h" ***/ + +#define VEC4_ROT(A, IMM) \ + _mm_or_si128(_mm_slli_epi32(A, IMM), _mm_srli_epi32(A, (32 - IMM))) + +/* same, but replace 2 of the shift/shift/or "rotation" by byte shuffles (8 & + * 16) (better) */ +#define VEC4_QUARTERROUND_SHUFFLE(A, B, C, D) \ + x_##A = _mm_add_epi32(x_##A, x_##B); \ + t_##A = _mm_xor_si128(x_##D, x_##A); \ + x_##D = _mm_shuffle_epi8(t_##A, rot16); \ + x_##C = _mm_add_epi32(x_##C, x_##D); \ + t_##C = _mm_xor_si128(x_##B, x_##C); \ + x_##B = VEC4_ROT(t_##C, 12); \ + x_##A = _mm_add_epi32(x_##A, x_##B); \ + t_##A = _mm_xor_si128(x_##D, x_##A); \ + x_##D = _mm_shuffle_epi8(t_##A, rot8); \ + x_##C = _mm_add_epi32(x_##C, x_##D); \ + t_##C = _mm_xor_si128(x_##B, x_##C); \ + x_##B = VEC4_ROT(t_##C, 7) + +#define VEC4_QUARTERROUND(A, B, C, D) VEC4_QUARTERROUND_SHUFFLE(A, B, C, D) + +if (bytes >= 256) { + /* constant for shuffling bytes (replacing multiple-of-8 rotates) */ + __m128i rot16 = + _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + __m128i rot8 = + _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3); + + __m128i x_0 = _mm_set1_epi32(x[0]); + __m128i x_1 = _mm_set1_epi32(x[1]); + __m128i x_2 = _mm_set1_epi32(x[2]); + __m128i x_3 = _mm_set1_epi32(x[3]); + __m128i x_4 = _mm_set1_epi32(x[4]); + __m128i x_5 = _mm_set1_epi32(x[5]); + __m128i x_6 = _mm_set1_epi32(x[6]); + __m128i x_7 = _mm_set1_epi32(x[7]); + __m128i x_8 = _mm_set1_epi32(x[8]); + __m128i x_9 = _mm_set1_epi32(x[9]); + __m128i x_10 = _mm_set1_epi32(x[10]); + __m128i x_11 = _mm_set1_epi32(x[11]); + __m128i x_12; + __m128i x_13; + __m128i x_14 = _mm_set1_epi32(x[14]); + __m128i x_15 = _mm_set1_epi32(x[15]); + __m128i orig0 = x_0; + __m128i orig1 = x_1; + __m128i orig2 = x_2; + __m128i orig3 = x_3; + __m128i orig4 = x_4; + __m128i orig5 = x_5; + __m128i orig6 = x_6; + __m128i orig7 = x_7; + __m128i orig8 = x_8; + __m128i orig9 = x_9; + __m128i orig10 = x_10; + __m128i orig11 = x_11; + __m128i orig12; + __m128i orig13; + __m128i orig14 = x_14; + __m128i orig15 = x_15; + __m128i t_0, t_1, t_2, t_3, t_4, t_5, t_6, t_7, t_8, t_9, t_10, t_11, t_12, + t_13, t_14, t_15; + + uint32_t in12, in13; + int i; + + while (bytes >= 256) { + const __m128i addv12 = _mm_set_epi64x(1, 0); + const __m128i addv13 = _mm_set_epi64x(3, 2); + __m128i t12, t13; + uint64_t in1213; + + x_0 = orig0; + x_1 = orig1; + x_2 = orig2; + x_3 = orig3; + x_4 = orig4; + x_5 = orig5; + x_6 = orig6; + x_7 = orig7; + x_8 = orig8; + x_9 = orig9; + x_10 = orig10; + x_11 = orig11; + x_14 = orig14; + x_15 = orig15; + + in12 = x[12]; + in13 = x[13]; + in1213 = ((uint64_t) in12) | (((uint64_t) in13) << 32); + t12 = _mm_set1_epi64x(in1213); + t13 = _mm_set1_epi64x(in1213); + + x_12 = _mm_add_epi64(addv12, t12); + x_13 = _mm_add_epi64(addv13, t13); + + t12 = _mm_unpacklo_epi32(x_12, x_13); + t13 = _mm_unpackhi_epi32(x_12, x_13); + + x_12 = _mm_unpacklo_epi32(t12, t13); + x_13 = _mm_unpackhi_epi32(t12, t13); + + orig12 = x_12; + orig13 = x_13; + + in1213 += 4; + + x[12] = in1213 & 0xFFFFFFFF; + x[13] = (in1213 >> 32) & 0xFFFFFFFF; + + for (i = 0; i < DOLBEAU_ROUNDS; i += 2) { + VEC4_QUARTERROUND(0, 4, 8, 12); + VEC4_QUARTERROUND(1, 5, 9, 13); + VEC4_QUARTERROUND(2, 6, 10, 14); + VEC4_QUARTERROUND(3, 7, 11, 15); + VEC4_QUARTERROUND(0, 5, 10, 15); + VEC4_QUARTERROUND(1, 6, 11, 12); + VEC4_QUARTERROUND(2, 7, 8, 13); + VEC4_QUARTERROUND(3, 4, 9, 14); + } + +#define ONEQUAD_TRANSPOSE(A, B, C, D) \ + { \ + __m128i t0, t1, t2, t3; \ + \ + x_##A = _mm_add_epi32(x_##A, orig##A); \ + x_##B = _mm_add_epi32(x_##B, orig##B); \ + x_##C = _mm_add_epi32(x_##C, orig##C); \ + x_##D = _mm_add_epi32(x_##D, orig##D); \ + t_##A = _mm_unpacklo_epi32(x_##A, x_##B); \ + t_##B = _mm_unpacklo_epi32(x_##C, x_##D); \ + t_##C = _mm_unpackhi_epi32(x_##A, x_##B); \ + t_##D = _mm_unpackhi_epi32(x_##C, x_##D); \ + x_##A = _mm_unpacklo_epi64(t_##A, t_##B); \ + x_##B = _mm_unpackhi_epi64(t_##A, t_##B); \ + x_##C = _mm_unpacklo_epi64(t_##C, t_##D); \ + x_##D = _mm_unpackhi_epi64(t_##C, t_##D); \ + \ + t0 = _mm_xor_si128(x_##A, _mm_loadu_si128((const __m128i*) (m + 0))); \ + _mm_storeu_si128((__m128i*) (c + 0), t0); \ + t1 = _mm_xor_si128(x_##B, _mm_loadu_si128((const __m128i*) (m + 64))); \ + _mm_storeu_si128((__m128i*) (c + 64), t1); \ + t2 = \ + _mm_xor_si128(x_##C, _mm_loadu_si128((const __m128i*) (m + 128))); \ + _mm_storeu_si128((__m128i*) (c + 128), t2); \ + t3 = \ + _mm_xor_si128(x_##D, _mm_loadu_si128((const __m128i*) (m + 192))); \ + _mm_storeu_si128((__m128i*) (c + 192), t3); \ + } + +#define ONEQUAD(A, B, C, D) ONEQUAD_TRANSPOSE(A, B, C, D) + + ONEQUAD(0, 1, 2, 3); + m += 16; + c += 16; + ONEQUAD(4, 5, 6, 7); + m += 16; + c += 16; + ONEQUAD(8, 9, 10, 11); + m += 16; + c += 16; + ONEQUAD(12, 13, 14, 15); + m -= 48; + c -= 48; + +#undef ONEQUAD +#undef ONEQUAD_TRANSPOSE + + bytes -= 256; + c += 256; + m += 256; + } +} +#undef VEC4_ROT +#undef VEC4_QUARTERROUND +#undef VEC4_QUARTERROUND_SHUFFLE +/*** End of # include "u4.h" ***/ + +/* # include "u1.h" */ +/*** Begin of # include "u1.h" ***/ +while (bytes >= 64) { + __m128i x_0, x_1, x_2, x_3; + __m128i t_1; + const __m128i rot16 = + _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + const __m128i rot8 = + _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3); + + uint32_t in12; + uint32_t in13; + int i; + + x_0 = _mm_loadu_si128((const __m128i*) (x + 0)); + x_1 = _mm_loadu_si128((const __m128i*) (x + 4)); + x_2 = _mm_loadu_si128((const __m128i*) (x + 8)); + x_3 = _mm_loadu_si128((const __m128i*) (x + 12)); + + for (i = 0; i < DOLBEAU_ROUNDS; i += 2) { + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_3 = _mm_shuffle_epi8(x_3, rot16); + + x_2 = _mm_add_epi32(x_2, x_3); + x_1 = _mm_xor_si128(x_1, x_2); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 12); + t_1 = _mm_srli_epi32(t_1, 20); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_0 = _mm_shuffle_epi32(x_0, 0x93); + x_3 = _mm_shuffle_epi8(x_3, rot8); + + x_2 = _mm_add_epi32(x_2, x_3); + x_3 = _mm_shuffle_epi32(x_3, 0x4e); + x_1 = _mm_xor_si128(x_1, x_2); + x_2 = _mm_shuffle_epi32(x_2, 0x39); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 7); + t_1 = _mm_srli_epi32(t_1, 25); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_3 = _mm_shuffle_epi8(x_3, rot16); + + x_2 = _mm_add_epi32(x_2, x_3); + x_1 = _mm_xor_si128(x_1, x_2); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 12); + t_1 = _mm_srli_epi32(t_1, 20); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_0 = _mm_shuffle_epi32(x_0, 0x39); + x_3 = _mm_shuffle_epi8(x_3, rot8); + + x_2 = _mm_add_epi32(x_2, x_3); + x_3 = _mm_shuffle_epi32(x_3, 0x4e); + x_1 = _mm_xor_si128(x_1, x_2); + x_2 = _mm_shuffle_epi32(x_2, 0x93); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 7); + t_1 = _mm_srli_epi32(t_1, 25); + x_1 = _mm_xor_si128(x_1, t_1); + } + x_0 = _mm_add_epi32(x_0, _mm_loadu_si128((const __m128i*) (x + 0))); + x_1 = _mm_add_epi32(x_1, _mm_loadu_si128((const __m128i*) (x + 4))); + x_2 = _mm_add_epi32(x_2, _mm_loadu_si128((const __m128i*) (x + 8))); + x_3 = _mm_add_epi32(x_3, _mm_loadu_si128((const __m128i*) (x + 12))); + x_0 = _mm_xor_si128(x_0, _mm_loadu_si128((const __m128i*) (m + 0))); + x_1 = _mm_xor_si128(x_1, _mm_loadu_si128((const __m128i*) (m + 16))); + x_2 = _mm_xor_si128(x_2, _mm_loadu_si128((const __m128i*) (m + 32))); + x_3 = _mm_xor_si128(x_3, _mm_loadu_si128((const __m128i*) (m + 48))); + _mm_storeu_si128((__m128i*) (c + 0), x_0); + _mm_storeu_si128((__m128i*) (c + 16), x_1); + _mm_storeu_si128((__m128i*) (c + 32), x_2); + _mm_storeu_si128((__m128i*) (c + 48), x_3); + + in12 = x[12]; + in13 = x[13]; + in12++; + if (in12 == 0) { + in13++; + } + x[12] = in12; + x[13] = in13; + + bytes -= 64; + c += 64; + m += 64; +} +/*** End of # include "u1.h" ***/ + +/* # include "u0.h" */ +/*** Begin of # include "u0.h" ***/ +if (bytes > 0) { + __m128i x_0, x_1, x_2, x_3; + __m128i t_1; + const __m128i rot16 = + _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + const __m128i rot8 = + _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3); + uint8_t partialblock[64]; + + unsigned int i; + + x_0 = _mm_loadu_si128((const __m128i*) (x + 0)); + x_1 = _mm_loadu_si128((const __m128i*) (x + 4)); + x_2 = _mm_loadu_si128((const __m128i*) (x + 8)); + x_3 = _mm_loadu_si128((const __m128i*) (x + 12)); + + for (i = 0; i < DOLBEAU_ROUNDS; i += 2) { + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_3 = _mm_shuffle_epi8(x_3, rot16); + + x_2 = _mm_add_epi32(x_2, x_3); + x_1 = _mm_xor_si128(x_1, x_2); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 12); + t_1 = _mm_srli_epi32(t_1, 20); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_0 = _mm_shuffle_epi32(x_0, 0x93); + x_3 = _mm_shuffle_epi8(x_3, rot8); + + x_2 = _mm_add_epi32(x_2, x_3); + x_3 = _mm_shuffle_epi32(x_3, 0x4e); + x_1 = _mm_xor_si128(x_1, x_2); + x_2 = _mm_shuffle_epi32(x_2, 0x39); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 7); + t_1 = _mm_srli_epi32(t_1, 25); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_3 = _mm_shuffle_epi8(x_3, rot16); + + x_2 = _mm_add_epi32(x_2, x_3); + x_1 = _mm_xor_si128(x_1, x_2); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 12); + t_1 = _mm_srli_epi32(t_1, 20); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_0 = _mm_shuffle_epi32(x_0, 0x39); + x_3 = _mm_shuffle_epi8(x_3, rot8); + + x_2 = _mm_add_epi32(x_2, x_3); + x_3 = _mm_shuffle_epi32(x_3, 0x4e); + x_1 = _mm_xor_si128(x_1, x_2); + x_2 = _mm_shuffle_epi32(x_2, 0x93); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 7); + t_1 = _mm_srli_epi32(t_1, 25); + x_1 = _mm_xor_si128(x_1, t_1); + } + x_0 = _mm_add_epi32(x_0, _mm_loadu_si128((const __m128i*) (x + 0))); + x_1 = _mm_add_epi32(x_1, _mm_loadu_si128((const __m128i*) (x + 4))); + x_2 = _mm_add_epi32(x_2, _mm_loadu_si128((const __m128i*) (x + 8))); + x_3 = _mm_add_epi32(x_3, _mm_loadu_si128((const __m128i*) (x + 12))); + _mm_storeu_si128((__m128i*) (partialblock + 0), x_0); + _mm_storeu_si128((__m128i*) (partialblock + 16), x_1); + _mm_storeu_si128((__m128i*) (partialblock + 32), x_2); + _mm_storeu_si128((__m128i*) (partialblock + 48), x_3); + + for (i = 0; i < bytes; i++) { + c[i] = m[i] ^ partialblock[i]; + } + + sodium_memzero(partialblock, sizeof partialblock); +} +/*** End of # include "u0.h" ***/ + +} + +static int +dolbeau_avx2_stream_ref_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, uint64_t ic, + const unsigned char *k) +{ + struct chacha_ctx ctx; + uint8_t ic_bytes[8]; + uint32_t ic_high; + uint32_t ic_low; + + if (!mlen) { + return 0; + } + ic_high = (uint32_t) (ic >> 32); + ic_low = (uint32_t) ic; + SODIUM_STORE32_LE(&ic_bytes[0], ic_low); + SODIUM_STORE32_LE(&ic_bytes[4], ic_high); + dolbeau_avx2_chacha_keysetup(&ctx, k); + dolbeau_avx2_chacha_ivsetup(&ctx, n, ic_bytes); + dolbeau_avx2_chacha20_encrypt_bytes(&ctx, m, c, mlen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +static int +dolbeau_avx2_stream_ietf_ext_ref_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + uint32_t ic, const unsigned char *k) +{ + struct chacha_ctx ctx; + uint8_t ic_bytes[4]; + + if (!mlen) { + return 0; + } + SODIUM_STORE32_LE(ic_bytes, ic); + dolbeau_avx2_chacha_keysetup(&ctx, k); + dolbeau_avx2_chacha_ietf_ivsetup(&ctx, n, ic_bytes); + dolbeau_avx2_chacha20_encrypt_bytes(&ctx, m, c, mlen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +struct crypto_stream_chacha20_implementation + crypto_stream_chacha20_dolbeau_avx2_implementation = { + .stream_xor_ic = dolbeau_avx2_stream_ref_xor_ic, + .stream_ietf_ext_xor_ic = dolbeau_avx2_stream_ietf_ext_ref_xor_ic + }; + +# ifdef __clang__ +# pragma clang attribute pop +# endif + +#endif +/*** End of # include "dolbeau/chacha20_dolbeau-avx2.c" ***/ + +/* # include "dolbeau/chacha20_dolbeau-avx512.c" */ +/*** Begin of # include "dolbeau/chacha20_dolbeau-avx512.c" ***/ + +#include +#include +#include + +/* #include "../crypto_stream_chacha20.h" */ + +/* #include "../private/common.h" */ + + +#if defined(SQLITE3MC_TARGET_X86) + +# ifdef __clang__ +# if __clang_major__ >= 18 && __clang_major__ < 22 +# pragma clang attribute push(__attribute__((target("sse2,ssse3,sse4.1,avx2,avx512f,evex512"))), apply_to = function) +# else +# pragma clang attribute push(__attribute__((target("sse2,ssse3,sse4.1,avx2,avx512f"))), apply_to = function) +# endif +# elif defined(__GNUC__) +# pragma GCC target("sse2,ssse3,sse4.1,avx2,avx512f") +# endif + +# include +# include +# include +# include +/* # include "../private/sse2_64_32.h" */ + + +/* # include "../stream_chacha20.h" */ + +/* # include "chacha20_dolbeau-avx512.h" */ +/*** Begin of # include "chacha20_dolbeau-avx512.h" ***/ + +#include + +/* #include "../stream_chacha20.h" */ + +/* #include "../crypto_stream_chacha20.h" */ + + +extern struct crypto_stream_chacha20_implementation + crypto_stream_chacha20_dolbeau_avx512_implementation; +/*** End of # include "chacha20_dolbeau-avx512.h" ***/ + + +#ifdef DOLBEAU_ROUNDS +# undef DOLBEAU_ROUNDS +# define DOLBEAU_ROUNDS 20 +#else +# define DOLBEAU_ROUNDS 20 +#endif + +static void +dolbeau_avx512_chacha_keysetup(chacha_ctx *ctx, const uint8_t *k) +{ + ctx->input[0] = 0x61707865; + ctx->input[1] = 0x3320646e; + ctx->input[2] = 0x79622d32; + ctx->input[3] = 0x6b206574; + ctx->input[4] = SODIUM_LOAD32_LE(k + 0); + ctx->input[5] = SODIUM_LOAD32_LE(k + 4); + ctx->input[6] = SODIUM_LOAD32_LE(k + 8); + ctx->input[7] = SODIUM_LOAD32_LE(k + 12); + ctx->input[8] = SODIUM_LOAD32_LE(k + 16); + ctx->input[9] = SODIUM_LOAD32_LE(k + 20); + ctx->input[10] = SODIUM_LOAD32_LE(k + 24); + ctx->input[11] = SODIUM_LOAD32_LE(k + 28); +} + +static void +dolbeau_avx512_chacha_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter) +{ + ctx->input[12] = counter == NULL ? 0 : SODIUM_LOAD32_LE(counter + 0); + ctx->input[13] = counter == NULL ? 0 : SODIUM_LOAD32_LE(counter + 4); + ctx->input[14] = SODIUM_LOAD32_LE(iv + 0); + ctx->input[15] = SODIUM_LOAD32_LE(iv + 4); +} + +static void +dolbeau_avx512_chacha_ietf_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter) +{ + ctx->input[12] = counter == NULL ? 0 : SODIUM_LOAD32_LE(counter); + ctx->input[13] = SODIUM_LOAD32_LE(iv + 0); + ctx->input[14] = SODIUM_LOAD32_LE(iv + 4); + ctx->input[15] = SODIUM_LOAD32_LE(iv + 8); +} + +static void +dolbeau_avx512_chacha20_encrypt_bytes(chacha_ctx *ctx, const uint8_t *m, uint8_t *c, + unsigned long long bytes) +{ + uint32_t * const x = &ctx->input[0]; + + if (!bytes) { + return; /* LCOV_EXCL_LINE */ + } +/* # include "u16.h" */ +/*** Begin of # include "u16.h" ***/ + +#define VEC16_LINE1(A, B, C, D) \ + x_##A = _mm512_add_epi32(x_##A, x_##B); \ + x_##D = _mm512_rol_epi32(_mm512_xor_si512(x_##D, x_##A), 16) +#define VEC16_LINE2(A, B, C, D) \ + x_##C = _mm512_add_epi32(x_##C, x_##D); \ + x_##B = _mm512_rol_epi32(_mm512_xor_si512(x_##B, x_##C), 12) +#define VEC16_LINE3(A, B, C, D) \ + x_##A = _mm512_add_epi32(x_##A, x_##B); \ + x_##D = _mm512_rol_epi32(_mm512_xor_si512(x_##D, x_##A), 8) +#define VEC16_LINE4(A, B, C, D) \ + x_##C = _mm512_add_epi32(x_##C, x_##D); \ + x_##B = _mm512_rol_epi32(_mm512_xor_si512(x_##B, x_##C), 7) + +#define VEC16_ROUND(A1, B1, C1, D1, A2, B2, C2, D2, A3, B3, C3, D3, A4, B4, C4, \ + D4) \ + VEC16_LINE1(A1, B1, C1, D1); \ + VEC16_LINE1(A2, B2, C2, D2); \ + VEC16_LINE1(A3, B3, C3, D3); \ + VEC16_LINE1(A4, B4, C4, D4); \ + VEC16_LINE2(A1, B1, C1, D1); \ + VEC16_LINE2(A2, B2, C2, D2); \ + VEC16_LINE2(A3, B3, C3, D3); \ + VEC16_LINE2(A4, B4, C4, D4); \ + VEC16_LINE3(A1, B1, C1, D1); \ + VEC16_LINE3(A2, B2, C2, D2); \ + VEC16_LINE3(A3, B3, C3, D3); \ + VEC16_LINE3(A4, B4, C4, D4); \ + VEC16_LINE4(A1, B1, C1, D1); \ + VEC16_LINE4(A2, B2, C2, D2); \ + VEC16_LINE4(A3, B3, C3, D3); \ + VEC16_LINE4(A4, B4, C4, D4) + +/* store 4 blocks whose 16 words are spread one-per-lane across the 4 source + * registers; a 4x4 transpose of 128-bit lanes finishes the 16x16 transpose that + * the two unpack stages below start. */ +#define ONEQUAD_TRANSPOSE_STORE(A, B, C, D) \ + { \ + __m512i u0 = _mm512_shuffle_i32x4(x_##A, x_##B, 0x88); \ + __m512i u1 = _mm512_shuffle_i32x4(x_##A, x_##B, 0xdd); \ + __m512i u2 = _mm512_shuffle_i32x4(x_##C, x_##D, 0x88); \ + __m512i u3 = _mm512_shuffle_i32x4(x_##C, x_##D, 0xdd); \ + __m512i b0 = _mm512_shuffle_i32x4(u0, u2, 0x88); \ + __m512i b1 = _mm512_shuffle_i32x4(u1, u3, 0x88); \ + __m512i b2 = _mm512_shuffle_i32x4(u0, u2, 0xdd); \ + __m512i b3 = _mm512_shuffle_i32x4(u1, u3, 0xdd); \ + b0 = _mm512_xor_si512( \ + b0, _mm512_loadu_si512((const void *) (m + 64 * (A)))); \ + b1 = _mm512_xor_si512( \ + b1, _mm512_loadu_si512((const void *) (m + 64 * (B)))); \ + b2 = _mm512_xor_si512( \ + b2, _mm512_loadu_si512((const void *) (m + 64 * (C)))); \ + b3 = _mm512_xor_si512( \ + b3, _mm512_loadu_si512((const void *) (m + 64 * (D)))); \ + _mm512_storeu_si512((void *) (c + 64 * (A)), b0); \ + _mm512_storeu_si512((void *) (c + 64 * (B)), b1); \ + _mm512_storeu_si512((void *) (c + 64 * (C)), b2); \ + _mm512_storeu_si512((void *) (c + 64 * (D)), b3); \ + } + +if (bytes >= 1024) { + const __m512i addv = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15); + uint32_t in12, in13; + + __m512i x_0 = _mm512_set1_epi32(x[0]); + __m512i x_1 = _mm512_set1_epi32(x[1]); + __m512i x_2 = _mm512_set1_epi32(x[2]); + __m512i x_3 = _mm512_set1_epi32(x[3]); + __m512i x_4 = _mm512_set1_epi32(x[4]); + __m512i x_5 = _mm512_set1_epi32(x[5]); + __m512i x_6 = _mm512_set1_epi32(x[6]); + __m512i x_7 = _mm512_set1_epi32(x[7]); + __m512i x_8 = _mm512_set1_epi32(x[8]); + __m512i x_9 = _mm512_set1_epi32(x[9]); + __m512i x_10 = _mm512_set1_epi32(x[10]); + __m512i x_11 = _mm512_set1_epi32(x[11]); + __m512i x_12; + __m512i x_13; + __m512i x_14 = _mm512_set1_epi32(x[14]); + __m512i x_15 = _mm512_set1_epi32(x[15]); + + __m512i orig0 = x_0; + __m512i orig1 = x_1; + __m512i orig2 = x_2; + __m512i orig3 = x_3; + __m512i orig4 = x_4; + __m512i orig5 = x_5; + __m512i orig6 = x_6; + __m512i orig7 = x_7; + __m512i orig8 = x_8; + __m512i orig9 = x_9; + __m512i orig10 = x_10; + __m512i orig11 = x_11; + __m512i orig12; + __m512i orig13; + __m512i orig14 = x_14; + __m512i orig15 = x_15; + __m512i t_0, t_1, t_2, t_3, t_4, t_5, t_6, t_7, t_8, t_9, t_10, t_11, t_12, + t_13, t_14, t_15; + + while (bytes >= 1024) { + __m512i base12, base13; + __mmask16 carry; + uint64_t in1213; + int i; + + x_0 = orig0; + x_1 = orig1; + x_2 = orig2; + x_3 = orig3; + x_4 = orig4; + x_5 = orig5; + x_6 = orig6; + x_7 = orig7; + x_8 = orig8; + x_9 = orig9; + x_10 = orig10; + x_11 = orig11; + x_14 = orig14; + x_15 = orig15; + + in12 = x[12]; + in13 = x[13]; + + /* per-block 64-bit counter: lane j holds (in12|in13<<32) + j, split back + * into low/high words. carry propagates only where the low add wraps. */ + base12 = _mm512_set1_epi32(in12); + base13 = _mm512_set1_epi32(in13); + x_12 = _mm512_add_epi32(base12, addv); + carry = _mm512_cmplt_epu32_mask(x_12, base12); + x_13 = _mm512_mask_add_epi32(base13, carry, base13, + _mm512_set1_epi32(1)); + + orig12 = x_12; + orig13 = x_13; + + in1213 = ((uint64_t) in12) | (((uint64_t) in13) << 32); + in1213 += 16; + + x[12] = in1213 & 0xFFFFFFFF; + x[13] = (in1213 >> 32) & 0xFFFFFFFF; + + for (i = 0; i < DOLBEAU_ROUNDS; i += 2) { + VEC16_ROUND(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); + VEC16_ROUND(0, 5, 10, 15, 1, 6, 11, 12, 2, 7, 8, 13, 3, 4, 9, 14); + } + + x_0 = _mm512_add_epi32(x_0, orig0); + x_1 = _mm512_add_epi32(x_1, orig1); + x_2 = _mm512_add_epi32(x_2, orig2); + x_3 = _mm512_add_epi32(x_3, orig3); + x_4 = _mm512_add_epi32(x_4, orig4); + x_5 = _mm512_add_epi32(x_5, orig5); + x_6 = _mm512_add_epi32(x_6, orig6); + x_7 = _mm512_add_epi32(x_7, orig7); + x_8 = _mm512_add_epi32(x_8, orig8); + x_9 = _mm512_add_epi32(x_9, orig9); + x_10 = _mm512_add_epi32(x_10, orig10); + x_11 = _mm512_add_epi32(x_11, orig11); + x_12 = _mm512_add_epi32(x_12, orig12); + x_13 = _mm512_add_epi32(x_13, orig13); + x_14 = _mm512_add_epi32(x_14, orig14); + x_15 = _mm512_add_epi32(x_15, orig15); + + /* 16x16 transpose, stage 1: interleave 32-bit words of adjacent rows */ + t_0 = _mm512_unpacklo_epi32(x_0, x_1); + t_1 = _mm512_unpackhi_epi32(x_0, x_1); + t_2 = _mm512_unpacklo_epi32(x_2, x_3); + t_3 = _mm512_unpackhi_epi32(x_2, x_3); + t_4 = _mm512_unpacklo_epi32(x_4, x_5); + t_5 = _mm512_unpackhi_epi32(x_4, x_5); + t_6 = _mm512_unpacklo_epi32(x_6, x_7); + t_7 = _mm512_unpackhi_epi32(x_6, x_7); + t_8 = _mm512_unpacklo_epi32(x_8, x_9); + t_9 = _mm512_unpackhi_epi32(x_8, x_9); + t_10 = _mm512_unpacklo_epi32(x_10, x_11); + t_11 = _mm512_unpackhi_epi32(x_10, x_11); + t_12 = _mm512_unpacklo_epi32(x_12, x_13); + t_13 = _mm512_unpackhi_epi32(x_12, x_13); + t_14 = _mm512_unpacklo_epi32(x_14, x_15); + t_15 = _mm512_unpackhi_epi32(x_14, x_15); + + /* stage 2: interleave 64-bit words */ + x_0 = _mm512_unpacklo_epi64(t_0, t_2); + x_1 = _mm512_unpackhi_epi64(t_0, t_2); + x_2 = _mm512_unpacklo_epi64(t_1, t_3); + x_3 = _mm512_unpackhi_epi64(t_1, t_3); + x_4 = _mm512_unpacklo_epi64(t_4, t_6); + x_5 = _mm512_unpackhi_epi64(t_4, t_6); + x_6 = _mm512_unpacklo_epi64(t_5, t_7); + x_7 = _mm512_unpackhi_epi64(t_5, t_7); + x_8 = _mm512_unpacklo_epi64(t_8, t_10); + x_9 = _mm512_unpackhi_epi64(t_8, t_10); + x_10 = _mm512_unpacklo_epi64(t_9, t_11); + x_11 = _mm512_unpackhi_epi64(t_9, t_11); + x_12 = _mm512_unpacklo_epi64(t_12, t_14); + x_13 = _mm512_unpackhi_epi64(t_12, t_14); + x_14 = _mm512_unpacklo_epi64(t_13, t_15); + x_15 = _mm512_unpackhi_epi64(t_13, t_15); + + /* stage 3/4: shuffle 128-bit lanes, xor with the message, store */ + ONEQUAD_TRANSPOSE_STORE(0, 4, 8, 12); + ONEQUAD_TRANSPOSE_STORE(1, 5, 9, 13); + ONEQUAD_TRANSPOSE_STORE(2, 6, 10, 14); + ONEQUAD_TRANSPOSE_STORE(3, 7, 11, 15); + + bytes -= 1024; + c += 1024; + m += 1024; + } +} + +#undef VEC16_LINE1 +#undef VEC16_LINE2 +#undef VEC16_LINE3 +#undef VEC16_LINE4 +#undef VEC16_ROUND +#undef ONEQUAD_TRANSPOSE_STORE +/*** End of # include "u16.h" ***/ + +/* # include "u8.h" */ +/*** Begin of # include "u8.h" ***/ + +#define VEC8_ROT(A, IMM) \ + _mm256_or_si256(_mm256_slli_epi32(A, IMM), _mm256_srli_epi32(A, (32 - IMM))) + +/* same, but replace 2 of the shift/shift/or "rotation" by byte shuffles (8 & + * 16) (better) */ +#define VEC8_QUARTERROUND_SHUFFLE(A, B, C, D) \ + x_##A = _mm256_add_epi32(x_##A, x_##B); \ + t_##A = _mm256_xor_si256(x_##D, x_##A); \ + x_##D = _mm256_shuffle_epi8(t_##A, rot16); \ + x_##C = _mm256_add_epi32(x_##C, x_##D); \ + t_##C = _mm256_xor_si256(x_##B, x_##C); \ + x_##B = VEC8_ROT(t_##C, 12); \ + x_##A = _mm256_add_epi32(x_##A, x_##B); \ + t_##A = _mm256_xor_si256(x_##D, x_##A); \ + x_##D = _mm256_shuffle_epi8(t_##A, rot8); \ + x_##C = _mm256_add_epi32(x_##C, x_##D); \ + t_##C = _mm256_xor_si256(x_##B, x_##C); \ + x_##B = VEC8_ROT(t_##C, 7) + +#define VEC8_QUARTERROUND(A, B, C, D) VEC8_QUARTERROUND_SHUFFLE(A, B, C, D) + +#define VEC8_LINE1(A, B, C, D) \ + x_##A = _mm256_add_epi32(x_##A, x_##B); \ + x_##D = _mm256_shuffle_epi8(_mm256_xor_si256(x_##D, x_##A), rot16) +#define VEC8_LINE2(A, B, C, D) \ + x_##C = _mm256_add_epi32(x_##C, x_##D); \ + x_##B = VEC8_ROT(_mm256_xor_si256(x_##B, x_##C), 12) +#define VEC8_LINE3(A, B, C, D) \ + x_##A = _mm256_add_epi32(x_##A, x_##B); \ + x_##D = _mm256_shuffle_epi8(_mm256_xor_si256(x_##D, x_##A), rot8) +#define VEC8_LINE4(A, B, C, D) \ + x_##C = _mm256_add_epi32(x_##C, x_##D); \ + x_##B = VEC8_ROT(_mm256_xor_si256(x_##B, x_##C), 7) + +#define VEC8_ROUND_SEQ(A1, B1, C1, D1, A2, B2, C2, D2, A3, B3, C3, D3, A4, B4, \ + C4, D4) \ + VEC8_LINE1(A1, B1, C1, D1); \ + VEC8_LINE1(A2, B2, C2, D2); \ + VEC8_LINE1(A3, B3, C3, D3); \ + VEC8_LINE1(A4, B4, C4, D4); \ + VEC8_LINE2(A1, B1, C1, D1); \ + VEC8_LINE2(A2, B2, C2, D2); \ + VEC8_LINE2(A3, B3, C3, D3); \ + VEC8_LINE2(A4, B4, C4, D4); \ + VEC8_LINE3(A1, B1, C1, D1); \ + VEC8_LINE3(A2, B2, C2, D2); \ + VEC8_LINE3(A3, B3, C3, D3); \ + VEC8_LINE3(A4, B4, C4, D4); \ + VEC8_LINE4(A1, B1, C1, D1); \ + VEC8_LINE4(A2, B2, C2, D2); \ + VEC8_LINE4(A3, B3, C3, D3); \ + VEC8_LINE4(A4, B4, C4, D4) + +#define VEC8_ROUND_HALF(A1, B1, C1, D1, A2, B2, C2, D2, A3, B3, C3, D3, A4, \ + B4, C4, D4) \ + VEC8_LINE1(A1, B1, C1, D1); \ + VEC8_LINE1(A2, B2, C2, D2); \ + VEC8_LINE2(A1, B1, C1, D1); \ + VEC8_LINE2(A2, B2, C2, D2); \ + VEC8_LINE3(A1, B1, C1, D1); \ + VEC8_LINE3(A2, B2, C2, D2); \ + VEC8_LINE4(A1, B1, C1, D1); \ + VEC8_LINE4(A2, B2, C2, D2); \ + VEC8_LINE1(A3, B3, C3, D3); \ + VEC8_LINE1(A4, B4, C4, D4); \ + VEC8_LINE2(A3, B3, C3, D3); \ + VEC8_LINE2(A4, B4, C4, D4); \ + VEC8_LINE3(A3, B3, C3, D3); \ + VEC8_LINE3(A4, B4, C4, D4); \ + VEC8_LINE4(A3, B3, C3, D3); \ + VEC8_LINE4(A4, B4, C4, D4) + +#define VEC8_ROUND_HALFANDHALF(A1, B1, C1, D1, A2, B2, C2, D2, A3, B3, C3, D3, \ + A4, B4, C4, D4) \ + VEC8_LINE1(A1, B1, C1, D1); \ + VEC8_LINE1(A2, B2, C2, D2); \ + VEC8_LINE2(A1, B1, C1, D1); \ + VEC8_LINE2(A2, B2, C2, D2); \ + VEC8_LINE1(A3, B3, C3, D3); \ + VEC8_LINE1(A4, B4, C4, D4); \ + VEC8_LINE2(A3, B3, C3, D3); \ + VEC8_LINE2(A4, B4, C4, D4); \ + VEC8_LINE3(A1, B1, C1, D1); \ + VEC8_LINE3(A2, B2, C2, D2); \ + VEC8_LINE4(A1, B1, C1, D1); \ + VEC8_LINE4(A2, B2, C2, D2); \ + VEC8_LINE3(A3, B3, C3, D3); \ + VEC8_LINE3(A4, B4, C4, D4); \ + VEC8_LINE4(A3, B3, C3, D3); \ + VEC8_LINE4(A4, B4, C4, D4) + +#define VEC8_ROUND(A1, B1, C1, D1, A2, B2, C2, D2, A3, B3, C3, D3, A4, B4, C4, \ + D4) \ + VEC8_ROUND_SEQ(A1, B1, C1, D1, A2, B2, C2, D2, A3, B3, C3, D3, A4, B4, C4, \ + D4) + +if (bytes >= 512) { + /* constant for shuffling bytes (replacing multiple-of-8 rotates) */ + __m256i rot16 = + _mm256_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2, + 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + __m256i rot8 = + _mm256_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3, + 14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3); + uint32_t in12, in13; + + /* the naive way seems as fast (if not a bit faster) than the vector way */ + __m256i x_0 = _mm256_set1_epi32(x[0]); + __m256i x_1 = _mm256_set1_epi32(x[1]); + __m256i x_2 = _mm256_set1_epi32(x[2]); + __m256i x_3 = _mm256_set1_epi32(x[3]); + __m256i x_4 = _mm256_set1_epi32(x[4]); + __m256i x_5 = _mm256_set1_epi32(x[5]); + __m256i x_6 = _mm256_set1_epi32(x[6]); + __m256i x_7 = _mm256_set1_epi32(x[7]); + __m256i x_8 = _mm256_set1_epi32(x[8]); + __m256i x_9 = _mm256_set1_epi32(x[9]); + __m256i x_10 = _mm256_set1_epi32(x[10]); + __m256i x_11 = _mm256_set1_epi32(x[11]); + __m256i x_12; + __m256i x_13; + __m256i x_14 = _mm256_set1_epi32(x[14]); + __m256i x_15 = _mm256_set1_epi32(x[15]); + + __m256i orig0 = x_0; + __m256i orig1 = x_1; + __m256i orig2 = x_2; + __m256i orig3 = x_3; + __m256i orig4 = x_4; + __m256i orig5 = x_5; + __m256i orig6 = x_6; + __m256i orig7 = x_7; + __m256i orig8 = x_8; + __m256i orig9 = x_9; + __m256i orig10 = x_10; + __m256i orig11 = x_11; + __m256i orig12; + __m256i orig13; + __m256i orig14 = x_14; + __m256i orig15 = x_15; + __m256i t_0, t_1, t_2, t_3, t_4, t_5, t_6, t_7, t_8, t_9, t_10, t_11, t_12, + t_13, t_14, t_15; + + while (bytes >= 512) { + const __m256i addv12 = _mm256_set_epi64x(3, 2, 1, 0); + const __m256i addv13 = _mm256_set_epi64x(7, 6, 5, 4); + const __m256i permute = _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0); + __m256i t12, t13; + + uint64_t in1213; + int i; + + x_0 = orig0; + x_1 = orig1; + x_2 = orig2; + x_3 = orig3; + x_4 = orig4; + x_5 = orig5; + x_6 = orig6; + x_7 = orig7; + x_8 = orig8; + x_9 = orig9; + x_10 = orig10; + x_11 = orig11; + x_14 = orig14; + x_15 = orig15; + + in12 = x[12]; + in13 = x[13]; + in1213 = ((uint64_t) in12) | (((uint64_t) in13) << 32); + x_12 = x_13 = _mm256_broadcastq_epi64(_mm_cvtsi64_si128(in1213)); + + t12 = _mm256_add_epi64(addv12, x_12); + t13 = _mm256_add_epi64(addv13, x_13); + + x_12 = _mm256_unpacklo_epi32(t12, t13); + x_13 = _mm256_unpackhi_epi32(t12, t13); + + t12 = _mm256_unpacklo_epi32(x_12, x_13); + t13 = _mm256_unpackhi_epi32(x_12, x_13); + + /* required because unpack* are intra-lane */ + x_12 = _mm256_permutevar8x32_epi32(t12, permute); + x_13 = _mm256_permutevar8x32_epi32(t13, permute); + + orig12 = x_12; + orig13 = x_13; + + in1213 += 8; + + x[12] = in1213 & 0xFFFFFFFF; + x[13] = (in1213 >> 32) & 0xFFFFFFFF; + + for (i = 0; i < DOLBEAU_ROUNDS; i += 2) { + VEC8_ROUND(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); + VEC8_ROUND(0, 5, 10, 15, 1, 6, 11, 12, 2, 7, 8, 13, 3, 4, 9, 14); + } + +#define ONEQUAD_TRANSPOSE(A, B, C, D) \ + { \ + __m128i t0, t1, t2, t3; \ + x_##A = _mm256_add_epi32(x_##A, orig##A); \ + x_##B = _mm256_add_epi32(x_##B, orig##B); \ + x_##C = _mm256_add_epi32(x_##C, orig##C); \ + x_##D = _mm256_add_epi32(x_##D, orig##D); \ + t_##A = _mm256_unpacklo_epi32(x_##A, x_##B); \ + t_##B = _mm256_unpacklo_epi32(x_##C, x_##D); \ + t_##C = _mm256_unpackhi_epi32(x_##A, x_##B); \ + t_##D = _mm256_unpackhi_epi32(x_##C, x_##D); \ + x_##A = _mm256_unpacklo_epi64(t_##A, t_##B); \ + x_##B = _mm256_unpackhi_epi64(t_##A, t_##B); \ + x_##C = _mm256_unpacklo_epi64(t_##C, t_##D); \ + x_##D = _mm256_unpackhi_epi64(t_##C, t_##D); \ + t0 = _mm_xor_si128(_mm256_extracti128_si256(x_##A, 0), \ + _mm_loadu_si128((const __m128i*) (m + 0))); \ + _mm_storeu_si128((__m128i*) (c + 0), t0); \ + t1 = _mm_xor_si128(_mm256_extracti128_si256(x_##B, 0), \ + _mm_loadu_si128((const __m128i*) (m + 64))); \ + _mm_storeu_si128((__m128i*) (c + 64), t1); \ + t2 = _mm_xor_si128(_mm256_extracti128_si256(x_##C, 0), \ + _mm_loadu_si128((const __m128i*) (m + 128))); \ + _mm_storeu_si128((__m128i*) (c + 128), t2); \ + t3 = _mm_xor_si128(_mm256_extracti128_si256(x_##D, 0), \ + _mm_loadu_si128((const __m128i*) (m + 192))); \ + _mm_storeu_si128((__m128i*) (c + 192), t3); \ + t0 = _mm_xor_si128(_mm256_extracti128_si256(x_##A, 1), \ + _mm_loadu_si128((const __m128i*) (m + 256))); \ + _mm_storeu_si128((__m128i*) (c + 256), t0); \ + t1 = _mm_xor_si128(_mm256_extracti128_si256(x_##B, 1), \ + _mm_loadu_si128((const __m128i*) (m + 320))); \ + _mm_storeu_si128((__m128i*) (c + 320), t1); \ + t2 = _mm_xor_si128(_mm256_extracti128_si256(x_##C, 1), \ + _mm_loadu_si128((const __m128i*) (m + 384))); \ + _mm_storeu_si128((__m128i*) (c + 384), t2); \ + t3 = _mm_xor_si128(_mm256_extracti128_si256(x_##D, 1), \ + _mm_loadu_si128((const __m128i*) (m + 448))); \ + _mm_storeu_si128((__m128i*) (c + 448), t3); \ + } + +#define ONEQUAD(A, B, C, D) ONEQUAD_TRANSPOSE(A, B, C, D) + +#define ONEQUAD_UNPCK(A, B, C, D) \ + { \ + x_##A = _mm256_add_epi32(x_##A, orig##A); \ + x_##B = _mm256_add_epi32(x_##B, orig##B); \ + x_##C = _mm256_add_epi32(x_##C, orig##C); \ + x_##D = _mm256_add_epi32(x_##D, orig##D); \ + t_##A = _mm256_unpacklo_epi32(x_##A, x_##B); \ + t_##B = _mm256_unpacklo_epi32(x_##C, x_##D); \ + t_##C = _mm256_unpackhi_epi32(x_##A, x_##B); \ + t_##D = _mm256_unpackhi_epi32(x_##C, x_##D); \ + x_##A = _mm256_unpacklo_epi64(t_##A, t_##B); \ + x_##B = _mm256_unpackhi_epi64(t_##A, t_##B); \ + x_##C = _mm256_unpacklo_epi64(t_##C, t_##D); \ + x_##D = _mm256_unpackhi_epi64(t_##C, t_##D); \ + } + +#define ONEOCTO(A, B, C, D, A2, B2, C2, D2) \ + { \ + ONEQUAD_UNPCK(A, B, C, D); \ + ONEQUAD_UNPCK(A2, B2, C2, D2); \ + t_##A = _mm256_permute2x128_si256(x_##A, x_##A2, 0x20); \ + t_##A2 = _mm256_permute2x128_si256(x_##A, x_##A2, 0x31); \ + t_##B = _mm256_permute2x128_si256(x_##B, x_##B2, 0x20); \ + t_##B2 = _mm256_permute2x128_si256(x_##B, x_##B2, 0x31); \ + t_##C = _mm256_permute2x128_si256(x_##C, x_##C2, 0x20); \ + t_##C2 = _mm256_permute2x128_si256(x_##C, x_##C2, 0x31); \ + t_##D = _mm256_permute2x128_si256(x_##D, x_##D2, 0x20); \ + t_##D2 = _mm256_permute2x128_si256(x_##D, x_##D2, 0x31); \ + t_##A = _mm256_xor_si256( \ + t_##A, _mm256_loadu_si256((const __m256i*) (m + 0))); \ + t_##B = _mm256_xor_si256( \ + t_##B, _mm256_loadu_si256((const __m256i*) (m + 64))); \ + t_##C = _mm256_xor_si256( \ + t_##C, _mm256_loadu_si256((const __m256i*) (m + 128))); \ + t_##D = _mm256_xor_si256( \ + t_##D, _mm256_loadu_si256((const __m256i*) (m + 192))); \ + t_##A2 = _mm256_xor_si256( \ + t_##A2, _mm256_loadu_si256((const __m256i*) (m + 256))); \ + t_##B2 = _mm256_xor_si256( \ + t_##B2, _mm256_loadu_si256((const __m256i*) (m + 320))); \ + t_##C2 = _mm256_xor_si256( \ + t_##C2, _mm256_loadu_si256((const __m256i*) (m + 384))); \ + t_##D2 = _mm256_xor_si256( \ + t_##D2, _mm256_loadu_si256((const __m256i*) (m + 448))); \ + _mm256_storeu_si256((__m256i*) (c + 0), t_##A); \ + _mm256_storeu_si256((__m256i*) (c + 64), t_##B); \ + _mm256_storeu_si256((__m256i*) (c + 128), t_##C); \ + _mm256_storeu_si256((__m256i*) (c + 192), t_##D); \ + _mm256_storeu_si256((__m256i*) (c + 256), t_##A2); \ + _mm256_storeu_si256((__m256i*) (c + 320), t_##B2); \ + _mm256_storeu_si256((__m256i*) (c + 384), t_##C2); \ + _mm256_storeu_si256((__m256i*) (c + 448), t_##D2); \ + } + + ONEOCTO(0, 1, 2, 3, 4, 5, 6, 7); + m += 32; + c += 32; + ONEOCTO(8, 9, 10, 11, 12, 13, 14, 15); + m -= 32; + c -= 32; + +#undef ONEQUAD +#undef ONEQUAD_TRANSPOSE +#undef ONEQUAD_UNPCK +#undef ONEOCTO + + bytes -= 512; + c += 512; + m += 512; + } +} +#undef VEC8_ROT +#undef VEC8_QUARTERROUND +#undef VEC8_QUARTERROUND_NAIVE +#undef VEC8_QUARTERROUND_SHUFFLE +#undef VEC8_QUARTERROUND_SHUFFLE2 +#undef VEC8_LINE1 +#undef VEC8_LINE2 +#undef VEC8_LINE3 +#undef VEC8_LINE4 +#undef VEC8_ROUND +#undef VEC8_ROUND_SEQ +#undef VEC8_ROUND_HALF +#undef VEC8_ROUND_HALFANDHALF +/*** End of # include "u8.h" ***/ + +/* # include "u4.h" */ +/*** Begin of # include "u4.h" ***/ + +#define VEC4_ROT(A, IMM) \ + _mm_or_si128(_mm_slli_epi32(A, IMM), _mm_srli_epi32(A, (32 - IMM))) + +/* same, but replace 2 of the shift/shift/or "rotation" by byte shuffles (8 & + * 16) (better) */ +#define VEC4_QUARTERROUND_SHUFFLE(A, B, C, D) \ + x_##A = _mm_add_epi32(x_##A, x_##B); \ + t_##A = _mm_xor_si128(x_##D, x_##A); \ + x_##D = _mm_shuffle_epi8(t_##A, rot16); \ + x_##C = _mm_add_epi32(x_##C, x_##D); \ + t_##C = _mm_xor_si128(x_##B, x_##C); \ + x_##B = VEC4_ROT(t_##C, 12); \ + x_##A = _mm_add_epi32(x_##A, x_##B); \ + t_##A = _mm_xor_si128(x_##D, x_##A); \ + x_##D = _mm_shuffle_epi8(t_##A, rot8); \ + x_##C = _mm_add_epi32(x_##C, x_##D); \ + t_##C = _mm_xor_si128(x_##B, x_##C); \ + x_##B = VEC4_ROT(t_##C, 7) + +#define VEC4_QUARTERROUND(A, B, C, D) VEC4_QUARTERROUND_SHUFFLE(A, B, C, D) + +if (bytes >= 256) { + /* constant for shuffling bytes (replacing multiple-of-8 rotates) */ + __m128i rot16 = + _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + __m128i rot8 = + _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3); + + __m128i x_0 = _mm_set1_epi32(x[0]); + __m128i x_1 = _mm_set1_epi32(x[1]); + __m128i x_2 = _mm_set1_epi32(x[2]); + __m128i x_3 = _mm_set1_epi32(x[3]); + __m128i x_4 = _mm_set1_epi32(x[4]); + __m128i x_5 = _mm_set1_epi32(x[5]); + __m128i x_6 = _mm_set1_epi32(x[6]); + __m128i x_7 = _mm_set1_epi32(x[7]); + __m128i x_8 = _mm_set1_epi32(x[8]); + __m128i x_9 = _mm_set1_epi32(x[9]); + __m128i x_10 = _mm_set1_epi32(x[10]); + __m128i x_11 = _mm_set1_epi32(x[11]); + __m128i x_12; + __m128i x_13; + __m128i x_14 = _mm_set1_epi32(x[14]); + __m128i x_15 = _mm_set1_epi32(x[15]); + __m128i orig0 = x_0; + __m128i orig1 = x_1; + __m128i orig2 = x_2; + __m128i orig3 = x_3; + __m128i orig4 = x_4; + __m128i orig5 = x_5; + __m128i orig6 = x_6; + __m128i orig7 = x_7; + __m128i orig8 = x_8; + __m128i orig9 = x_9; + __m128i orig10 = x_10; + __m128i orig11 = x_11; + __m128i orig12; + __m128i orig13; + __m128i orig14 = x_14; + __m128i orig15 = x_15; + __m128i t_0, t_1, t_2, t_3, t_4, t_5, t_6, t_7, t_8, t_9, t_10, t_11, t_12, + t_13, t_14, t_15; + + uint32_t in12, in13; + int i; + + while (bytes >= 256) { + const __m128i addv12 = _mm_set_epi64x(1, 0); + const __m128i addv13 = _mm_set_epi64x(3, 2); + __m128i t12, t13; + uint64_t in1213; + + x_0 = orig0; + x_1 = orig1; + x_2 = orig2; + x_3 = orig3; + x_4 = orig4; + x_5 = orig5; + x_6 = orig6; + x_7 = orig7; + x_8 = orig8; + x_9 = orig9; + x_10 = orig10; + x_11 = orig11; + x_14 = orig14; + x_15 = orig15; + + in12 = x[12]; + in13 = x[13]; + in1213 = ((uint64_t) in12) | (((uint64_t) in13) << 32); + t12 = _mm_set1_epi64x(in1213); + t13 = _mm_set1_epi64x(in1213); + + x_12 = _mm_add_epi64(addv12, t12); + x_13 = _mm_add_epi64(addv13, t13); + + t12 = _mm_unpacklo_epi32(x_12, x_13); + t13 = _mm_unpackhi_epi32(x_12, x_13); + + x_12 = _mm_unpacklo_epi32(t12, t13); + x_13 = _mm_unpackhi_epi32(t12, t13); + + orig12 = x_12; + orig13 = x_13; + + in1213 += 4; + + x[12] = in1213 & 0xFFFFFFFF; + x[13] = (in1213 >> 32) & 0xFFFFFFFF; + + for (i = 0; i < DOLBEAU_ROUNDS; i += 2) { + VEC4_QUARTERROUND(0, 4, 8, 12); + VEC4_QUARTERROUND(1, 5, 9, 13); + VEC4_QUARTERROUND(2, 6, 10, 14); + VEC4_QUARTERROUND(3, 7, 11, 15); + VEC4_QUARTERROUND(0, 5, 10, 15); + VEC4_QUARTERROUND(1, 6, 11, 12); + VEC4_QUARTERROUND(2, 7, 8, 13); + VEC4_QUARTERROUND(3, 4, 9, 14); + } + +#define ONEQUAD_TRANSPOSE(A, B, C, D) \ + { \ + __m128i t0, t1, t2, t3; \ + \ + x_##A = _mm_add_epi32(x_##A, orig##A); \ + x_##B = _mm_add_epi32(x_##B, orig##B); \ + x_##C = _mm_add_epi32(x_##C, orig##C); \ + x_##D = _mm_add_epi32(x_##D, orig##D); \ + t_##A = _mm_unpacklo_epi32(x_##A, x_##B); \ + t_##B = _mm_unpacklo_epi32(x_##C, x_##D); \ + t_##C = _mm_unpackhi_epi32(x_##A, x_##B); \ + t_##D = _mm_unpackhi_epi32(x_##C, x_##D); \ + x_##A = _mm_unpacklo_epi64(t_##A, t_##B); \ + x_##B = _mm_unpackhi_epi64(t_##A, t_##B); \ + x_##C = _mm_unpacklo_epi64(t_##C, t_##D); \ + x_##D = _mm_unpackhi_epi64(t_##C, t_##D); \ + \ + t0 = _mm_xor_si128(x_##A, _mm_loadu_si128((const __m128i*) (m + 0))); \ + _mm_storeu_si128((__m128i*) (c + 0), t0); \ + t1 = _mm_xor_si128(x_##B, _mm_loadu_si128((const __m128i*) (m + 64))); \ + _mm_storeu_si128((__m128i*) (c + 64), t1); \ + t2 = \ + _mm_xor_si128(x_##C, _mm_loadu_si128((const __m128i*) (m + 128))); \ + _mm_storeu_si128((__m128i*) (c + 128), t2); \ + t3 = \ + _mm_xor_si128(x_##D, _mm_loadu_si128((const __m128i*) (m + 192))); \ + _mm_storeu_si128((__m128i*) (c + 192), t3); \ + } + +#define ONEQUAD(A, B, C, D) ONEQUAD_TRANSPOSE(A, B, C, D) + + ONEQUAD(0, 1, 2, 3); + m += 16; + c += 16; + ONEQUAD(4, 5, 6, 7); + m += 16; + c += 16; + ONEQUAD(8, 9, 10, 11); + m += 16; + c += 16; + ONEQUAD(12, 13, 14, 15); + m -= 48; + c -= 48; + +#undef ONEQUAD +#undef ONEQUAD_TRANSPOSE + + bytes -= 256; + c += 256; + m += 256; + } +} +#undef VEC4_ROT +#undef VEC4_QUARTERROUND +#undef VEC4_QUARTERROUND_SHUFFLE +/*** End of # include "u4.h" ***/ + +/* # include "u1.h" */ +/*** Begin of # include "u1.h" ***/ +while (bytes >= 64) { + __m128i x_0, x_1, x_2, x_3; + __m128i t_1; + const __m128i rot16 = + _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + const __m128i rot8 = + _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3); + + uint32_t in12; + uint32_t in13; + int i; + + x_0 = _mm_loadu_si128((const __m128i*) (x + 0)); + x_1 = _mm_loadu_si128((const __m128i*) (x + 4)); + x_2 = _mm_loadu_si128((const __m128i*) (x + 8)); + x_3 = _mm_loadu_si128((const __m128i*) (x + 12)); + + for (i = 0; i < DOLBEAU_ROUNDS; i += 2) { + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_3 = _mm_shuffle_epi8(x_3, rot16); + + x_2 = _mm_add_epi32(x_2, x_3); + x_1 = _mm_xor_si128(x_1, x_2); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 12); + t_1 = _mm_srli_epi32(t_1, 20); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_0 = _mm_shuffle_epi32(x_0, 0x93); + x_3 = _mm_shuffle_epi8(x_3, rot8); + + x_2 = _mm_add_epi32(x_2, x_3); + x_3 = _mm_shuffle_epi32(x_3, 0x4e); + x_1 = _mm_xor_si128(x_1, x_2); + x_2 = _mm_shuffle_epi32(x_2, 0x39); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 7); + t_1 = _mm_srli_epi32(t_1, 25); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_3 = _mm_shuffle_epi8(x_3, rot16); + + x_2 = _mm_add_epi32(x_2, x_3); + x_1 = _mm_xor_si128(x_1, x_2); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 12); + t_1 = _mm_srli_epi32(t_1, 20); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_0 = _mm_shuffle_epi32(x_0, 0x39); + x_3 = _mm_shuffle_epi8(x_3, rot8); + + x_2 = _mm_add_epi32(x_2, x_3); + x_3 = _mm_shuffle_epi32(x_3, 0x4e); + x_1 = _mm_xor_si128(x_1, x_2); + x_2 = _mm_shuffle_epi32(x_2, 0x93); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 7); + t_1 = _mm_srli_epi32(t_1, 25); + x_1 = _mm_xor_si128(x_1, t_1); + } + x_0 = _mm_add_epi32(x_0, _mm_loadu_si128((const __m128i*) (x + 0))); + x_1 = _mm_add_epi32(x_1, _mm_loadu_si128((const __m128i*) (x + 4))); + x_2 = _mm_add_epi32(x_2, _mm_loadu_si128((const __m128i*) (x + 8))); + x_3 = _mm_add_epi32(x_3, _mm_loadu_si128((const __m128i*) (x + 12))); + x_0 = _mm_xor_si128(x_0, _mm_loadu_si128((const __m128i*) (m + 0))); + x_1 = _mm_xor_si128(x_1, _mm_loadu_si128((const __m128i*) (m + 16))); + x_2 = _mm_xor_si128(x_2, _mm_loadu_si128((const __m128i*) (m + 32))); + x_3 = _mm_xor_si128(x_3, _mm_loadu_si128((const __m128i*) (m + 48))); + _mm_storeu_si128((__m128i*) (c + 0), x_0); + _mm_storeu_si128((__m128i*) (c + 16), x_1); + _mm_storeu_si128((__m128i*) (c + 32), x_2); + _mm_storeu_si128((__m128i*) (c + 48), x_3); + + in12 = x[12]; + in13 = x[13]; + in12++; + if (in12 == 0) { + in13++; + } + x[12] = in12; + x[13] = in13; + + bytes -= 64; + c += 64; + m += 64; +} +/*** End of # include "u1.h" ***/ + +/* # include "u0.h" */ +/*** Begin of # include "u0.h" ***/ +if (bytes > 0) { + __m128i x_0, x_1, x_2, x_3; + __m128i t_1; + const __m128i rot16 = + _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + const __m128i rot8 = + _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3); + uint8_t partialblock[64]; + + unsigned int i; + + x_0 = _mm_loadu_si128((const __m128i*) (x + 0)); + x_1 = _mm_loadu_si128((const __m128i*) (x + 4)); + x_2 = _mm_loadu_si128((const __m128i*) (x + 8)); + x_3 = _mm_loadu_si128((const __m128i*) (x + 12)); + + for (i = 0; i < DOLBEAU_ROUNDS; i += 2) { + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_3 = _mm_shuffle_epi8(x_3, rot16); + + x_2 = _mm_add_epi32(x_2, x_3); + x_1 = _mm_xor_si128(x_1, x_2); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 12); + t_1 = _mm_srli_epi32(t_1, 20); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_0 = _mm_shuffle_epi32(x_0, 0x93); + x_3 = _mm_shuffle_epi8(x_3, rot8); + + x_2 = _mm_add_epi32(x_2, x_3); + x_3 = _mm_shuffle_epi32(x_3, 0x4e); + x_1 = _mm_xor_si128(x_1, x_2); + x_2 = _mm_shuffle_epi32(x_2, 0x39); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 7); + t_1 = _mm_srli_epi32(t_1, 25); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_3 = _mm_shuffle_epi8(x_3, rot16); + + x_2 = _mm_add_epi32(x_2, x_3); + x_1 = _mm_xor_si128(x_1, x_2); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 12); + t_1 = _mm_srli_epi32(t_1, 20); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_0 = _mm_shuffle_epi32(x_0, 0x39); + x_3 = _mm_shuffle_epi8(x_3, rot8); + + x_2 = _mm_add_epi32(x_2, x_3); + x_3 = _mm_shuffle_epi32(x_3, 0x4e); + x_1 = _mm_xor_si128(x_1, x_2); + x_2 = _mm_shuffle_epi32(x_2, 0x93); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 7); + t_1 = _mm_srli_epi32(t_1, 25); + x_1 = _mm_xor_si128(x_1, t_1); + } + x_0 = _mm_add_epi32(x_0, _mm_loadu_si128((const __m128i*) (x + 0))); + x_1 = _mm_add_epi32(x_1, _mm_loadu_si128((const __m128i*) (x + 4))); + x_2 = _mm_add_epi32(x_2, _mm_loadu_si128((const __m128i*) (x + 8))); + x_3 = _mm_add_epi32(x_3, _mm_loadu_si128((const __m128i*) (x + 12))); + _mm_storeu_si128((__m128i*) (partialblock + 0), x_0); + _mm_storeu_si128((__m128i*) (partialblock + 16), x_1); + _mm_storeu_si128((__m128i*) (partialblock + 32), x_2); + _mm_storeu_si128((__m128i*) (partialblock + 48), x_3); + + for (i = 0; i < bytes; i++) { + c[i] = m[i] ^ partialblock[i]; + } + + sodium_memzero(partialblock, sizeof partialblock); +} +/*** End of # include "u0.h" ***/ + +} + +static int +dolbeau_avx512_stream_ref_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, uint64_t ic, + const unsigned char *k) +{ + struct chacha_ctx ctx; + uint8_t ic_bytes[8]; + uint32_t ic_high; + uint32_t ic_low; + + if (!mlen) { + return 0; + } + ic_high = (uint32_t) (ic >> 32); + ic_low = (uint32_t) ic; + SODIUM_STORE32_LE(&ic_bytes[0], ic_low); + SODIUM_STORE32_LE(&ic_bytes[4], ic_high); + dolbeau_avx512_chacha_keysetup(&ctx, k); + dolbeau_avx512_chacha_ivsetup(&ctx, n, ic_bytes); + dolbeau_avx512_chacha20_encrypt_bytes(&ctx, m, c, mlen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +static int +dolbeau_avx512_stream_ietf_ext_ref_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + uint32_t ic, const unsigned char *k) +{ + struct chacha_ctx ctx; + uint8_t ic_bytes[4]; + + if (!mlen) { + return 0; + } + SODIUM_STORE32_LE(ic_bytes, ic); + dolbeau_avx512_chacha_keysetup(&ctx, k); + dolbeau_avx512_chacha_ietf_ivsetup(&ctx, n, ic_bytes); + dolbeau_avx512_chacha20_encrypt_bytes(&ctx, m, c, mlen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +struct crypto_stream_chacha20_implementation + crypto_stream_chacha20_dolbeau_avx512_implementation = { + .stream_xor_ic = dolbeau_avx512_stream_ref_xor_ic, + .stream_ietf_ext_xor_ic = dolbeau_avx512_stream_ietf_ext_ref_xor_ic + }; + +# ifdef __clang__ +# pragma clang attribute pop +# endif + +#endif +/*** End of # include "dolbeau/chacha20_dolbeau-avx512.c" ***/ + +#endif +#elif defined(SQLITE3MC_TARGET_ARM64) && defined(__ARM_NEON) +/* # include "dolbeau/chacha20_dolbeau-neon.c" */ +/*** Begin of # include "dolbeau/chacha20_dolbeau-neon.c" ***/ + +#include +#include +#include + +/* #include "../crypto_stream_chacha20.h" */ + +/* #include "../private/common.h" */ + + +#if defined(SQLITE3MC_TARGET_ARM) + +# include + +/* # include "../stream_chacha20.h" */ + +/* # include "chacha20_dolbeau-neon.h" */ +/*** Begin of # include "chacha20_dolbeau-neon.h" ***/ + +#include + +/* #include "../stream_chacha20.h" */ + +/* #include "../crypto_stream_chacha20.h" */ + + +extern struct crypto_stream_chacha20_implementation + crypto_stream_chacha20_dolbeau_neon_implementation; +/*** End of # include "chacha20_dolbeau-neon.h" ***/ + + +#ifdef DOLBEAU_ROUNDS +# undef DOLBEAU_ROUNDS +# define DOLBEAU_ROUNDS 20 +#else +# define DOLBEAU_ROUNDS 20 +#endif + +# define MIN_VECTOR_BYTES 128 + +static inline uint32x4_t +rotl32_16_neon(uint32x4_t x) +{ + return vreinterpretq_u32_u16(vrev32q_u16(vreinterpretq_u16_u32(x))); +} + +static inline uint32x4_t +rotl32_12_neon(uint32x4_t x) +{ + return vsriq_n_u32(vshlq_n_u32(x, 12), x, 20); +} + +static inline uint32x4_t +rotl32_8_neon(uint32x4_t x) +{ + static const uint8_t rot8_tbl[16] = { + 3, 0, 1, 2, 7, 4, 5, 6, + 11, 8, 9, 10, 15, 12, 13, 14 + }; + const uint8x16_t tbl = vld1q_u8(rot8_tbl); + + return vreinterpretq_u32_u8(vqtbl1q_u8(vreinterpretq_u8_u32(x), tbl)); +} + +static inline uint32x4_t +rotl32_7_neon(uint32x4_t x) +{ + return vsriq_n_u32(vshlq_n_u32(x, 7), x, 25); +} + +static void +dolbeau_neon_chacha_keysetup(chacha_ctx *ctx, const uint8_t *k) +{ + ctx->input[0] = 0x61707865; + ctx->input[1] = 0x3320646e; + ctx->input[2] = 0x79622d32; + ctx->input[3] = 0x6b206574; + ctx->input[4] = SODIUM_LOAD32_LE(k + 0); + ctx->input[5] = SODIUM_LOAD32_LE(k + 4); + ctx->input[6] = SODIUM_LOAD32_LE(k + 8); + ctx->input[7] = SODIUM_LOAD32_LE(k + 12); + ctx->input[8] = SODIUM_LOAD32_LE(k + 16); + ctx->input[9] = SODIUM_LOAD32_LE(k + 20); + ctx->input[10] = SODIUM_LOAD32_LE(k + 24); + ctx->input[11] = SODIUM_LOAD32_LE(k + 28); +} + +static void +dolbeau_neon_chacha_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter) +{ + ctx->input[12] = counter == NULL ? 0 : SODIUM_LOAD32_LE(counter + 0); + ctx->input[13] = counter == NULL ? 0 : SODIUM_LOAD32_LE(counter + 4); + ctx->input[14] = SODIUM_LOAD32_LE(iv + 0); + ctx->input[15] = SODIUM_LOAD32_LE(iv + 4); +} + +static void +dolbeau_neon_chacha_ietf_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter) +{ + ctx->input[12] = counter == NULL ? 0 : SODIUM_LOAD32_LE(counter); + ctx->input[13] = SODIUM_LOAD32_LE(iv + 0); + ctx->input[14] = SODIUM_LOAD32_LE(iv + 4); + ctx->input[15] = SODIUM_LOAD32_LE(iv + 8); +} + +static void +dolbeau_neon_chacha20_encrypt_bytes(chacha_ctx *ctx, const uint8_t *m, uint8_t *c, + unsigned long long bytes) +{ + uint32_t * const x = &ctx->input[0]; + + if (!bytes) { + return; /* LCOV_EXCL_LINE */ + } +/* # include "u4-neon.h" */ +/*** Begin of # include "u4-neon.h" ***/ + +#define VEC4_QUARTERROUND(A, B, C, D) \ + x_##A = vaddq_u32(x_##A, x_##B); \ + t_##A = veorq_u32(x_##D, x_##A); \ + x_##D = rotl32_16_neon(t_##A); \ + x_##C = vaddq_u32(x_##C, x_##D); \ + t_##C = veorq_u32(x_##B, x_##C); \ + x_##B = rotl32_12_neon(t_##C); \ + x_##A = vaddq_u32(x_##A, x_##B); \ + t_##A = veorq_u32(x_##D, x_##A); \ + x_##D = rotl32_8_neon(t_##A); \ + x_##C = vaddq_u32(x_##C, x_##D); \ + t_##C = veorq_u32(x_##B, x_##C); \ + x_##B = rotl32_7_neon(t_##C) + +if (bytes >= 256) { + uint32x4_t x_0 = vdupq_n_u32(x[0]); + uint32x4_t x_1 = vdupq_n_u32(x[1]); + uint32x4_t x_2 = vdupq_n_u32(x[2]); + uint32x4_t x_3 = vdupq_n_u32(x[3]); + uint32x4_t x_4 = vdupq_n_u32(x[4]); + uint32x4_t x_5 = vdupq_n_u32(x[5]); + uint32x4_t x_6 = vdupq_n_u32(x[6]); + uint32x4_t x_7 = vdupq_n_u32(x[7]); + uint32x4_t x_8 = vdupq_n_u32(x[8]); + uint32x4_t x_9 = vdupq_n_u32(x[9]); + uint32x4_t x_10 = vdupq_n_u32(x[10]); + uint32x4_t x_11 = vdupq_n_u32(x[11]); + uint32x4_t x_12; + uint32x4_t x_13; + uint32x4_t x_14 = vdupq_n_u32(x[14]); + uint32x4_t x_15 = vdupq_n_u32(x[15]); + uint32x4_t orig0 = x_0; + uint32x4_t orig1 = x_1; + uint32x4_t orig2 = x_2; + uint32x4_t orig3 = x_3; + uint32x4_t orig4 = x_4; + uint32x4_t orig5 = x_5; + uint32x4_t orig6 = x_6; + uint32x4_t orig7 = x_7; + uint32x4_t orig8 = x_8; + uint32x4_t orig9 = x_9; + uint32x4_t orig10 = x_10; + uint32x4_t orig11 = x_11; + uint32x4_t orig12; + uint32x4_t orig13; + uint32x4_t orig14 = x_14; + uint32x4_t orig15 = x_15; + uint32x4_t t_0, t_1, t_2, t_3, t_4, t_5, t_6, t_7, t_8, t_9, t_10, t_11, + t_12, t_13, t_14, t_15; + + uint32_t in12, in13; + int i; + + while (bytes >= 256) { + static const uint64_t addv12_tbl[2] = { 0, 1 }; + static const uint64_t addv13_tbl[2] = { 2, 3 }; + uint64x2_t t12, t13; + uint64_t in1213; + + x_0 = orig0; + x_1 = orig1; + x_2 = orig2; + x_3 = orig3; + x_4 = orig4; + x_5 = orig5; + x_6 = orig6; + x_7 = orig7; + x_8 = orig8; + x_9 = orig9; + x_10 = orig10; + x_11 = orig11; + x_14 = orig14; + x_15 = orig15; + + in12 = x[12]; + in13 = x[13]; + in1213 = ((uint64_t) in12) | (((uint64_t) in13) << 32); + + t12 = vaddq_u64(vld1q_u64(addv12_tbl), vdupq_n_u64(in1213)); + t13 = vaddq_u64(vld1q_u64(addv13_tbl), vdupq_n_u64(in1213)); + + x_12 = vuzp1q_u32(vreinterpretq_u32_u64(t12), + vreinterpretq_u32_u64(t13)); + x_13 = vuzp2q_u32(vreinterpretq_u32_u64(t12), + vreinterpretq_u32_u64(t13)); + + orig12 = x_12; + orig13 = x_13; + + in1213 += 4; + + x[12] = in1213 & 0xFFFFFFFF; + x[13] = (in1213 >> 32) & 0xFFFFFFFF; + + for (i = 0; i < DOLBEAU_ROUNDS; i += 2) { + VEC4_QUARTERROUND(0, 4, 8, 12); + VEC4_QUARTERROUND(1, 5, 9, 13); + VEC4_QUARTERROUND(2, 6, 10, 14); + VEC4_QUARTERROUND(3, 7, 11, 15); + VEC4_QUARTERROUND(0, 5, 10, 15); + VEC4_QUARTERROUND(1, 6, 11, 12); + VEC4_QUARTERROUND(2, 7, 8, 13); + VEC4_QUARTERROUND(3, 4, 9, 14); + } + +#define ONEQUAD_TRANSPOSE(A, B, C, D) \ + { \ + uint32x4_t t0, t1, t2, t3; \ + \ + x_##A = vaddq_u32(x_##A, orig##A); \ + x_##B = vaddq_u32(x_##B, orig##B); \ + x_##C = vaddq_u32(x_##C, orig##C); \ + x_##D = vaddq_u32(x_##D, orig##D); \ + t_##A = vtrn1q_u32(x_##A, x_##B); \ + t_##B = vtrn2q_u32(x_##A, x_##B); \ + t_##C = vtrn1q_u32(x_##C, x_##D); \ + t_##D = vtrn2q_u32(x_##C, x_##D); \ + x_##A = vreinterpretq_u32_u64( \ + vtrn1q_u64(vreinterpretq_u64_u32(t_##A), \ + vreinterpretq_u64_u32(t_##C))); \ + x_##B = vreinterpretq_u32_u64( \ + vtrn1q_u64(vreinterpretq_u64_u32(t_##B), \ + vreinterpretq_u64_u32(t_##D))); \ + x_##C = vreinterpretq_u32_u64( \ + vtrn2q_u64(vreinterpretq_u64_u32(t_##A), \ + vreinterpretq_u64_u32(t_##C))); \ + x_##D = vreinterpretq_u32_u64( \ + vtrn2q_u64(vreinterpretq_u64_u32(t_##B), \ + vreinterpretq_u64_u32(t_##D))); \ + t0 = veorq_u32(x_##A, vreinterpretq_u32_u8(vld1q_u8(m + 0))); \ + vst1q_u8(c + 0, vreinterpretq_u8_u32(t0)); \ + t1 = veorq_u32(x_##B, vreinterpretq_u32_u8(vld1q_u8(m + 64))); \ + vst1q_u8(c + 64, vreinterpretq_u8_u32(t1)); \ + t2 = veorq_u32(x_##C, vreinterpretq_u32_u8(vld1q_u8(m + 128))); \ + vst1q_u8(c + 128, vreinterpretq_u8_u32(t2)); \ + t3 = veorq_u32(x_##D, vreinterpretq_u32_u8(vld1q_u8(m + 192))); \ + vst1q_u8(c + 192, vreinterpretq_u8_u32(t3)); \ + } + +#define ONEQUAD(A, B, C, D) ONEQUAD_TRANSPOSE(A, B, C, D) + + ONEQUAD(0, 1, 2, 3); + m += 16; + c += 16; + ONEQUAD(4, 5, 6, 7); + m += 16; + c += 16; + ONEQUAD(8, 9, 10, 11); + m += 16; + c += 16; + ONEQUAD(12, 13, 14, 15); + m -= 48; + c -= 48; + +#undef ONEQUAD +#undef ONEQUAD_TRANSPOSE + + bytes -= 256; + c += 256; + m += 256; + } +} +#undef VEC4_QUARTERROUND +/*** End of # include "u4-neon.h" ***/ + +/* # include "u2-neon.h" */ +/*** Begin of # include "u2-neon.h" ***/ + +#define VEC2_HALFROUND(P, E0, E2) \ + P##_0 = vaddq_u32(P##_0, P##_1); \ + P##_3 = veorq_u32(P##_3, P##_0); \ + P##_3 = rotl32_16_neon(P##_3); \ + P##_2 = vaddq_u32(P##_2, P##_3); \ + P##_1 = veorq_u32(P##_1, P##_2); \ + P##_1 = rotl32_12_neon(P##_1); \ + P##_0 = vaddq_u32(P##_0, P##_1); \ + P##_3 = veorq_u32(P##_3, P##_0); \ + P##_0 = vextq_u32(P##_0, P##_0, E0); \ + P##_3 = rotl32_8_neon(P##_3); \ + P##_2 = vaddq_u32(P##_2, P##_3); \ + P##_3 = vextq_u32(P##_3, P##_3, 2); \ + P##_1 = veorq_u32(P##_1, P##_2); \ + P##_2 = vextq_u32(P##_2, P##_2, E2); \ + P##_1 = rotl32_7_neon(P##_1) + +while (bytes >= 128) { + static const uint64_t addv_tbl[2] = { 1, 0 }; + + uint32x4_t orig0 = vld1q_u32(x + 0); + uint32x4_t orig1 = vld1q_u32(x + 4); + uint32x4_t orig2 = vld1q_u32(x + 8); + uint32x4_t orig3 = vld1q_u32(x + 12); + uint32x4_t orig3b = vreinterpretq_u32_u64(vaddq_u64( + vreinterpretq_u64_u32(orig3), vld1q_u64(addv_tbl))); + uint32x4_t x_0, x_1, x_2, x_3; + uint32x4_t y_0, y_1, y_2, y_3; + + uint64_t in1213; + int i; + + x_0 = orig0; + x_1 = orig1; + x_2 = orig2; + x_3 = orig3; + y_0 = orig0; + y_1 = orig1; + y_2 = orig2; + y_3 = orig3b; + + for (i = 0; i < DOLBEAU_ROUNDS; i += 2) { + VEC2_HALFROUND(x, 3, 1); + VEC2_HALFROUND(y, 3, 1); + VEC2_HALFROUND(x, 1, 3); + VEC2_HALFROUND(y, 1, 3); + } + x_0 = vaddq_u32(x_0, orig0); + x_1 = vaddq_u32(x_1, orig1); + x_2 = vaddq_u32(x_2, orig2); + x_3 = vaddq_u32(x_3, orig3); + y_0 = vaddq_u32(y_0, orig0); + y_1 = vaddq_u32(y_1, orig1); + y_2 = vaddq_u32(y_2, orig2); + y_3 = vaddq_u32(y_3, orig3b); + + x_0 = veorq_u32(x_0, vreinterpretq_u32_u8(vld1q_u8(m + 0))); + x_1 = veorq_u32(x_1, vreinterpretq_u32_u8(vld1q_u8(m + 16))); + x_2 = veorq_u32(x_2, vreinterpretq_u32_u8(vld1q_u8(m + 32))); + x_3 = veorq_u32(x_3, vreinterpretq_u32_u8(vld1q_u8(m + 48))); + y_0 = veorq_u32(y_0, vreinterpretq_u32_u8(vld1q_u8(m + 64))); + y_1 = veorq_u32(y_1, vreinterpretq_u32_u8(vld1q_u8(m + 80))); + y_2 = veorq_u32(y_2, vreinterpretq_u32_u8(vld1q_u8(m + 96))); + y_3 = veorq_u32(y_3, vreinterpretq_u32_u8(vld1q_u8(m + 112))); + + vst1q_u8(c + 0, vreinterpretq_u8_u32(x_0)); + vst1q_u8(c + 16, vreinterpretq_u8_u32(x_1)); + vst1q_u8(c + 32, vreinterpretq_u8_u32(x_2)); + vst1q_u8(c + 48, vreinterpretq_u8_u32(x_3)); + vst1q_u8(c + 64, vreinterpretq_u8_u32(y_0)); + vst1q_u8(c + 80, vreinterpretq_u8_u32(y_1)); + vst1q_u8(c + 96, vreinterpretq_u8_u32(y_2)); + vst1q_u8(c + 112, vreinterpretq_u8_u32(y_3)); + + in1213 = ((uint64_t) x[12]) | (((uint64_t) x[13]) << 32); + in1213 += 2; + + x[12] = (uint32_t) (in1213 & 0xFFFFFFFF); + x[13] = (uint32_t) (in1213 >> 32); + + bytes -= 128; + c += 128; + m += 128; +} +#undef VEC2_HALFROUND +/*** End of # include "u2-neon.h" ***/ + +/* # include "u1-neon.h" */ +/*** Begin of # include "u1-neon.h" ***/ +while (bytes >= 64) { + uint32x4_t x_0, x_1, x_2, x_3; + + uint32_t in12; + uint32_t in13; + int i; + + x_0 = vld1q_u32(x + 0); + x_1 = vld1q_u32(x + 4); + x_2 = vld1q_u32(x + 8); + x_3 = vld1q_u32(x + 12); + + for (i = 0; i < DOLBEAU_ROUNDS; i += 2) { + x_0 = vaddq_u32(x_0, x_1); + x_3 = veorq_u32(x_3, x_0); + x_3 = rotl32_16_neon(x_3); + + x_2 = vaddq_u32(x_2, x_3); + x_1 = veorq_u32(x_1, x_2); + x_1 = rotl32_12_neon(x_1); + + x_0 = vaddq_u32(x_0, x_1); + x_3 = veorq_u32(x_3, x_0); + x_0 = vextq_u32(x_0, x_0, 3); + x_3 = rotl32_8_neon(x_3); + + x_2 = vaddq_u32(x_2, x_3); + x_3 = vextq_u32(x_3, x_3, 2); + x_1 = veorq_u32(x_1, x_2); + x_2 = vextq_u32(x_2, x_2, 1); + x_1 = rotl32_7_neon(x_1); + + x_0 = vaddq_u32(x_0, x_1); + x_3 = veorq_u32(x_3, x_0); + x_3 = rotl32_16_neon(x_3); + + x_2 = vaddq_u32(x_2, x_3); + x_1 = veorq_u32(x_1, x_2); + x_1 = rotl32_12_neon(x_1); + + x_0 = vaddq_u32(x_0, x_1); + x_3 = veorq_u32(x_3, x_0); + x_0 = vextq_u32(x_0, x_0, 1); + x_3 = rotl32_8_neon(x_3); + + x_2 = vaddq_u32(x_2, x_3); + x_3 = vextq_u32(x_3, x_3, 2); + x_1 = veorq_u32(x_1, x_2); + x_2 = vextq_u32(x_2, x_2, 3); + x_1 = rotl32_7_neon(x_1); + } + x_0 = vaddq_u32(x_0, vld1q_u32(x + 0)); + x_1 = vaddq_u32(x_1, vld1q_u32(x + 4)); + x_2 = vaddq_u32(x_2, vld1q_u32(x + 8)); + x_3 = vaddq_u32(x_3, vld1q_u32(x + 12)); + + x_0 = veorq_u32(x_0, vreinterpretq_u32_u8(vld1q_u8(m + 0))); + x_1 = veorq_u32(x_1, vreinterpretq_u32_u8(vld1q_u8(m + 16))); + x_2 = veorq_u32(x_2, vreinterpretq_u32_u8(vld1q_u8(m + 32))); + x_3 = veorq_u32(x_3, vreinterpretq_u32_u8(vld1q_u8(m + 48))); + + vst1q_u8(c + 0, vreinterpretq_u8_u32(x_0)); + vst1q_u8(c + 16, vreinterpretq_u8_u32(x_1)); + vst1q_u8(c + 32, vreinterpretq_u8_u32(x_2)); + vst1q_u8(c + 48, vreinterpretq_u8_u32(x_3)); + + in12 = x[12]; + in13 = x[13]; + in12++; + if (in12 == 0) { + in13++; + } + x[12] = in12; + x[13] = in13; + + bytes -= 64; + c += 64; + m += 64; +} +/*** End of # include "u1-neon.h" ***/ + +/* # include "u0-neon.h" */ +/*** Begin of # include "u0-neon.h" ***/ +if (bytes > 0) { + uint32x4_t x_0, x_1, x_2, x_3; + uint8_t partialblock[64]; + + unsigned int i; + + x_0 = vld1q_u32(x + 0); + x_1 = vld1q_u32(x + 4); + x_2 = vld1q_u32(x + 8); + x_3 = vld1q_u32(x + 12); + + for (i = 0; i < DOLBEAU_ROUNDS; i += 2) { + x_0 = vaddq_u32(x_0, x_1); + x_3 = veorq_u32(x_3, x_0); + x_3 = rotl32_16_neon(x_3); + + x_2 = vaddq_u32(x_2, x_3); + x_1 = veorq_u32(x_1, x_2); + x_1 = rotl32_12_neon(x_1); + + x_0 = vaddq_u32(x_0, x_1); + x_3 = veorq_u32(x_3, x_0); + x_0 = vextq_u32(x_0, x_0, 3); + x_3 = rotl32_8_neon(x_3); + + x_2 = vaddq_u32(x_2, x_3); + x_3 = vextq_u32(x_3, x_3, 2); + x_1 = veorq_u32(x_1, x_2); + x_2 = vextq_u32(x_2, x_2, 1); + x_1 = rotl32_7_neon(x_1); + + x_0 = vaddq_u32(x_0, x_1); + x_3 = veorq_u32(x_3, x_0); + x_3 = rotl32_16_neon(x_3); + + x_2 = vaddq_u32(x_2, x_3); + x_1 = veorq_u32(x_1, x_2); + x_1 = rotl32_12_neon(x_1); + + x_0 = vaddq_u32(x_0, x_1); + x_3 = veorq_u32(x_3, x_0); + x_0 = vextq_u32(x_0, x_0, 1); + x_3 = rotl32_8_neon(x_3); + + x_2 = vaddq_u32(x_2, x_3); + x_3 = vextq_u32(x_3, x_3, 2); + x_1 = veorq_u32(x_1, x_2); + x_2 = vextq_u32(x_2, x_2, 3); + x_1 = rotl32_7_neon(x_1); + } + x_0 = vaddq_u32(x_0, vld1q_u32(x + 0)); + x_1 = vaddq_u32(x_1, vld1q_u32(x + 4)); + x_2 = vaddq_u32(x_2, vld1q_u32(x + 8)); + x_3 = vaddq_u32(x_3, vld1q_u32(x + 12)); + + vst1q_u8(partialblock + 0, vreinterpretq_u8_u32(x_0)); + vst1q_u8(partialblock + 16, vreinterpretq_u8_u32(x_1)); + vst1q_u8(partialblock + 32, vreinterpretq_u8_u32(x_2)); + vst1q_u8(partialblock + 48, vreinterpretq_u8_u32(x_3)); + + for (i = 0; i < bytes; i++) { + c[i] = m[i] ^ partialblock[i]; + } + + sodium_memzero(partialblock, sizeof partialblock); +} +/*** End of # include "u0-neon.h" ***/ + +} + +static int +dolbeau_neon_stream_neon_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + uint64_t ic, const unsigned char *k) +{ + struct chacha_ctx ctx; + uint8_t ic_bytes[8]; + uint32_t ic_high; + uint32_t ic_low; + + if (mlen < MIN_VECTOR_BYTES) { + return crypto_stream_chacha20_ref_implementation.stream_xor_ic( + c, m, mlen, n, ic, k); + } + ic_high = (uint32_t) (ic >> 32); + ic_low = (uint32_t) ic; + SODIUM_STORE32_LE(&ic_bytes[0], ic_low); + SODIUM_STORE32_LE(&ic_bytes[4], ic_high); + dolbeau_neon_chacha_keysetup(&ctx, k); + dolbeau_neon_chacha_ivsetup(&ctx, n, ic_bytes); + dolbeau_neon_chacha20_encrypt_bytes(&ctx, m, c, mlen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +static int +dolbeau_neon_stream_ietf_ext_neon_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + uint32_t ic, const unsigned char *k) +{ + struct chacha_ctx ctx; + uint8_t ic_bytes[4]; + + if (mlen < MIN_VECTOR_BYTES) { + return crypto_stream_chacha20_ref_implementation.stream_ietf_ext_xor_ic( + c, m, mlen, n, ic, k); + } + SODIUM_STORE32_LE(ic_bytes, ic); + dolbeau_neon_chacha_keysetup(&ctx, k); + dolbeau_neon_chacha_ietf_ivsetup(&ctx, n, ic_bytes); + dolbeau_neon_chacha20_encrypt_bytes(&ctx, m, c, mlen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +struct crypto_stream_chacha20_implementation + crypto_stream_chacha20_dolbeau_neon_implementation = { + .stream_xor_ic = dolbeau_neon_stream_neon_xor_ic, + .stream_ietf_ext_xor_ic = dolbeau_neon_stream_ietf_ext_neon_xor_ic + }; + +#endif +/*** End of # include "dolbeau/chacha20_dolbeau-neon.c" ***/ + +#endif + +#if defined(__GNUC__) +# pragma GCC pop_options +#endif + +static const crypto_stream_chacha20_implementation* sodium_chacha20_implementation = NULL; + +int +crypto_stream_chacha20_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint64_t ic, + const unsigned char *k) +{ + if (mlen > crypto_stream_chacha20_MESSAGEBYTES_MAX) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } + return sodium_chacha20_implementation->stream_xor_ic(c, m, mlen, n, ic, k); +} + +int +crypto_stream_chacha20_ietf_ext_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint32_t ic, + const unsigned char *k) +{ + if (mlen > crypto_stream_chacha20_MESSAGEBYTES_MAX) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } + return sodium_chacha20_implementation->stream_ietf_ext_xor_ic(c, m, mlen, n, ic, k); +} + +int +crypto_stream_chacha20_ietf_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint32_t ic, + const unsigned char *k) +{ + if ((unsigned long long) ic > + (64ULL * (1ULL << 32)) / 64ULL - (mlen + 63ULL) / 64ULL) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } + return crypto_stream_chacha20_ietf_ext_xor_ic(c, m, mlen, n, ic, k); +} + +#define SQLITE3MC_CHACHA20_HWACCL_UNKNOWN -1 +#define SQLITE3MC_CHACHA20_HWACCL_OFF 0 + +/* X86 options */ +#define SQLITE3MC_CHACHA20_HWACCL_SSSE3 1 +#define SQLITE3MC_CHACHA20_HWACCL_AVX2 2 +#define SQLITE3MC_CHACHA20_HWACCL_AVX512 3 + +/* ARM options */ +#define SQLITE3MC_CHACHA20_HWACCL_NEON 4 + +#define SQLITE3MC_CHACHA20_HWACCL_AUTO 5 +#define SQLITE3MC_CHACHA20_HWACCL_MAX 6 + +/* 0 1 2 3 4 5 6 */ +static char* gChaCha20HwAccelOptions[] = { "off", "ssse3", "avx2", "avx512f", "neon", "auto", "max" }; +static int gChaCha20HwAccelRequest = SQLITE3MC_CHACHA20_HWACCL_AUTO; +static int gChaCha20HwAccelSelected = SQLITE3MC_CHACHA20_HWACCL_UNKNOWN; + +/* +** The following constants define the range of valid options per hardware family +** +** gChaCha20HwAccelMin specifies the minimal allowed option in the range. +** gChaCha20HwAccelMax specifies the maximal allowed option in the range. +** +** gChaCha20HwAccelAuto specifies the default value in the range. +** This constant allows to exclude experimental options. +** For example, the AVX512F implementation is currently experimental +** and not yet included in official releases of libsodium. +** If the status in libsodium changes in the future, the value of this constant +** may be changed accordingly. However, the option AVX512F can be chosen explicitly +** at the user's discretion. The same is true for the NEON option on ARM. +*/ + +#if defined(SQLITE3MC_TARGET_X86) +static int gChaCha20HwAccelMin = SQLITE3MC_CHACHA20_HWACCL_SSSE3; +static int gChaCha20HwAccelMax = SQLITE3MC_CHACHA20_HWACCL_AVX512; +static int gChaCha20HwAccelAuto = SQLITE3MC_CHACHA20_HWACCL_AVX2; +#elif defined(SQLITE3MC_TARGET_ARM) +static int gChaCha20HwAccelMin = SQLITE3MC_CHACHA20_HWACCL_NEON; +static int gChaCha20HwAccelMax = SQLITE3MC_CHACHA20_HWACCL_NEON; +static int gChaCha20HwAccelAuto = SQLITE3MC_CHACHA20_HWACCL_NEON; +#elif defined(SQLITE3MC_TARGET_WASM) +static int gChaCha20HwAccelMin = SQLITE3MC_CHACHA20_HWACCL_SSSE3; +static int gChaCha20HwAccelMax = SQLITE3MC_CHACHA20_HWACCL_SSSE3; +static int gChaCha20HwAccelAuto = SQLITE3MC_CHACHA20_HWACCL_SSSE3; +#else +static int gChaCha20HwAccelMin = SQLITE3MC_CHACHA20_HWACCL_OFF; +static int gChaCha20HwAccelMax = SQLITE3MC_CHACHA20_HWACCL_OFF; +static int gChaCha20HwAccelAuto = SQLITE3MC_CHACHA20_HWACCL_OFF; +#endif + +SODIUM_EXPORT int +sqlite3mcChaCha20HwAccelerated() +{ + int rc = 0; + if (gChaCha20HwAccelSelected == SQLITE3MC_CHACHA20_HWACCL_UNKNOWN) + { + gChaCha20HwAccelRequest = gChaCha20HwAccelAuto; + rc = crypto_stream_chacha20_pick_best_implementation(); + } + return gChaCha20HwAccelSelected > 0; +} + +SODIUM_EXPORT const char* +sqlite3mcChaCha20HwConfig(const char* option) +{ + int rc; + if (strlen(option) > 0) + { + /* Identify option */ + int optRequested = SQLITE3MC_CHACHA20_HWACCL_UNKNOWN; + int k; + for (k = SQLITE3MC_CHACHA20_HWACCL_OFF; k <= SQLITE3MC_CHACHA20_HWACCL_MAX; ++k) + { + if (sqlite3StrICmp(option, gChaCha20HwAccelOptions[k]) == 0) + { + optRequested = k; + break; + } + } + + int valid = (optRequested == SQLITE3MC_CHACHA20_HWACCL_OFF) || + (optRequested == SQLITE3MC_CHACHA20_HWACCL_AUTO) || + (optRequested == SQLITE3MC_CHACHA20_HWACCL_MAX) || + (optRequested >= gChaCha20HwAccelMin && optRequested <= gChaCha20HwAccelMax); + if (!valid) + return NULL; + + /* Reset current selected option, if necessary */ + if (optRequested != gChaCha20HwAccelSelected) + { + /* Reset selected option */ + if (optRequested == SQLITE3MC_CHACHA20_HWACCL_AUTO) + gChaCha20HwAccelRequest = gChaCha20HwAccelAuto; + else + gChaCha20HwAccelRequest = optRequested; + rc = crypto_stream_chacha20_pick_best_implementation(); + } + } + else if (gChaCha20HwAccelSelected == SQLITE3MC_CHACHA20_HWACCL_UNKNOWN) + { + gChaCha20HwAccelRequest = gChaCha20HwAccelAuto; + rc = crypto_stream_chacha20_pick_best_implementation(); + } + + /* Return current selected option */ + if (gChaCha20HwAccelSelected >= SQLITE3MC_CHACHA20_HWACCL_OFF && + gChaCha20HwAccelSelected <= SQLITE3MC_CHACHA20_HWACCL_AUTO) + return gChaCha20HwAccelOptions[gChaCha20HwAccelSelected]; + else + return NULL; +} + +SODIUM_EXPORT int +crypto_stream_chacha20_pick_best_implementation(void) +{ +#if defined(SQLITE3MC_TARGET_X86) + if (gChaCha20HwAccelRequest >= SQLITE3MC_CHACHA20_HWACCL_AVX512 && + sqlite3mcCpuFeatures() & SQLITE3MC_CPU_AVX512F) + { + sodium_chacha20_implementation = &crypto_stream_chacha20_dolbeau_avx512_implementation; + gChaCha20HwAccelSelected = SQLITE3MC_CHACHA20_HWACCL_AVX512; + return 0; + } + if (gChaCha20HwAccelRequest >= SQLITE3MC_CHACHA20_HWACCL_AVX2 && + sqlite3mcCpuFeatures() & SQLITE3MC_CPU_AVX2) + { + sodium_chacha20_implementation = &crypto_stream_chacha20_dolbeau_avx2_implementation; + gChaCha20HwAccelSelected = SQLITE3MC_CHACHA20_HWACCL_AVX2; + return 0; + } +#endif +#if defined(SQLITE3MC_TARGET_X86) || (defined(SQLITE3MC_TARGET_WASM) && defined(__wasm_simd128__) && defined(__SSSE3__)) + if (gChaCha20HwAccelRequest >= SQLITE3MC_CHACHA20_HWACCL_SSSE3 && + sqlite3mcCpuFeatures() & SQLITE3MC_CPU_SSSE3) + { + sodium_chacha20_implementation = &crypto_stream_chacha20_dolbeau_ssse3_implementation; + gChaCha20HwAccelSelected = SQLITE3MC_CHACHA20_HWACCL_SSSE3; + return 0; + } +#endif +#if defined(SQLITE3MC_TARGET_ARM64) && defined(__ARM_NEON) + if (gChaCha20HwAccelRequest >= SQLITE3MC_CHACHA20_HWACCL_NEON && + sqlite3mcCpuFeatures() & SQLITE3MC_CPU_NEON) + { + sodium_chacha20_implementation = &crypto_stream_chacha20_dolbeau_neon_implementation; + gChaCha20HwAccelSelected = SQLITE3MC_CHACHA20_HWACCL_NEON; + return 0; + } +#endif + sodium_chacha20_implementation = &crypto_stream_chacha20_ref_implementation; + gChaCha20HwAccelSelected = SQLITE3MC_CHACHA20_HWACCL_OFF; + + /* Signal that no implementation with hardware support available */ +#if 1 + /* In that case we use our own ChaCha20 implementation. */ + return -1; +#else + /* In that case use the libsodium ChaCha20 reference implementation. */ + return 0; +#endif +} +/*** End of #include "src/stream_chacha20.c" ***/ + +/* #include "src/onetimeauth_poly1305.c" */ +/*** Begin of #include "src/onetimeauth_poly1305.c" ***/ +/* #include "onetimeauth_poly1305.h" */ +/*** Begin of #include "onetimeauth_poly1305.h" ***/ + +#ifndef onetimeauth_poly1305_H +#define onetimeauth_poly1305_H + +typedef struct CRYPTO_ALIGN(16) crypto_onetimeauth_poly1305_state { + unsigned char opaque[256]; +} crypto_onetimeauth_poly1305_state; + +typedef struct crypto_onetimeauth_poly1305_implementation { + int (*onetimeauth)(unsigned char *out, const unsigned char *in, + unsigned long long inlen, const unsigned char *k); + int (*onetimeauth_init)(crypto_onetimeauth_poly1305_state *state, + const unsigned char * key); + int (*onetimeauth_update)(crypto_onetimeauth_poly1305_state *state, + const unsigned char * in, + unsigned long long inlen); + int (*onetimeauth_final)(crypto_onetimeauth_poly1305_state *state, + unsigned char * out); +} crypto_onetimeauth_poly1305_implementation; + +#endif +/*** End of #include "onetimeauth_poly1305.h" ***/ + +/* #include "private/common.h" */ + + +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) && !defined(HAVE_TI_MODE) + +#include + +typedef struct { + uint64_t lo; + uint64_t hi; +} uint128_t; + +static __forceinline uint128_t +u128_mul(uint64_t x, uint64_t y) +{ + uint128_t r; +#if defined(_M_X64) + r.lo = _umul128(x, y, &r.hi); +#else /* _M_ARM64 */ + r.hi = __umulh(x, y); + r.lo = x * y; +#endif + return r; +} + +static __forceinline uint64_t +addc64(uint64_t a, uint64_t b, uint64_t carry_in, uint64_t* carry_out) +{ + uint64_t sum = a + carry_in; + uint64_t c1 = (sum < a); + sum += b; + uint64_t c2 = (sum < b); + *carry_out = c1 | c2; + return sum; +} + +static __forceinline uint128_t +u128_add(uint128_t a, uint128_t b) +{ + uint128_t r; + uint64_t carry; + r.lo = addc64(a.lo, b.lo, 0, &carry); + r.hi = addc64(a.hi, b.hi, carry, &carry); + return r; +} + +static __forceinline uint128_t +u128_addlo(uint128_t a, uint64_t b) +{ + uint128_t r; + uint64_t carry; + r.lo = addc64(a.lo, b, 0, &carry); + r.hi = addc64(a.hi, 0, carry, &carry); + return r; +} + +static __forceinline uint64_t +u128_lo(uint128_t v) { return v.lo; } + +static __forceinline uint64_t +u128_shr(uint128_t v, int shift) +{ + if (shift == 0) return v.lo; + if (shift < 64) return (v.lo >> shift) | (v.hi << (64 - shift)); + return v.hi >> (shift - 64); +} + +#define SODIUM_MUL(out, x, y) out = u128_mul((uint64_t) (x), (uint64_t) (y)) +#define SODIUM_ADD(out, in) out = u128_add((out), (in)) +#define SODIUM_ADDLO(out, in) out = u128_addlo((out), (uint64_t) (in)) +#define SODIUM_SHR(in, shift) u128_shr((in), (shift)) +#define SODIUM_LO(in) u128_lo(in) + +#define SQLITE3MC_POLY1305_HAVE_128BIT 1 + +#endif + +/* #include "donna/poly1305_donna.c" */ +/*** Begin of #include "donna/poly1305_donna.c" ***/ + +/* #include "poly1305_donna.h" */ +/*** Begin of #include "poly1305_donna.h" ***/ +#ifndef poly1305_donna_H +#define poly1305_donna_H + +#include + +/* #include "../onetimeauth_poly1305.h" */ + + +extern struct crypto_onetimeauth_poly1305_implementation + crypto_onetimeauth_poly1305_donna_implementation; + +#endif /* poly1305_donna_H */ +/*** End of #include "poly1305_donna.h" ***/ + +/* #include "../private/common.h" */ + + +#if defined(HAVE_TI_MODE) || defined(SQLITE3MC_POLY1305_HAVE_128BIT) +/* #include "poly1305_donna64.h" */ +/*** Begin of #include "poly1305_donna64.h" ***/ +/* + poly1305 implementation using 64 bit * 64 bit = 128 bit multiplication + and 128 bit addition +*/ + +/* #include "../private/common.h" */ + + +#if !defined(_MSC_VER) +#define SODIUM_MUL(out, x, y) out = ((uint128_t) x * y) +#define SODIUM_ADD(out, in) out += in +#define SODIUM_ADDLO(out, in) out += in +#define SODIUM_SHR(in, shift) (unsigned long long) (in >> (shift)) +#define SODIUM_LO(in) (unsigned long long) (in) +#endif + +#if defined(_MSC_VER) +# define POLY1305_NOINLINE __declspec(noinline) +#elif defined(__clang__) || defined(__GNUC__) +# define POLY1305_NOINLINE __attribute__((noinline)) +#else +# define POLY1305_NOINLINE +#endif + +#define poly1305_block_size 16 + +/* 17 + sizeof(unsigned long long) + 8*sizeof(unsigned long long) */ +typedef struct donna_poly1305_state_internal_t { + unsigned long long r[3]; + unsigned long long h[3]; + unsigned long long pad[2]; + unsigned long long leftover; + unsigned char buffer[poly1305_block_size]; + unsigned char final; +} donna_poly1305_state_internal_t; + +static void +donna_poly1305_init(donna_poly1305_state_internal_t *st, const unsigned char key[32]) +{ + unsigned long long t0, t1; + + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + t0 = SODIUM_LOAD64_LE(&key[0]); + t1 = SODIUM_LOAD64_LE(&key[8]); + + /* wiped after finalization */ + st->r[0] = (t0) & 0xffc0fffffff; + st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff; + st->r[2] = ((t1 >> 24)) & 0x00ffffffc0f; + + /* h = 0 */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + + /* save pad for later */ + st->pad[0] = SODIUM_LOAD64_LE(&key[16]); + st->pad[1] = SODIUM_LOAD64_LE(&key[24]); + + st->leftover = 0; + st->final = 0; +} + +static void +donna_poly1305_blocks(donna_poly1305_state_internal_t *st, const unsigned char *m, + unsigned long long bytes) +{ + const unsigned long long hibit = + (st->final) ? 0ULL : (1ULL << 40); /* 1 << 128 */ + unsigned long long r0, r1, r2; + unsigned long long s1, s2; + unsigned long long h0, h1, h2; + unsigned long long c; + uint128_t d0, d1, d2, d; + + r0 = st->r[0]; + r1 = st->r[1]; + r2 = st->r[2]; + + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + + s1 = r1 * (5 << 2); + s2 = r2 * (5 << 2); + + while (bytes >= poly1305_block_size) { + unsigned long long t0, t1; + + /* h += m[i] */ + t0 = SODIUM_LOAD64_LE(&m[0]); + t1 = SODIUM_LOAD64_LE(&m[8]); + + h0 += t0 & 0xfffffffffff; + h1 += ((t0 >> 44) | (t1 << 20)) & 0xfffffffffff; + h2 += (((t1 >> 24)) & 0x3ffffffffff) | hibit; + + /* h *= r */ + SODIUM_MUL(d0, h0, r0); + SODIUM_MUL(d, h1, s2); + SODIUM_ADD(d0, d); + SODIUM_MUL(d, h2, s1); + SODIUM_ADD(d0, d); + SODIUM_MUL(d1, h0, r1); + SODIUM_MUL(d, h1, r0); + SODIUM_ADD(d1, d); + SODIUM_MUL(d, h2, s2); + SODIUM_ADD(d1, d); + SODIUM_MUL(d2, h0, r2); + SODIUM_MUL(d, h1, r1); + SODIUM_ADD(d2, d); + SODIUM_MUL(d, h2, r0); + SODIUM_ADD(d2, d); + + /* (partial) h %= p */ + c = SODIUM_SHR(d0, 44); + h0 = SODIUM_LO(d0) & 0xfffffffffff; + SODIUM_ADDLO(d1, c); + c = SODIUM_SHR(d1, 44); + h1 = SODIUM_LO(d1) & 0xfffffffffff; + SODIUM_ADDLO(d2, c); + c = SODIUM_SHR(d2, 42); + h2 = SODIUM_LO(d2) & 0x3ffffffffff; + h0 += c * 5; + c = (h0 >> 44); + h0 &= 0xfffffffffff; + h1 += c; + + m += poly1305_block_size; + bytes -= poly1305_block_size; + } + + st->h[0] = h0; + st->h[1] = h1; + st->h[2] = h2; +} + +static POLY1305_NOINLINE void +donna_poly1305_finish(donna_poly1305_state_internal_t *st, unsigned char mac[16]) +{ + unsigned long long h0, h1, h2, c; + unsigned long long g0, g1, g2; + unsigned long long t0, t1; + unsigned long long mask; + + /* process the remaining block */ + if (st->leftover) { + unsigned long long i = st->leftover; + + st->buffer[i] = 1; + + for (i = i + 1; i < poly1305_block_size; i++) { + st->buffer[i] = 0; + } + st->final = 1; + donna_poly1305_blocks(st, st->buffer, poly1305_block_size); + } + + /* fully carry h */ + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + + c = h1 >> 44; + h1 &= 0xfffffffffff; + h2 += c; + c = h2 >> 42; + h2 &= 0x3ffffffffff; + h0 += c * 5; + c = h0 >> 44; + h0 &= 0xfffffffffff; + h1 += c; + c = h1 >> 44; + h1 &= 0xfffffffffff; + h2 += c; + c = h2 >> 42; + h2 &= 0x3ffffffffff; + h0 += c * 5; + c = h0 >> 44; + h0 &= 0xfffffffffff; + h1 += c; + + /* compute h + -p */ + g0 = h0 + 5; + c = g0 >> 44; + g0 &= 0xfffffffffff; + g1 = h1 + c; + c = g1 >> 44; + g1 &= 0xfffffffffff; + g2 = h2 + c - (1ULL << 42); + + /* select h if h < p, or h + -p if h >= p */ + mask = (g2 >> ((sizeof(unsigned long long) * 8) - 1)) - 1; + g0 &= mask; + g1 &= mask; + g2 &= mask; + mask = ~mask; + h0 = (h0 & mask) | g0; + h1 = (h1 & mask) | g1; + h2 = (h2 & mask) | g2; + + /* h = (h + pad) */ + t0 = st->pad[0]; + t1 = st->pad[1]; + + h0 += ((t0) & 0xfffffffffff); + c = (h0 >> 44); + h0 &= 0xfffffffffff; + h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; + c = (h1 >> 44); + h1 &= 0xfffffffffff; + h2 += (((t1 >> 24)) & 0x3ffffffffff) + c; + h2 &= 0x3ffffffffff; + + /* mac = h % (2^128) */ + h0 = (h0) | (h1 << 44); + h1 = (h1 >> 20) | (h2 << 24); + + SODIUM_STORE64_LE(&mac[0], h0); + SODIUM_STORE64_LE(&mac[8], h1); + + /* zero out the state */ + sodium_memzero((void *) st, sizeof *st); +} +/*** End of #include "poly1305_donna64.h" ***/ + +#else +/* #include "poly1305_donna32.h" */ +/*** Begin of #include "poly1305_donna32.h" ***/ +/* + poly1305 implementation using 32 bit * 32 bit = 64 bit multiplication + and 64 bit addition +*/ + +#if defined(_MSC_VER) +# define POLY1305_NOINLINE __declspec(noinline) +#elif defined(__clang__) || defined(__GNUC__) +# define POLY1305_NOINLINE __attribute__((noinline)) +#else +# define POLY1305_NOINLINE +#endif + +/* #include "../private/common.h" */ + + +#define poly1305_block_size 16 + +/* 17 + sizeof(unsigned long long) + 14*sizeof(unsigned long) */ +typedef struct donna_poly1305_state_internal_t { + unsigned long r[5]; + unsigned long h[5]; + unsigned long pad[4]; + unsigned long long leftover; + unsigned char buffer[poly1305_block_size]; + unsigned char final; +} donna_poly1305_state_internal_t; + +static void +donna_poly1305_init(donna_poly1305_state_internal_t *st, const unsigned char key[32]) +{ + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff - wiped after finalization */ + st->r[0] = (SODIUM_LOAD32_LE(&key[0])) & 0x3ffffff; + st->r[1] = (SODIUM_LOAD32_LE(&key[3]) >> 2) & 0x3ffff03; + st->r[2] = (SODIUM_LOAD32_LE(&key[6]) >> 4) & 0x3ffc0ff; + st->r[3] = (SODIUM_LOAD32_LE(&key[9]) >> 6) & 0x3f03fff; + st->r[4] = (SODIUM_LOAD32_LE(&key[12]) >> 8) & 0x00fffff; + + /* h = 0 */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + st->h[3] = 0; + st->h[4] = 0; + + /* save pad for later */ + st->pad[0] = SODIUM_LOAD32_LE(&key[16]); + st->pad[1] = SODIUM_LOAD32_LE(&key[20]); + st->pad[2] = SODIUM_LOAD32_LE(&key[24]); + st->pad[3] = SODIUM_LOAD32_LE(&key[28]); + + st->leftover = 0; + st->final = 0; +} + +static void +donna_poly1305_blocks(donna_poly1305_state_internal_t *st, const unsigned char *m, + unsigned long long bytes) +{ + const unsigned long hibit = (st->final) ? 0UL : (1UL << 24); /* 1 << 128 */ + unsigned long r0, r1, r2, r3, r4; + unsigned long s1, s2, s3, s4; + unsigned long h0, h1, h2, h3, h4; + unsigned long long d0, d1, d2, d3, d4; + unsigned long c; + + r0 = st->r[0]; + r1 = st->r[1]; + r2 = st->r[2]; + r3 = st->r[3]; + r4 = st->r[4]; + + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + h3 = st->h[3]; + h4 = st->h[4]; + + while (bytes >= poly1305_block_size) { + /* h += m[i] */ + h0 += (SODIUM_LOAD32_LE(m + 0)) & 0x3ffffff; + h1 += (SODIUM_LOAD32_LE(m + 3) >> 2) & 0x3ffffff; + h2 += (SODIUM_LOAD32_LE(m + 6) >> 4) & 0x3ffffff; + h3 += (SODIUM_LOAD32_LE(m + 9) >> 6) & 0x3ffffff; + h4 += (SODIUM_LOAD32_LE(m + 12) >> 8) | hibit; + + /* h *= r */ + d0 = ((unsigned long long) h0 * r0) + ((unsigned long long) h1 * s4) + + ((unsigned long long) h2 * s3) + ((unsigned long long) h3 * s2) + + ((unsigned long long) h4 * s1); + d1 = ((unsigned long long) h0 * r1) + ((unsigned long long) h1 * r0) + + ((unsigned long long) h2 * s4) + ((unsigned long long) h3 * s3) + + ((unsigned long long) h4 * s2); + d2 = ((unsigned long long) h0 * r2) + ((unsigned long long) h1 * r1) + + ((unsigned long long) h2 * r0) + ((unsigned long long) h3 * s4) + + ((unsigned long long) h4 * s3); + d3 = ((unsigned long long) h0 * r3) + ((unsigned long long) h1 * r2) + + ((unsigned long long) h2 * r1) + ((unsigned long long) h3 * r0) + + ((unsigned long long) h4 * s4); + d4 = ((unsigned long long) h0 * r4) + ((unsigned long long) h1 * r3) + + ((unsigned long long) h2 * r2) + ((unsigned long long) h3 * r1) + + ((unsigned long long) h4 * r0); + + /* (partial) h %= p */ + c = (unsigned long) (d0 >> 26); + h0 = (unsigned long) d0 & 0x3ffffff; + d1 += c; + c = (unsigned long) (d1 >> 26); + h1 = (unsigned long) d1 & 0x3ffffff; + d2 += c; + c = (unsigned long) (d2 >> 26); + h2 = (unsigned long) d2 & 0x3ffffff; + d3 += c; + c = (unsigned long) (d3 >> 26); + h3 = (unsigned long) d3 & 0x3ffffff; + d4 += c; + c = (unsigned long) (d4 >> 26); + h4 = (unsigned long) d4 & 0x3ffffff; + h0 += c * 5; + c = (h0 >> 26); + h0 &= 0x3ffffff; + h1 += c; + + m += poly1305_block_size; + bytes -= poly1305_block_size; + } + + st->h[0] = h0; + st->h[1] = h1; + st->h[2] = h2; + st->h[3] = h3; + st->h[4] = h4; +} + +static POLY1305_NOINLINE void +donna_poly1305_finish(donna_poly1305_state_internal_t *st, unsigned char mac[16]) +{ + unsigned long h0, h1, h2, h3, h4, c; + unsigned long g0, g1, g2, g3, g4; + unsigned long long f; + unsigned long mask; + + /* process the remaining block */ + if (st->leftover) { + unsigned long long i = st->leftover; + + st->buffer[i++] = 1; + for (; i < poly1305_block_size; i++) { + st->buffer[i] = 0; + } + st->final = 1; + donna_poly1305_blocks(st, st->buffer, poly1305_block_size); + } + + /* fully carry h */ + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + h3 = st->h[3]; + h4 = st->h[4]; + + c = h1 >> 26; + h1 = h1 & 0x3ffffff; + h2 += c; + c = h2 >> 26; + h2 = h2 & 0x3ffffff; + h3 += c; + c = h3 >> 26; + h3 = h3 & 0x3ffffff; + h4 += c; + c = h4 >> 26; + h4 = h4 & 0x3ffffff; + h0 += c * 5; + c = h0 >> 26; + h0 = h0 & 0x3ffffff; + h1 += c; + + /* compute h + -p */ + g0 = h0 + 5; + c = g0 >> 26; + g0 &= 0x3ffffff; + g1 = h1 + c; + c = g1 >> 26; + g1 &= 0x3ffffff; + g2 = h2 + c; + c = g2 >> 26; + g2 &= 0x3ffffff; + g3 = h3 + c; + c = g3 >> 26; + g3 &= 0x3ffffff; + g4 = h4 + c - (1UL << 26); + + /* select h if h < p, or h + -p if h >= p */ + mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1; + g0 &= mask; + g1 &= mask; + g2 &= mask; + g3 &= mask; + g4 &= mask; + mask = ~mask; + + h0 = (h0 & mask) | g0; + h1 = (h1 & mask) | g1; + h2 = (h2 & mask) | g2; + h3 = (h3 & mask) | g3; + h4 = (h4 & mask) | g4; + + /* h = h % (2^128) */ + h0 = ((h0) | (h1 << 26)) & 0xffffffff; + h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; + h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; + h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; + + /* mac = (h + pad) % (2^128) */ + f = (unsigned long long) h0 + st->pad[0]; + h0 = (unsigned long) f; + f = (unsigned long long) h1 + st->pad[1] + (f >> 32); + h1 = (unsigned long) f; + f = (unsigned long long) h2 + st->pad[2] + (f >> 32); + h2 = (unsigned long) f; + f = (unsigned long long) h3 + st->pad[3] + (f >> 32); + h3 = (unsigned long) f; + + SODIUM_STORE32_LE(mac + 0, (uint32_t) h0); + SODIUM_STORE32_LE(mac + 4, (uint32_t) h1); + SODIUM_STORE32_LE(mac + 8, (uint32_t) h2); + SODIUM_STORE32_LE(mac + 12, (uint32_t) h3); + + /* zero out the state */ + sodium_memzero((void *) st, sizeof *st); +} +/*** End of #include "poly1305_donna32.h" ***/ + +#endif +/* #include "../onetimeauth_poly1305.h" */ + + +static void +donna_poly1305_update(donna_poly1305_state_internal_t *st, const unsigned char *m, + unsigned long long bytes) +{ + unsigned long long i; + + /* handle leftover */ + if (st->leftover) { + unsigned long long want = (poly1305_block_size - st->leftover); + + if (want > bytes) { + want = bytes; + } + for (i = 0; i < want; i++) { + st->buffer[st->leftover + i] = m[i]; + } + bytes -= want; + m += want; + st->leftover += want; + if (st->leftover < poly1305_block_size) { + return; + } + donna_poly1305_blocks(st, st->buffer, poly1305_block_size); + st->leftover = 0; + } + + /* process full blocks */ + if (bytes >= poly1305_block_size) { + unsigned long long want = (bytes & ~(poly1305_block_size - 1)); + + donna_poly1305_blocks(st, m, want); + m += want; + bytes -= want; + } + + /* store leftover */ + if (bytes) { + for (i = 0; i < bytes; i++) { + st->buffer[st->leftover + i] = m[i]; + } + st->leftover += bytes; + } +} + +static int +crypto_onetimeauth_poly1305_donna(unsigned char *out, const unsigned char *m, + unsigned long long inlen, + const unsigned char *key) +{ + CRYPTO_ALIGN(64) donna_poly1305_state_internal_t state; + + donna_poly1305_init(&state, key); + donna_poly1305_update(&state, m, inlen); + donna_poly1305_finish(&state, out); + + return 0; +} + +static int +crypto_onetimeauth_poly1305_donna_init(crypto_onetimeauth_poly1305_state *state, + const unsigned char *key) +{ + COMPILER_ASSERT(sizeof(crypto_onetimeauth_poly1305_state) >= + sizeof(donna_poly1305_state_internal_t)); + donna_poly1305_init((donna_poly1305_state_internal_t *) (void *) state, key); + + return 0; +} + +static int +crypto_onetimeauth_poly1305_donna_update( + crypto_onetimeauth_poly1305_state *state, const unsigned char *in, + unsigned long long inlen) +{ + donna_poly1305_update((donna_poly1305_state_internal_t *) (void *) state, in, inlen); + + return 0; +} + +static int +crypto_onetimeauth_poly1305_donna_final( + crypto_onetimeauth_poly1305_state *state, unsigned char *out) +{ + donna_poly1305_finish((donna_poly1305_state_internal_t *) (void *) state, out); + + return 0; +} + +struct crypto_onetimeauth_poly1305_implementation + crypto_onetimeauth_poly1305_donna_implementation = { + .onetimeauth = crypto_onetimeauth_poly1305_donna, + .onetimeauth_init = crypto_onetimeauth_poly1305_donna_init, + .onetimeauth_update = + crypto_onetimeauth_poly1305_donna_update, + .onetimeauth_final = crypto_onetimeauth_poly1305_donna_final + }; + +#undef poly1305_block_size +/*** End of #include "donna/poly1305_donna.c" ***/ + + +#if defined(SQLITE3MC_TARGET_X86) +#if defined(HAVE_TI_MODE) || defined(SQLITE3MC_POLY1305_HAVE_128BIT) + +/* #include "sse2/poly1305_sse2.c" */ +/*** Begin of #include "sse2/poly1305_sse2.c" ***/ + +#include +#include + +/* #include "../onetimeauth_poly1305.h" */ + +/* #include "poly1305_sse2.h" */ +/*** Begin of #include "poly1305_sse2.h" ***/ +#ifndef poly1305_sse2_H +#define poly1305_sse2_H + +#include + +/* #include "../onetimeauth_poly1305.h" */ + + +extern struct crypto_onetimeauth_poly1305_implementation + crypto_onetimeauth_poly1305_sse2_implementation; + +#endif /* poly1305_sse2_H */ +/*** End of #include "poly1305_sse2.h" ***/ + +/* #include "../private/common.h" */ + + +#if defined(SQLITE3MC_TARGET_X86) + +#if defined(HAVE_TI_MODE) || defined(SQLITE3MC_POLY1305_HAVE_128BIT) + +# ifdef __clang__ +# pragma clang attribute push(__attribute__((target("sse2"))), apply_to = function) +# elif defined(__GNUC__) +# pragma GCC target("sse2") +# endif + +# include +/* # include "../private/sse2_64_32.h" */ + + +typedef __m128i xmmi; + +# if defined(_MSC_VER) +# define POLY1305_NOINLINE __declspec(noinline) +# elif defined(__clang__) || defined(__GNUC__) +# define POLY1305_NOINLINE __attribute__((noinline)) +# else +# define POLY1305_NOINLINE +# endif + +# define poly1305_block_size 32 + +enum poly1305_state_flags_t { + poly1305_started = 1, + poly1305_final_shift8 = 4, + poly1305_final_shift16 = 8, + poly1305_final_r2_r = 16, /* use [r^2,r] for the final block */ + poly1305_final_r_1 = 32 /* use [r,1] for the final block */ +}; + +typedef struct sse2_poly1305_state_internal_t { + union { + uint64_t h[3]; + uint32_t hh[10]; + } H; /* 40 bytes */ + uint32_t R[5]; /* 20 bytes */ + uint32_t R2[5]; /* 20 bytes */ + uint32_t R4[5]; /* 20 bytes */ + uint64_t pad[2]; /* 16 bytes */ + uint64_t flags; /* 8 bytes */ + unsigned long long leftover; /* 8 bytes */ + unsigned char buffer[poly1305_block_size]; /* 32 bytes */ +} sse2_poly1305_state_internal_t; /* 164 bytes total */ + +/* + * _mm_loadl_epi64() is turned into a simple MOVQ. So, unaligned accesses are + * totally fine, even though this intrinsic requires a __m128i* input. + * This confuses static analysis, so force alignment, only in debug mode. + */ +# ifdef DEBUG +static xmmi +_fakealign_mm_loadl_epi64(const void *m) +{ + xmmi tmp; + memcpy(&tmp, m, 8); + + return _mm_loadl_epi64(&tmp); +} +# define _mm_loadl_epi64(X) _fakealign_mm_loadl_epi64(X) +#endif + +/* copy 0-31 bytes */ +static inline void +sse2_poly1305_block_copy31(unsigned char *dst, const unsigned char *src, + unsigned long long bytes) +{ + if (bytes & 16) { + _mm_store_si128((xmmi *) (void *) dst, + _mm_loadu_si128((const xmmi *) (const void *) src)); + src += 16; + dst += 16; + } + if (bytes & 8) { + memcpy(dst, src, 8); + src += 8; + dst += 8; + } + if (bytes & 4) { + memcpy(dst, src, 4); + src += 4; + dst += 4; + } + if (bytes & 2) { + memcpy(dst, src, 2); + src += 2; + dst += 2; + } + if (bytes & 1) { + *dst = *src; + } +} + +static POLY1305_NOINLINE void +sse2_poly1305_init_ext(sse2_poly1305_state_internal_t *st, const unsigned char key[32], + unsigned long long bytes) +{ + uint32_t *R; + uint128_t d[3]; + uint64_t r0, r1, r2; + uint64_t rt0, rt1, rt2, st2, c; + uint64_t t0, t1; + unsigned long long i; + + if (!bytes) { + bytes = ~(unsigned long long) 0; + } + /* H = 0 */ + _mm_storeu_si128((xmmi *) (void *) &st->H.hh[0], _mm_setzero_si128()); + _mm_storeu_si128((xmmi *) (void *) &st->H.hh[4], _mm_setzero_si128()); + _mm_storeu_si128((xmmi *) (void *) &st->H.hh[8], _mm_setzero_si128()); + + /* clamp key */ + memcpy(&t0, key, 8); + memcpy(&t1, key + 8, 8); + r0 = t0 & 0xffc0fffffff; + t0 >>= 44; + t0 |= t1 << 20; + r1 = t0 & 0xfffffc0ffff; + t1 >>= 24; + r2 = t1 & 0x00ffffffc0f; + + /* r^1 */ + R = st->R; + R[0] = (uint32_t)(r0) &0x3ffffff; + R[1] = (uint32_t)((r0 >> 26) | (r1 << 18)) & 0x3ffffff; + R[2] = (uint32_t)((r1 >> 8)) & 0x3ffffff; + R[3] = (uint32_t)((r1 >> 34) | (r2 << 10)) & 0x3ffffff; + R[4] = (uint32_t)((r2 >> 16)); + + /* save pad */ + memcpy(&st->pad[0], key + 16, 8); + memcpy(&st->pad[1], key + 24, 8); + + rt0 = r0; + rt1 = r1; + rt2 = r2; + + /* r^2, r^4 */ + for (i = 0; i < 2; i++) { + if (i == 0) { + R = st->R2; + if (bytes <= 16) { + break; + } + } else if (i == 1) { + R = st->R4; + if (bytes < 96) { + break; + } + } + st2 = rt2 * (5 << 2); + +#ifdef SQLITE3MC_POLY1305_HAVE_128BIT + d[0] = u128_add(u128_mul(rt0, rt0), u128_mul(rt1 * 2, st2)); + d[1] = u128_add(u128_mul(rt2, st2), u128_mul(rt0 * 2, rt1)); + d[2] = u128_add(u128_mul(rt1, rt1), u128_mul(rt2 * 2, rt0)); + + rt0 = u128_lo(d[0]) & 0xfffffffffff; + c = u128_shr(d[0], 44); + d[1] = u128_addlo(d[1], c); + + rt1 = u128_lo(d[1]) & 0xfffffffffff; + c = u128_shr(d[1], 44); + d[2] = u128_addlo(d[2], c); + + rt2 = u128_lo(d[2]) & 0x3ffffffffff; + c = u128_shr(d[2], 42); +#else + d[0] = ((uint128_t) rt0 * rt0) + ((uint128_t)(rt1 * 2) * st2); + d[1] = ((uint128_t) rt2 * st2) + ((uint128_t)(rt0 * 2) * rt1); + d[2] = ((uint128_t) rt1 * rt1) + ((uint128_t)(rt2 * 2) * rt0); + + rt0 = (uint64_t) d[0] & 0xfffffffffff; + c = (uint64_t)(d[0] >> 44); + d[1] += c; + + rt1 = (uint64_t) d[1] & 0xfffffffffff; + c = (uint64_t)(d[1] >> 44); + d[2] += c; + + rt2 = (uint64_t) d[2] & 0x3ffffffffff; + c = (uint64_t)(d[2] >> 42); +#endif + rt0 += c * 5; + c = (rt0 >> 44); + rt0 = rt0 & 0xfffffffffff; + rt1 += c; + c = (rt1 >> 44); + rt1 = rt1 & 0xfffffffffff; + rt2 += c; /* even if rt2 overflows, it will still fit in rp4 safely, and + is safe to multiply with */ + + R[0] = (uint32_t)(rt0) &0x3ffffff; + R[1] = (uint32_t)((rt0 >> 26) | (rt1 << 18)) & 0x3ffffff; + R[2] = (uint32_t)((rt1 >> 8)) & 0x3ffffff; + R[3] = (uint32_t)((rt1 >> 34) | (rt2 << 10)) & 0x3ffffff; + R[4] = (uint32_t)((rt2 >> 16)); + } + st->flags = 0; + st->leftover = 0U; +} + +static volatile uint64_t optblocker_u64; + +static POLY1305_NOINLINE void +sse2_poly1305_blocks(sse2_poly1305_state_internal_t *st, const unsigned char *m, + unsigned long long bytes) +{ + CRYPTO_ALIGN(64) + xmmi sse2_HIBIT = + _mm_shuffle_epi32(_mm_cvtsi32_si128(1 << 24), _MM_SHUFFLE(1, 0, 1, 0)); + const xmmi sse2_MMASK = _mm_shuffle_epi32(_mm_cvtsi32_si128((1 << 26) - 1), + _MM_SHUFFLE(1, 0, 1, 0)); + const xmmi FIVE = + _mm_shuffle_epi32(_mm_cvtsi32_si128(5), _MM_SHUFFLE(1, 0, 1, 0)); + xmmi H0, H1, H2, H3, H4; + xmmi T0, T1, T2, T3, T4, T5, T6, T7, T8; + xmmi M0, M1, M2, M3, M4; + xmmi M5, M6, M7, M8; + xmmi C1, C2; + xmmi R20, R21, R22, R23, R24, S21, S22, S23, S24; + xmmi R40, R41, R42, R43, R44, S41, S42, S43, S44; + + if (st->flags & poly1305_final_shift8) { + sse2_HIBIT = _mm_srli_si128(sse2_HIBIT, 8); + } + if (st->flags & poly1305_final_shift16) { + sse2_HIBIT = _mm_setzero_si128(); + } + if (!(st->flags & poly1305_started)) { + /* H = [Mx,My] */ + T5 = _mm_unpacklo_epi64( + _mm_loadl_epi64((const xmmi *) (const void *) (m + 0)), + _mm_loadl_epi64((const xmmi *) (const void *) (m + 16))); + T6 = _mm_unpacklo_epi64( + _mm_loadl_epi64((const xmmi *) (const void *) (m + 8)), + _mm_loadl_epi64((const xmmi *) (const void *) (m + 24))); + H0 = _mm_and_si128(sse2_MMASK, T5); + H1 = _mm_and_si128(sse2_MMASK, _mm_srli_epi64(T5, 26)); + T5 = _mm_or_si128(_mm_srli_epi64(T5, 52), _mm_slli_epi64(T6, 12)); + H2 = _mm_and_si128(sse2_MMASK, T5); + H3 = _mm_and_si128(sse2_MMASK, _mm_srli_epi64(T5, 26)); + H4 = _mm_srli_epi64(T6, 40); + H4 = _mm_or_si128(H4, sse2_HIBIT); + m += 32; + bytes -= 32; + st->flags |= poly1305_started; + } else { + T0 = _mm_loadu_si128((const xmmi *) (const void *) &st->H.hh[0]); + T1 = _mm_loadu_si128((const xmmi *) (const void *) &st->H.hh[4]); + T2 = _mm_loadu_si128((const xmmi *) (const void *) &st->H.hh[8]); + H0 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(1, 1, 0, 0)); + H1 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(3, 3, 2, 2)); + H2 = _mm_shuffle_epi32(T1, _MM_SHUFFLE(1, 1, 0, 0)); + H3 = _mm_shuffle_epi32(T1, _MM_SHUFFLE(3, 3, 2, 2)); + H4 = _mm_shuffle_epi32(T2, _MM_SHUFFLE(1, 1, 0, 0)); + } + if (st->flags & (poly1305_final_r2_r | poly1305_final_r_1)) { + if (st->flags & poly1305_final_r2_r) { + /* use [r^2, r] */ + T2 = _mm_loadu_si128((const xmmi *) (const void *) &st->R[0]); + T3 = _mm_cvtsi32_si128(st->R[4]); + T0 = _mm_loadu_si128((const xmmi *) (const void *) &st->R2[0]); + T1 = _mm_cvtsi32_si128(st->R2[4]); + T4 = _mm_unpacklo_epi32(T0, T2); + T5 = _mm_unpackhi_epi32(T0, T2); + R24 = _mm_unpacklo_epi64(T1, T3); + } else { + /* use [r^1, 1] */ + T0 = _mm_loadu_si128((const xmmi *) (const void *) &st->R[0]); + T1 = _mm_cvtsi32_si128(st->R[4]); + T2 = _mm_cvtsi32_si128(1); + T4 = _mm_unpacklo_epi32(T0, T2); + T5 = _mm_unpackhi_epi32(T0, T2); + R24 = T1; + } + R20 = _mm_shuffle_epi32(T4, _MM_SHUFFLE(1, 1, 0, 0)); + R21 = _mm_shuffle_epi32(T4, _MM_SHUFFLE(3, 3, 2, 2)); + R22 = _mm_shuffle_epi32(T5, _MM_SHUFFLE(1, 1, 0, 0)); + R23 = _mm_shuffle_epi32(T5, _MM_SHUFFLE(3, 3, 2, 2)); + } else { + /* use [r^2, r^2] */ + T0 = _mm_loadu_si128((const xmmi *) (const void *) &st->R2[0]); + T1 = _mm_cvtsi32_si128(st->R2[4]); + R20 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(0, 0, 0, 0)); + R21 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(1, 1, 1, 1)); + R22 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(2, 2, 2, 2)); + R23 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(3, 3, 3, 3)); + R24 = _mm_shuffle_epi32(T1, _MM_SHUFFLE(0, 0, 0, 0)); + } + S21 = _mm_mul_epu32(R21, FIVE); + S22 = _mm_mul_epu32(R22, FIVE); + S23 = _mm_mul_epu32(R23, FIVE); + S24 = _mm_mul_epu32(R24, FIVE); + + if (bytes >= 64) { + T0 = _mm_loadu_si128((const xmmi *) (const void *) &st->R4[0]); + T1 = _mm_cvtsi32_si128(st->R4[4]); + R40 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(0, 0, 0, 0)); + R41 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(1, 1, 1, 1)); + R42 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(2, 2, 2, 2)); + R43 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(3, 3, 3, 3)); + R44 = _mm_shuffle_epi32(T1, _MM_SHUFFLE(0, 0, 0, 0)); + S41 = _mm_mul_epu32(R41, FIVE); + S42 = _mm_mul_epu32(R42, FIVE); + S43 = _mm_mul_epu32(R43, FIVE); + S44 = _mm_mul_epu32(R44, FIVE); + + while (bytes >= 64) { + xmmi v00, v01, v02, v03, v04; + xmmi v10, v11, v12, v13, v14; + xmmi v20, v21, v22, v23, v24; + xmmi v30, v31, v32, v33, v34; + xmmi v40, v41, v42, v43, v44; + xmmi T14, T15; + + /* H *= [r^4,r^4], preload [Mx,My] */ + T15 = S42; + T0 = H4; + T0 = _mm_mul_epu32(T0, S41); + v01 = H3; + v01 = _mm_mul_epu32(v01, T15); + T14 = S43; + T1 = H4; + T1 = _mm_mul_epu32(T1, T15); + v11 = H3; + v11 = _mm_mul_epu32(v11, T14); + T2 = H4; + T2 = _mm_mul_epu32(T2, T14); + T0 = _mm_add_epi64(T0, v01); + T15 = S44; + v02 = H2; + v02 = _mm_mul_epu32(v02, T14); + T3 = H4; + T3 = _mm_mul_epu32(T3, T15); + T1 = _mm_add_epi64(T1, v11); + v03 = H1; + v03 = _mm_mul_epu32(v03, T15); + v12 = H2; + v12 = _mm_mul_epu32(v12, T15); + T0 = _mm_add_epi64(T0, v02); + T14 = R40; + v21 = H3; + v21 = _mm_mul_epu32(v21, T15); + v31 = H3; + v31 = _mm_mul_epu32(v31, T14); + T0 = _mm_add_epi64(T0, v03); + T4 = H4; + T4 = _mm_mul_epu32(T4, T14); + T1 = _mm_add_epi64(T1, v12); + v04 = H0; + v04 = _mm_mul_epu32(v04, T14); + T2 = _mm_add_epi64(T2, v21); + v13 = H1; + v13 = _mm_mul_epu32(v13, T14); + T3 = _mm_add_epi64(T3, v31); + T15 = R41; + v22 = H2; + v22 = _mm_mul_epu32(v22, T14); + v32 = H2; + v32 = _mm_mul_epu32(v32, T15); + T0 = _mm_add_epi64(T0, v04); + v41 = H3; + v41 = _mm_mul_epu32(v41, T15); + T1 = _mm_add_epi64(T1, v13); + v14 = H0; + v14 = _mm_mul_epu32(v14, T15); + T2 = _mm_add_epi64(T2, v22); + T14 = R42; + T5 = _mm_unpacklo_epi64( + _mm_loadl_epi64((const xmmi *) (const void *) (m + 0)), + _mm_loadl_epi64((const xmmi *) (const void *) (m + 16))); + v23 = H1; + v23 = _mm_mul_epu32(v23, T15); + T3 = _mm_add_epi64(T3, v32); + v33 = H1; + v33 = _mm_mul_epu32(v33, T14); + T4 = _mm_add_epi64(T4, v41); + v42 = H2; + v42 = _mm_mul_epu32(v42, T14); + T1 = _mm_add_epi64(T1, v14); + T15 = R43; + T6 = _mm_unpacklo_epi64( + _mm_loadl_epi64((const xmmi *) (const void *) (m + 8)), + _mm_loadl_epi64((const xmmi *) (const void *) (m + 24))); + v24 = H0; + v24 = _mm_mul_epu32(v24, T14); + T2 = _mm_add_epi64(T2, v23); + v34 = H0; + v34 = _mm_mul_epu32(v34, T15); + T3 = _mm_add_epi64(T3, v33); + M0 = _mm_and_si128(sse2_MMASK, T5); + v43 = H1; + v43 = _mm_mul_epu32(v43, T15); + T4 = _mm_add_epi64(T4, v42); + M1 = _mm_and_si128(sse2_MMASK, _mm_srli_epi64(T5, 26)); + v44 = H0; + v44 = _mm_mul_epu32(v44, R44); + T2 = _mm_add_epi64(T2, v24); + T5 = _mm_or_si128(_mm_srli_epi64(T5, 52), _mm_slli_epi64(T6, 12)); + T3 = _mm_add_epi64(T3, v34); + M3 = _mm_and_si128(sse2_MMASK, _mm_srli_epi64(T6, 14)); + T4 = _mm_add_epi64(T4, v43); + M2 = _mm_and_si128(sse2_MMASK, T5); + T4 = _mm_add_epi64(T4, v44); + M4 = _mm_or_si128(_mm_srli_epi64(T6, 40), sse2_HIBIT); + + /* H += [Mx',My'] */ + T5 = _mm_loadu_si128((const xmmi *) (const void *) (m + 32)); + T6 = _mm_loadu_si128((const xmmi *) (const void *) (m + 48)); + T7 = _mm_unpacklo_epi32(T5, T6); + T8 = _mm_unpackhi_epi32(T5, T6); + M5 = _mm_unpacklo_epi32(T7, _mm_setzero_si128()); + M6 = _mm_unpackhi_epi32(T7, _mm_setzero_si128()); + M7 = _mm_unpacklo_epi32(T8, _mm_setzero_si128()); + M8 = _mm_unpackhi_epi32(T8, _mm_setzero_si128()); + M6 = _mm_slli_epi64(M6, 6); + M7 = _mm_slli_epi64(M7, 12); + M8 = _mm_slli_epi64(M8, 18); + T0 = _mm_add_epi64(T0, M5); + T1 = _mm_add_epi64(T1, M6); + T2 = _mm_add_epi64(T2, M7); + T3 = _mm_add_epi64(T3, M8); + T4 = _mm_add_epi64(T4, sse2_HIBIT); + + /* H += [Mx,My]*[r^2,r^2] */ + T15 = S22; + v00 = M4; + v00 = _mm_mul_epu32(v00, S21); + v01 = M3; + v01 = _mm_mul_epu32(v01, T15); + T14 = S23; + v10 = M4; + v10 = _mm_mul_epu32(v10, T15); + v11 = M3; + v11 = _mm_mul_epu32(v11, T14); + T0 = _mm_add_epi64(T0, v00); + v20 = M4; + v20 = _mm_mul_epu32(v20, T14); + T0 = _mm_add_epi64(T0, v01); + T15 = S24; + v02 = M2; + v02 = _mm_mul_epu32(v02, T14); + T1 = _mm_add_epi64(T1, v10); + v30 = M4; + v30 = _mm_mul_epu32(v30, T15); + T1 = _mm_add_epi64(T1, v11); + v03 = M1; + v03 = _mm_mul_epu32(v03, T15); + T2 = _mm_add_epi64(T2, v20); + v12 = M2; + v12 = _mm_mul_epu32(v12, T15); + T0 = _mm_add_epi64(T0, v02); + T14 = R20; + v21 = M3; + v21 = _mm_mul_epu32(v21, T15); + T3 = _mm_add_epi64(T3, v30); + v31 = M3; + v31 = _mm_mul_epu32(v31, T14); + T0 = _mm_add_epi64(T0, v03); + v40 = M4; + v40 = _mm_mul_epu32(v40, T14); + T1 = _mm_add_epi64(T1, v12); + v04 = M0; + v04 = _mm_mul_epu32(v04, T14); + T2 = _mm_add_epi64(T2, v21); + v13 = M1; + v13 = _mm_mul_epu32(v13, T14); + T3 = _mm_add_epi64(T3, v31); + T15 = R21; + v22 = M2; + v22 = _mm_mul_epu32(v22, T14); + T4 = _mm_add_epi64(T4, v40); + v32 = M2; + v32 = _mm_mul_epu32(v32, T15); + T0 = _mm_add_epi64(T0, v04); + v41 = M3; + v41 = _mm_mul_epu32(v41, T15); + T1 = _mm_add_epi64(T1, v13); + v14 = M0; + v14 = _mm_mul_epu32(v14, T15); + T2 = _mm_add_epi64(T2, v22); + T14 = R22; + v23 = M1; + v23 = _mm_mul_epu32(v23, T15); + T3 = _mm_add_epi64(T3, v32); + v33 = M1; + v33 = _mm_mul_epu32(v33, T14); + T4 = _mm_add_epi64(T4, v41); + v42 = M2; + v42 = _mm_mul_epu32(v42, T14); + T1 = _mm_add_epi64(T1, v14); + T15 = R23; + v24 = M0; + v24 = _mm_mul_epu32(v24, T14); + T2 = _mm_add_epi64(T2, v23); + v34 = M0; + v34 = _mm_mul_epu32(v34, T15); + T3 = _mm_add_epi64(T3, v33); + v43 = M1; + v43 = _mm_mul_epu32(v43, T15); + T4 = _mm_add_epi64(T4, v42); + v44 = M0; + v44 = _mm_mul_epu32(v44, R24); + T2 = _mm_add_epi64(T2, v24); + T3 = _mm_add_epi64(T3, v34); + T4 = _mm_add_epi64(T4, v43); + T4 = _mm_add_epi64(T4, v44); + + /* reduce */ + C1 = _mm_srli_epi64(T0, 26); + C2 = _mm_srli_epi64(T3, 26); + T0 = _mm_and_si128(T0, sse2_MMASK); + T3 = _mm_and_si128(T3, sse2_MMASK); + T1 = _mm_add_epi64(T1, C1); + T4 = _mm_add_epi64(T4, C2); + C1 = _mm_srli_epi64(T1, 26); + C2 = _mm_srli_epi64(T4, 26); + T1 = _mm_and_si128(T1, sse2_MMASK); + T4 = _mm_and_si128(T4, sse2_MMASK); + T2 = _mm_add_epi64(T2, C1); + T0 = _mm_add_epi64(T0, _mm_mul_epu32(C2, FIVE)); + C1 = _mm_srli_epi64(T2, 26); + C2 = _mm_srli_epi64(T0, 26); + T2 = _mm_and_si128(T2, sse2_MMASK); + T0 = _mm_and_si128(T0, sse2_MMASK); + T3 = _mm_add_epi64(T3, C1); + T1 = _mm_add_epi64(T1, C2); + C1 = _mm_srli_epi64(T3, 26); + T3 = _mm_and_si128(T3, sse2_MMASK); + T4 = _mm_add_epi64(T4, C1); + + /* Final: H = (H*[r^4,r^4] + [Mx,My]*[r^2,r^2] + [Mx',My']) */ + H0 = T0; + H1 = T1; + H2 = T2; + H3 = T3; + H4 = T4; + + m += 64; + bytes -= 64; + } + } + + if (bytes >= 32) { + xmmi v01, v02, v03, v04; + xmmi v11, v12, v13, v14; + xmmi v21, v22, v23, v24; + xmmi v31, v32, v33, v34; + xmmi v41, v42, v43, v44; + xmmi T14, T15; + + /* H *= [r^2,r^2] */ + T15 = S22; + T0 = H4; + T0 = _mm_mul_epu32(T0, S21); + v01 = H3; + v01 = _mm_mul_epu32(v01, T15); + T14 = S23; + T1 = H4; + T1 = _mm_mul_epu32(T1, T15); + v11 = H3; + v11 = _mm_mul_epu32(v11, T14); + T2 = H4; + T2 = _mm_mul_epu32(T2, T14); + T0 = _mm_add_epi64(T0, v01); + T15 = S24; + v02 = H2; + v02 = _mm_mul_epu32(v02, T14); + T3 = H4; + T3 = _mm_mul_epu32(T3, T15); + T1 = _mm_add_epi64(T1, v11); + v03 = H1; + v03 = _mm_mul_epu32(v03, T15); + v12 = H2; + v12 = _mm_mul_epu32(v12, T15); + T0 = _mm_add_epi64(T0, v02); + T14 = R20; + v21 = H3; + v21 = _mm_mul_epu32(v21, T15); + v31 = H3; + v31 = _mm_mul_epu32(v31, T14); + T0 = _mm_add_epi64(T0, v03); + T4 = H4; + T4 = _mm_mul_epu32(T4, T14); + T1 = _mm_add_epi64(T1, v12); + v04 = H0; + v04 = _mm_mul_epu32(v04, T14); + T2 = _mm_add_epi64(T2, v21); + v13 = H1; + v13 = _mm_mul_epu32(v13, T14); + T3 = _mm_add_epi64(T3, v31); + T15 = R21; + v22 = H2; + v22 = _mm_mul_epu32(v22, T14); + v32 = H2; + v32 = _mm_mul_epu32(v32, T15); + T0 = _mm_add_epi64(T0, v04); + v41 = H3; + v41 = _mm_mul_epu32(v41, T15); + T1 = _mm_add_epi64(T1, v13); + v14 = H0; + v14 = _mm_mul_epu32(v14, T15); + T2 = _mm_add_epi64(T2, v22); + T14 = R22; + v23 = H1; + v23 = _mm_mul_epu32(v23, T15); + T3 = _mm_add_epi64(T3, v32); + v33 = H1; + v33 = _mm_mul_epu32(v33, T14); + T4 = _mm_add_epi64(T4, v41); + v42 = H2; + v42 = _mm_mul_epu32(v42, T14); + T1 = _mm_add_epi64(T1, v14); + T15 = R23; + v24 = H0; + v24 = _mm_mul_epu32(v24, T14); + T2 = _mm_add_epi64(T2, v23); + v34 = H0; + v34 = _mm_mul_epu32(v34, T15); + T3 = _mm_add_epi64(T3, v33); + v43 = H1; + v43 = _mm_mul_epu32(v43, T15); + T4 = _mm_add_epi64(T4, v42); + v44 = H0; + v44 = _mm_mul_epu32(v44, R24); + T2 = _mm_add_epi64(T2, v24); + T3 = _mm_add_epi64(T3, v34); + T4 = _mm_add_epi64(T4, v43); + T4 = _mm_add_epi64(T4, v44); + + /* H += [Mx,My] */ + if (m) { + T5 = _mm_loadu_si128((const xmmi *) (const void *) (m + 0)); + T6 = _mm_loadu_si128((const xmmi *) (const void *) (m + 16)); + T7 = _mm_unpacklo_epi32(T5, T6); + T8 = _mm_unpackhi_epi32(T5, T6); + M0 = _mm_unpacklo_epi32(T7, _mm_setzero_si128()); + M1 = _mm_unpackhi_epi32(T7, _mm_setzero_si128()); + M2 = _mm_unpacklo_epi32(T8, _mm_setzero_si128()); + M3 = _mm_unpackhi_epi32(T8, _mm_setzero_si128()); + M1 = _mm_slli_epi64(M1, 6); + M2 = _mm_slli_epi64(M2, 12); + M3 = _mm_slli_epi64(M3, 18); + T0 = _mm_add_epi64(T0, M0); + T1 = _mm_add_epi64(T1, M1); + T2 = _mm_add_epi64(T2, M2); + T3 = _mm_add_epi64(T3, M3); + T4 = _mm_add_epi64(T4, sse2_HIBIT); + } + + /* reduce */ + C1 = _mm_srli_epi64(T0, 26); + C2 = _mm_srli_epi64(T3, 26); + T0 = _mm_and_si128(T0, sse2_MMASK); + T3 = _mm_and_si128(T3, sse2_MMASK); + T1 = _mm_add_epi64(T1, C1); + T4 = _mm_add_epi64(T4, C2); + C1 = _mm_srli_epi64(T1, 26); + C2 = _mm_srli_epi64(T4, 26); + T1 = _mm_and_si128(T1, sse2_MMASK); + T4 = _mm_and_si128(T4, sse2_MMASK); + T2 = _mm_add_epi64(T2, C1); + T0 = _mm_add_epi64(T0, _mm_mul_epu32(C2, FIVE)); + C1 = _mm_srli_epi64(T2, 26); + C2 = _mm_srli_epi64(T0, 26); + T2 = _mm_and_si128(T2, sse2_MMASK); + T0 = _mm_and_si128(T0, sse2_MMASK); + T3 = _mm_add_epi64(T3, C1); + T1 = _mm_add_epi64(T1, C2); + C1 = _mm_srli_epi64(T3, 26); + T3 = _mm_and_si128(T3, sse2_MMASK); + T4 = _mm_add_epi64(T4, C1); + + /* H = (H*[r^2,r^2] + [Mx,My]) */ + H0 = T0; + H1 = T1; + H2 = T2; + H3 = T3; + H4 = T4; + } + + if (m) { + T0 = _mm_shuffle_epi32(H0, _MM_SHUFFLE(0, 0, 2, 0)); + T1 = _mm_shuffle_epi32(H1, _MM_SHUFFLE(0, 0, 2, 0)); + T2 = _mm_shuffle_epi32(H2, _MM_SHUFFLE(0, 0, 2, 0)); + T3 = _mm_shuffle_epi32(H3, _MM_SHUFFLE(0, 0, 2, 0)); + T4 = _mm_shuffle_epi32(H4, _MM_SHUFFLE(0, 0, 2, 0)); + T0 = _mm_unpacklo_epi64(T0, T1); + T1 = _mm_unpacklo_epi64(T2, T3); + _mm_storeu_si128((xmmi *) (void *) &st->H.hh[0], T0); + _mm_storeu_si128((xmmi *) (void *) &st->H.hh[4], T1); + _mm_storel_epi64((xmmi *) (void *) &st->H.hh[8], T4); + } else { + uint32_t t0, t1, t2, t3, t4, b; + uint64_t h0, h1, h2, g0, g1, g2, c, nc; + + /* H = H[0]+H[1] */ + T0 = H0; + T1 = H1; + T2 = H2; + T3 = H3; + T4 = H4; + + T0 = _mm_add_epi64(T0, _mm_srli_si128(T0, 8)); + T1 = _mm_add_epi64(T1, _mm_srli_si128(T1, 8)); + T2 = _mm_add_epi64(T2, _mm_srli_si128(T2, 8)); + T3 = _mm_add_epi64(T3, _mm_srli_si128(T3, 8)); + T4 = _mm_add_epi64(T4, _mm_srli_si128(T4, 8)); + + t0 = _mm_cvtsi128_si32(T0); + b = (t0 >> 26); + t0 &= 0x3ffffff; + t1 = _mm_cvtsi128_si32(T1) + b; + b = (t1 >> 26); + t1 &= 0x3ffffff; + t2 = _mm_cvtsi128_si32(T2) + b; + b = (t2 >> 26); + t2 &= 0x3ffffff; + t3 = _mm_cvtsi128_si32(T3) + b; + b = (t3 >> 26); + t3 &= 0x3ffffff; + t4 = _mm_cvtsi128_si32(T4) + b; + + /* everything except t4 is in range, so this is all safe */ + h0 = (((uint64_t) t0) | ((uint64_t) t1 << 26)) & 0xfffffffffffull; + h1 = (((uint64_t) t1 >> 18) | ((uint64_t) t2 << 8) | + ((uint64_t) t3 << 34)) & + 0xfffffffffffull; + h2 = (((uint64_t) t3 >> 10) | ((uint64_t) t4 << 16)); + + c = (h2 >> 42); + h2 &= 0x3ffffffffff; + h0 += c * 5; + c = (h0 >> 44); + h0 &= 0xfffffffffff; + h1 += c; + c = (h1 >> 44); + h1 &= 0xfffffffffff; + h2 += c; + c = (h2 >> 42); + h2 &= 0x3ffffffffff; + h0 += c * 5; + c = (h0 >> 44); + h0 &= 0xfffffffffff; + h1 += c; + + g0 = h0 + 5; + c = (g0 >> 44); + g0 &= 0xfffffffffff; + g1 = h1 + c; + c = (g1 >> 44); + g1 &= 0xfffffffffff; + g2 = h2 + c - ((uint64_t) 1 << 42); + + c = (((g2 >> 61) ^ optblocker_u64) >> 2) - 1; + nc = ~c; + h0 = (h0 & nc) | (g0 & c); + h1 = (h1 & nc) | (g1 & c); + h2 = (h2 & nc) | (g2 & c); + + st->H.h[0] = h0; + st->H.h[1] = h1; + st->H.h[2] = h2; + } +} + +static void +sse2_poly1305_update(sse2_poly1305_state_internal_t *st, const unsigned char *m, + unsigned long long bytes) +{ + unsigned long long i; + + /* handle leftover */ + if (st->leftover) { + unsigned long long want = (poly1305_block_size - st->leftover); + + if (want > bytes) { + want = bytes; + } + for (i = 0; i < want; i++) { + st->buffer[st->leftover + i] = m[i]; + } + bytes -= want; + m += want; + st->leftover += want; + if (st->leftover < poly1305_block_size) { + return; + } + sse2_poly1305_blocks(st, st->buffer, poly1305_block_size); + st->leftover = 0; + } + + /* process full blocks */ + if (bytes >= poly1305_block_size) { + unsigned long long want = (bytes & ~(poly1305_block_size - 1)); + + sse2_poly1305_blocks(st, m, want); + m += want; + bytes -= want; + } + + /* store leftover */ + if (bytes) { + for (i = 0; i < bytes; i++) { + st->buffer[st->leftover + i] = m[i]; + } + st->leftover += bytes; + } +} + +static POLY1305_NOINLINE void +sse2_poly1305_finish_ext(sse2_poly1305_state_internal_t *st, const unsigned char *m, + unsigned long long leftover, unsigned char mac[16]) +{ + uint64_t h0, h1, h2; + + if (leftover) { + CRYPTO_ALIGN(16) unsigned char final[32] = { 0 }; + + sse2_poly1305_block_copy31(final, m, leftover); + if (leftover != 16) { + final[leftover] = 1; + } + st->flags |= + (leftover >= 16) ? poly1305_final_shift8 : poly1305_final_shift16; + sse2_poly1305_blocks(st, final, 32); + } + + if (st->flags & poly1305_started) { + /* finalize, H *= [r^2,r], or H *= [r,1] */ + if (!leftover || (leftover > 16)) { + st->flags |= poly1305_final_r2_r; + } else { + st->flags |= poly1305_final_r_1; + } + sse2_poly1305_blocks(st, NULL, 32); + } + + h0 = st->H.h[0]; + h1 = st->H.h[1]; + h2 = st->H.h[2]; + + /* pad */ + h0 = ((h0) | (h1 << 44)); + h1 = ((h1 >> 20) | (h2 << 24)); +#ifdef HAVE_AMD64_ASM + __asm__ __volatile__( + "addq %2, %0 ;\n" + "adcq %3, %1 ;\n" + : "+r"(h0), "+r"(h1) + : "r"(st->pad[0]), "r"(st->pad[1]) + : "flags", "cc"); +#else + { + uint128_t h; + + memcpy(&h, &st->pad[0], 16); +#ifdef SQLITE3MC_POLY1305_HAVE_128BIT + uint128_t t; + t.lo = h0; + t.hi = h1; + h = u128_add(h, t); + h0 = u128_lo(h); + h1 = h.hi; +#else + h += ((uint128_t) h1 << 64) | h0; + h0 = (uint64_t) h; + h1 = (uint64_t)(h >> 64); +#endif + } +#endif + _mm_storeu_si128((xmmi *) (void *) st + 0, _mm_setzero_si128()); + _mm_storeu_si128((xmmi *) (void *) st + 1, _mm_setzero_si128()); + _mm_storeu_si128((xmmi *) (void *) st + 2, _mm_setzero_si128()); + _mm_storeu_si128((xmmi *) (void *) st + 3, _mm_setzero_si128()); + _mm_storeu_si128((xmmi *) (void *) st + 4, _mm_setzero_si128()); + _mm_storeu_si128((xmmi *) (void *) st + 5, _mm_setzero_si128()); + _mm_storeu_si128((xmmi *) (void *) st + 6, _mm_setzero_si128()); + _mm_storeu_si128((xmmi *) (void *) st + 7, _mm_setzero_si128()); + + memcpy(&mac[0], &h0, 8); + memcpy(&mac[8], &h1, 8); + + sodium_memzero((void *) st, sizeof *st); +} + +static void +sse2_poly1305_finish(sse2_poly1305_state_internal_t *st, unsigned char mac[16]) +{ + sse2_poly1305_finish_ext(st, st->buffer, st->leftover, mac); +} + +static int +crypto_onetimeauth_poly1305_sse2_init(crypto_onetimeauth_poly1305_state *state, + const unsigned char *key) +{ + COMPILER_ASSERT(sizeof(crypto_onetimeauth_poly1305_state) >= + sizeof(sse2_poly1305_state_internal_t)); + sse2_poly1305_init_ext((sse2_poly1305_state_internal_t *) (void *) state, key, 0U); + + return 0; +} + +static int +crypto_onetimeauth_poly1305_sse2_update( + crypto_onetimeauth_poly1305_state *state, const unsigned char *in, + unsigned long long inlen) +{ + sse2_poly1305_update((sse2_poly1305_state_internal_t *) (void *) state, in, inlen); + + return 0; +} + +static int +crypto_onetimeauth_poly1305_sse2_final(crypto_onetimeauth_poly1305_state *state, + unsigned char *out) +{ + sse2_poly1305_finish((sse2_poly1305_state_internal_t *) (void *) state, out); + + return 0; +} + +static int +crypto_onetimeauth_poly1305_sse2(unsigned char *out, const unsigned char *m, + unsigned long long inlen, + const unsigned char *key) +{ + CRYPTO_ALIGN(64) sse2_poly1305_state_internal_t st; + unsigned long long blocks; + + sse2_poly1305_init_ext(&st, key, inlen); + blocks = inlen & ~31; + if (blocks > 0) { + sse2_poly1305_blocks(&st, m, blocks); + m += blocks; + inlen -= blocks; + } + sse2_poly1305_finish_ext(&st, m, inlen, out); + + return 0; +} + +struct crypto_onetimeauth_poly1305_implementation + crypto_onetimeauth_poly1305_sse2_implementation = { + .onetimeauth = crypto_onetimeauth_poly1305_sse2, + .onetimeauth_init = crypto_onetimeauth_poly1305_sse2_init, + .onetimeauth_update = + crypto_onetimeauth_poly1305_sse2_update, + .onetimeauth_final = crypto_onetimeauth_poly1305_sse2_final + }; + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#undef poly1305_block_size + +#endif +#endif /* SQLITE3MC_TARGET_X86 */ +/*** End of #include "sse2/poly1305_sse2.c" ***/ + + +#endif +#endif +/*** End of #include "src/onetimeauth_poly1305.c" ***/ + + +#undef SODIUM_STATIC +#undef CRYPTO_ALIGN +/*** End of #include "chacha20/libchacha20.c" ***/ + + #if HAVE_CIPHER_CHACHA20 || HAVE_CIPHER_SQLCIPHER || HAVE_CIPHER_ASCON128 || HAVE_CIPHER_AEGIS /* #include "fastpbkdf2.c" */ /*** Begin of #include "fastpbkdf2.c" ***/ @@ -287596,6 +295457,9 @@ void sqlcipher_hmac(int algorithm, /* #include "sha2.h" */ +/* Defined in memory_secure.c */ +SQLITE_PRIVATE void sqlite3mcSecureZeroMemory(void* v, size_t n); + /* --- MSVC doesn't support C99 --- */ #if defined(_MSC_VER) && !defined(__clang__) #define restrict @@ -287751,7 +295615,10 @@ static inline void md_pad(uint8_t *block, size_t blocksz, size_t used, size_t ms /* And outer. */ \ _init(&ctx->outer); \ _update(&ctx->outer, blk_outer, sizeof blk_outer); \ + sqlite3mcSecureZeroMemory(blk_inner, sizeof blk_inner); \ + sqlite3mcSecureZeroMemory(blk_outer, sizeof blk_outer); \ } \ + sqlite3mcSecureZeroMemory(k, sizeof k); \ } \ \ static inline void HMAC_UPDATE(_name)(HMAC_CTX(_name) *ctx, \ @@ -287814,6 +295681,9 @@ static inline void md_pad(uint8_t *block, size_t blocksz, size_t used, size_t ms \ /* Reform result into output buffer. */ \ _xtract(&result, out); \ + sqlite3mcSecureZeroMemory(Ublock, sizeof Ublock); \ + sqlite3mcSecureZeroMemory(&ctx, sizeof ctx); \ + sqlite3mcSecureZeroMemory(&result, sizeof result); \ } \ \ static inline void PBKDF2(_name)(const uint8_t *pw, size_t npw, \ @@ -287844,7 +295714,9 @@ static inline void md_pad(uint8_t *block, size_t blocksz, size_t used, size_t ms offset = (counter - 1) * _hashsz; \ taken = MIN(nout - offset, _hashsz); \ memcpy(out + offset, block, taken); \ + sqlite3mcSecureZeroMemory(block, sizeof block); \ } \ + sqlite3mcSecureZeroMemory(&ctx, sizeof ctx); \ } static inline void sha1_extract(sha1_ctx *restrict ctx, uint8_t *restrict out) @@ -288027,6 +295899,7 @@ void sqlcipher_hmac(int algorithm, unsigned char* key, int nkey, unsigned char* HMAC_sha1_update(&hctx, in2, in2_sz); } HMAC_sha1_final(&hctx, out); + sqlite3mcSecureZeroMemory(&hctx, sizeof(hctx)); } break; @@ -288040,6 +295913,7 @@ void sqlcipher_hmac(int algorithm, unsigned char* key, int nkey, unsigned char* HMAC_sha256_update(&hctx, in2, in2_sz); } HMAC_sha256_final(&hctx, out); + sqlite3mcSecureZeroMemory(&hctx, sizeof(hctx)); } break; @@ -288054,6 +295928,7 @@ void sqlcipher_hmac(int algorithm, unsigned char* key, int nkey, unsigned char* HMAC_sha512_update(&hctx, in2, in2_sz); } HMAC_sha512_final(&hctx, out); + sqlite3mcSecureZeroMemory(&hctx, sizeof(hctx)); } break; } @@ -288061,11 +295936,403 @@ void sqlcipher_hmac(int algorithm, unsigned char* key, int nkey, unsigned char* /*** End of #include "fastpbkdf2.c" ***/ -/* Prototypes for several crypto functions to make pedantic compilers happy */ -SQLITE_PRIVATE void chacha20_xor(void* data, size_t n, const uint8_t key[32], const uint8_t nonce[12], uint32_t counter); -SQLITE_PRIVATE void poly1305(const uint8_t* msg, size_t n, const uint8_t key[32], uint8_t tag[16]); -SQLITE_PRIVATE int poly1305_tagcmp(const uint8_t tag1[16], const uint8_t tag2[16]); -SQLITE_PRIVATE void chacha20_rng(void* out, size_t n); +/* #include "csprng_entropy.c" */ +/*** Begin of #include "csprng_entropy.c" ***/ +/* +** This file contains the implementation for +** - retrieving entropy +** - random number generation +** +** The code was separated from the ChaCha20-Poly1305 implementation. +*/ + +/* #include "mystdint.h" */ + +#include + +/* + * Platform-specific entropy functions for seeding RNG + */ +#if defined(__wasm__) || defined(__wasi__) + +#if defined(__EMSCRIPTEN__) +#include + + /* Calls the Web Crypto API directly instead of relying on an opaque + * getentropy() shim whose actual backing implementation cannot be + * verified from the C side. crypto.getRandomValues() is capped at + * 65536 bytes per call, so large requests are chunked; not relevant + * for this generator's actual usage (32/12/24-byte reads), but kept + * for correctness if entropy() is ever called with a larger buffer. */ +EM_JS(int, wasm_crypto_getrandom, (uint8_t* buf, size_t n), +{ + if (typeof crypto === 'undefined' || !crypto.getRandomValues) + return -1; + try + { + var view = new Uint8Array(HEAPU8.buffer, buf, n); + var chunk = 65536; + for (var i = 0; i < n; i += chunk) + { + crypto.getRandomValues(view.subarray(i, Math.min(i + chunk, n))); + } + return 0; + } + catch (e) + { + return -1; + } +}); + +static size_t entropy(void* buf, size_t n) +{ + size_t i; + if (wasm_crypto_getrandom((uint8_t*)buf, n) != 0) + return 0; + /* Defense in depth: reject an all-zero result. */ + for (i = 0; i < n; i++) + { + if (((uint8_t*)buf)[i] != 0) + return n; + } + return (n == 0) ? n : 0; +} + +#elif defined(__wasi__) +#include + +static size_t entropy(void* buf, size_t n) +{ + size_t i; + if (__wasi_random_get((uint8_t*)buf, n) != __WASI_ERRNO_SUCCESS) + return 0; + for (i = 0; i < n; i++) + { + if (((uint8_t*)buf)[i] != 0) + return n; + } + return (n == 0) ? n : 0; +} +#else +extern int getentropy(void* buf, size_t n); + +static size_t entropy(void* buf, size_t n) +{ + size_t i; + if (getentropy(buf, n) != 0) + return 0; + for (i = 0; i < n; i++) + { + if (((uint8_t*)buf)[i] != 0) + return n; + } + return (n == 0) ? n : 0; +} +#endif + +#elif defined(_WIN32) || defined(__CYGWIN__) + +#if SQLITE3MC_USE_RAND_S + +/* Force header stdlib.h to define rand_s() */ +#if !defined(_CRT_RAND_S) +#define _CRT_RAND_S +#endif +#include + +/* + Provide declaration of rand_s() for MinGW-32 (not 64). + MinGW-32 didn't declare it prior to version 5.3.0. +*/ +#if defined(__MINGW32__) && defined(__MINGW32_VERSION) && __MINGW32_VERSION < 5003000L && !defined(__MINGW64_VERSION_MAJOR) +__declspec(dllimport) int rand_s(unsigned int *); +#endif + +static size_t entropy(void* buf, size_t n) +{ + size_t totalBytes = 0; + while (totalBytes < n) + { + unsigned int random32 = 0; + size_t j = 0; + + if (rand_s(&random32)) + { + /* rand_s failed */ + return 0; + } + + for (; (j < sizeof(random32)) && (totalBytes < n); j++, totalBytes++) + { + const uint8_t random8 = (uint8_t)(random32 >> (j * 8)); + ((uint8_t*) buf)[totalBytes] = random8; + } + } + return n; +} + +#else + +#include +#define RtlGenRandom SystemFunction036 +BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); +#pragma comment(lib, "advapi32.lib") +static size_t entropy(void* buf, size_t n) +{ + return RtlGenRandom(buf, (ULONG) n) ? n : 0; +} + +#endif + +#elif defined(__linux__) || defined(__unix__) || defined(__APPLE__) || defined(__QNX__) + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#include +/* musl does not have so let's define RNDGETENTCNT here */ +#ifndef RNDGETENTCNT +#define RNDGETENTCNT _IOR('R', 0x00, int) +#endif + +/* Waits until the kernel's random pool is initialized, as libsodium does */ +static int wait_for_random_pool(void) +{ + struct pollfd pfd; + int fd, ret; + + do + { + fd = open("/dev/random", O_RDONLY, 0); + } + while (fd == -1 && errno == EINTR); + if (fd == -1) + return 0; /* no /dev/random: don't block, like libsodium */ + + /* /dev/random becomes readable once the pool is initialized */ + pfd.fd = fd; + pfd.events = POLLIN; + pfd.revents = 0; + do + { + ret = poll(&pfd, 1, -1); + } + while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + close(fd); + return (ret == 1) ? 0 : -1; +} +#endif + +/* Returns 1 if all n bytes are zero */ +static int is_all_zero(const void* buf, size_t n) +{ + size_t i; + for (i = 0; i < n; i++) + { + if (((const uint8_t*) buf)[i] != 0) + return 0; + } + return 1; +} + +/* Returns the number of urandom bytes read (either 0 or n) */ +static size_t read_urandom(void* buf, size_t n) +{ + size_t i; + ssize_t ret; + int fd, count; + struct stat st; + int errnold = errno; + +#ifdef __linux__ + /* Unlike getrandom(), /dev/urandom does not wait for the pool */ + if (wait_for_random_pool() != 0) + goto fail; +#endif + + do + { + fd = open("/dev/urandom", O_RDONLY, 0); + } + while (fd == -1 && errno == EINTR); + if (fd == -1) + goto fail; + fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); + + /* Check the sanity of the device node */ + if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode) + #ifdef __linux__ + || ioctl(fd, RNDGETENTCNT, &count) == -1 + #endif + ) + { + close(fd); + goto fail; + } + + /* Read bytes */ + for (i = 0; i < n; i += ret) + { + while ((ret = read(fd, (char *)buf + i, n - i)) == -1) + { + if (errno != EAGAIN && errno != EINTR) + { + close(fd); + goto fail; + } + } + } + close(fd); + + /* Verify that the random device returned non-zero data */ + if (!is_all_zero(buf, n)) + { + errno = errnold; + return n; + } + + /* Tiny n may unintentionally fall through! */ +fail: + fprintf(stderr, "bad /dev/urandom RNG\n"); + abort(); /* PANIC! */ + return 0; +} + +#if defined(__APPLE__) + #if defined(__clang__) || defined(__GNUC__) + #if __has_include() + #include + #define HAVE_COMMONCRYPTO_COMMONRANDOM_H 1 + #endif + #endif +#endif + +#if defined(__linux__) && defined(SYS_getrandom) +/* Returns the number of getrandom() bytes read (either 0 or n) */ +static size_t read_getrandom(void* buf, size_t n) +{ + size_t i = 0; + int errnold = errno; + while (i < n) + { + long ret = syscall(SYS_getrandom, (char*) buf + i, n - i, 0); + if (ret > 0) + i += (size_t) ret; /* short read: continue */ + else if (ret != -1 || errno != EINTR) + break; /* interrupted: retry; any other error: give up */ + } + errno = errnold; + return (i == n) ? n : 0; +} +#endif + +static size_t entropy(void* buf, size_t n) +{ +#if defined(__APPLE__) && defined(HAVE_COMMONCRYPTO_COMMONRANDOM_H) + if (CCRandomGenerateBytes(buf, n) == kCCSuccess && !is_all_zero(buf, n)) + return n; +#elif defined(__linux__) && defined(SYS_getrandom) + if (read_getrandom(buf, n) == n && !is_all_zero(buf, n)) + return n; +#endif + return read_urandom(buf, n); +} + +#else +# error "Secure pseudorandom number generator not implemented for this OS" +#endif + +/* + * ChaCha20 random number generator with fast key erasure: each refill + * replaces the key with the first 32 bytes of new keystream. + */ +#define CHACHA20_RNG_RESEED_INTERVAL 16384 /* refills (3.5 MiB of output) */ + +SQLITE_PRIVATE +void chacha20_rng(void* out, size_t n) +{ + static uint8_t key[32], nonce[12], buffer[256] = { 0 }; + static uint32_t counter = 0; + static size_t available = 0; +#if !defined(_WIN32) && !defined(__wasm__) + static pid_t pid = 0; + pid_t currentPid = getpid(); +#endif +#if SQLITE_THREADSAFE + sqlite3_mutex* mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG); + sqlite3_mutex_enter(mutex); +#endif +#if !defined(_WIN32) && !defined(__wasm__) + /* + * Detect fork(): if the current process id differs from the pid + * recorded on the previous call, we are running in a freshly forked + * child that inherited the parent's generator state via copy-on-write + * memory -- the same key, nonce, counter, and any not-yet-consumed + * buffered keystream bytes. If left as-is, both parent and child would + * emit the identical keystream for every buffered/future byte until + * the next natural reseed, which is a nonce-reuse condition and + * breaks the security guarantees this generator is relied on for + * (e.g. per-page nonces). Forcing counter = 0 triggers a reseed from + * a fresh entropy() call on the next iteration, and clearing + * available discards any keystream bytes already buffered from the + * parent's state so they cannot be replayed in both processes. + * Not applicable on Windows, which has no fork() in the POSIX sense. + */ + if (currentPid != pid) + { + /* Fork detected (or first call): force a reseed and discard any + * buffered output that might otherwise be replayed in both + * parent and child. */ + pid = currentPid; + counter = 0; + available = 0; + } +#endif + + while (n > 0) + { + size_t m; + if (available == 0) + { + if (counter == 0) + { + if (entropy(key, sizeof(key)) != sizeof(key)) + abort(); + if (entropy(nonce, sizeof(nonce)) != sizeof(nonce)) + abort(); + } + memset(buffer, 0, sizeof(buffer)); + chacha20_xor(buffer, sizeof(buffer), key, nonce, 0); + /* The first 32 bytes become the next key */ + memcpy(key, buffer, sizeof(key)); + memset(buffer, 0, sizeof(key)); + available = sizeof(buffer) - sizeof(key); + counter = (counter + 1) % CHACHA20_RNG_RESEED_INTERVAL; + } + m = (available < n) ? available : n; + memcpy(out, buffer + (sizeof(buffer) - available), m); + /* Wipe handed-out bytes */ + memset(buffer + (sizeof(buffer) - available), 0, m); + out = (uint8_t*)out + m; + available -= m; + n -= m; + } + +#if SQLITE_THREADSAFE + sqlite3_mutex_leave(mutex); +#endif +} +/*** End of #include "csprng_entropy.c" ***/ /* #include "chacha20poly1305.c" */ /*** Begin of #include "chacha20poly1305.c" ***/ @@ -288085,12 +296352,37 @@ SQLITE_PRIVATE void chacha20_rng(void* out, size_t n); #define ROL32(x, c) (((x) << (c)) | ((x) >> (32-(c)))) #define ROR32(x, c) (((x) >> (c)) | ((x) << (32-(c)))) -#define LOAD32_LE(p) \ - ( ((uint32_t)((p)[0]) << 0) \ - | ((uint32_t)((p)[1]) << 8) \ - | ((uint32_t)((p)[2]) << 16) \ - | ((uint32_t)((p)[3]) << 24) \ - ) +static inline uint32_t load32_le_(const void* p) +{ +#if defined(__wasm__) || defined(_MSC_VER) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + uint32_t v; + memcpy(&v, p, 4); + return v; +#else + const uint8_t* b = (const uint8_t*)p; + return (uint32_t)b[0] + | (uint32_t)b[1] << 8 + | (uint32_t)b[2] << 16 + | (uint32_t)b[3] << 24; +#endif +} + +static inline void store32_le_(void* p, uint32_t v) +{ +#if defined(__wasm__) || defined(_MSC_VER) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + memcpy(p, &v, 4); +#else + uint8_t* b = (uint8_t*)p; + b[0] = (uint8_t)(v); + b[1] = (uint8_t)(v >> 8); + b[2] = (uint8_t)(v >> 16); + b[3] = (uint8_t)(v >> 24); +#endif +} + +#define LOAD32_LE(p) load32_le_(p) #define LOAD32_BE(p) \ ( ((uint32_t)((p)[3]) << 0) \ | ((uint32_t)((p)[2]) << 8) \ @@ -288098,11 +296390,7 @@ SQLITE_PRIVATE void chacha20_rng(void* out, size_t n); | ((uint32_t)((p)[0]) << 24) \ ) -#define STORE32_LE(p, v) \ - (p)[0] = ((v) >> 0) & 0xFF; \ - (p)[1] = ((v) >> 8) & 0xFF; \ - (p)[2] = ((v) >> 16) & 0xFF; \ - (p)[3] = ((v) >> 24) & 0xFF; +#define STORE32_LE(p, v) store32_le_((p), (v)) #define STORE32_BE(p, v) \ (p)[3] = ((v) >> 0) & 0xFF; \ (p)[2] = ((v) >> 8) & 0xFF; \ @@ -288147,8 +296435,8 @@ static void chacha20_block(uint32_t x[16]) } SQLITE_PRIVATE -void chacha20_xor(void* buffer, size_t n, const uint8_t key[32], - const uint8_t nonce[12], uint32_t counter) +void sqleet_chacha20_xor(void* buffer, size_t n, const uint8_t key[32], + const uint8_t nonce[12], uint32_t counter) { size_t i; union { @@ -288215,8 +296503,8 @@ void chacha20_xor(void* buffer, size_t n, const uint8_t key[32], * Poly1305 authentication tags */ SQLITE_PRIVATE -void poly1305(const uint8_t* msg, size_t n, const uint8_t key[32], - uint8_t tag[16]) +void sqleet_poly1305(const uint8_t* msg, size_t n, const uint8_t key[32], + uint8_t tag[16]) { uint64_t d0, d1, d2, d3, d4; uint32_t h0, h1, h2, h3, h4; @@ -288284,8 +296572,73 @@ void poly1305(const uint8_t* msg, size_t n, const uint8_t key[32], s4 = d4; STORE32_LE(tag + 12, s4); } +#if defined(SQLITE3MC_TARGET_X86) + +#include + +SQLITE3MC_FUNC_ISA("sse2") SQLITE_PRIVATE -int poly1305_tagcmp(const uint8_t tag1[16], const uint8_t tag2[16]) +int poly1305_tagcmp_sse2(const uint8_t tag1[16], const uint8_t tag2[16]) +{ + __m128i tag1_vec = _mm_loadu_si128((const __m128i*)tag1); + __m128i tag2_vec = _mm_loadu_si128((const __m128i*)tag2); + __m128i tagDifference = _mm_xor_si128(tag1_vec, tag2_vec); + + /* Horizontal OR-Reduktion der 128 Bit auf 32 Bit, + rein datenunabhängige Shift-/Or-Folge. */ + tagDifference = _mm_or_si128(tagDifference, _mm_srli_si128(tagDifference, 8)); + tagDifference = _mm_or_si128(tagDifference, _mm_srli_si128(tagDifference, 4)); + + return _mm_cvtsi128_si32(tagDifference) != 0; +} + +SQLITE3MC_FUNC_ISA("sse4.1") +SQLITE_PRIVATE +int poly1305_tagcmp_sse41(const uint8_t tag1[16], const uint8_t tag2[16]) +{ + __m128i tag1_vec = _mm_loadu_si128((const __m128i*)tag1); + __m128i tag2_vec = _mm_loadu_si128((const __m128i*)tag2); + __m128i tagDifference = _mm_xor_si128(tag1_vec, tag2_vec); + return !_mm_testz_si128(tagDifference, tagDifference); +} + +#elif defined(SQLITE3MC_TARGET_ARM64) + +# ifdef USE_ARM64_NEON_H +# include +# else +# include +# endif + +SQLITE_PRIVATE +int poly1305_tagcmp_neon(const uint8_t tag1[16], const uint8_t tag2[16]) +{ + uint8x16_t tag1_vec = vld1q_u8(tag1); + uint8x16_t tag2_vec = vld1q_u8(tag2); + uint8x16_t tagDifference = veorq_u8(tag1_vec, tag2_vec); + return vmaxvq_u8(tagDifference) != 0; +} + +#elif defined(SQLITE3MC_TARGET_WASM) + +#if defined(__wasm_simd128__) + +# include + +SQLITE_PRIVATE +int poly1305_tagcmp_wasm_simd(const uint8_t tag1[16], const uint8_t tag2[16]) +{ + v128_t tagDifference = + wasm_v128_xor(wasm_v128_load(tag1), wasm_v128_load(tag2)); + return wasm_v128_any_true(tagDifference); +} + +#endif + +#endif + +SQLITE_PRIVATE +int poly1305_tagcmp_scalar(const uint8_t tag1[16], const uint8_t tag2[16]) { uint8_t d = 0; d |= tag1[ 0] ^ tag2[ 0]; @@ -288308,220 +296661,170 @@ int poly1305_tagcmp(const uint8_t tag1[16], const uint8_t tag2[16]) } /* - * Platform-specific entropy functions for seeding RNG - */ -#if defined(__WASM__) +** Switching to "best" chacha20 implementation +*/ -extern int getentropy(void* buf, size_t n); +/* +** Use the smallest SQLite page size, 512 bytes, as threshold for activating hardware acceleration. +** Actually, the threshold should be at least 1024 bytes for AVX512. +*/ +#define CHACHA20_THRESHOLD 512 -static size_t entropy(void* buf, size_t n) +SQLITE_PRIVATE +void chacha20_xor(void* buffer, size_t n, const uint8_t key[32], + const uint8_t nonce[12], uint32_t counter) { - return (getentropy(buf, n) == 0) ? n : 0; + int rc = 0; + if (n >= CHACHA20_THRESHOLD && sqlite3mcChaCha20HwAccelerated()) + { + rc = crypto_stream_chacha20_ietf_xor_ic(buffer, buffer, n, nonce, counter, key); + } + else + { + sqleet_chacha20_xor(buffer, n, key, nonce, counter); + } } -#elif defined(_WIN32) || defined(__CYGWIN__) - -#if SQLITE3MC_USE_RAND_S - -/* Force header stdlib.h to define rand_s() */ -#if !defined(_CRT_RAND_S) -#define _CRT_RAND_S -#endif -#include - /* - Provide declaration of rand_s() for MinGW-32 (not 64). - MinGW-32 didn't declare it prior to version 5.3.0. +** Switching to "best" poly1305 implementation */ -#if defined(__MINGW32__) && defined(__MINGW32_VERSION) && __MINGW32_VERSION < 5003000L && !defined(__MINGW64_VERSION_MAJOR) -__declspec(dllimport) int rand_s(unsigned int *); -#endif -static size_t entropy(void* buf, size_t n) -{ - size_t totalBytes = 0; - while (totalBytes < n) - { - unsigned int random32 = 0; - size_t j = 0; +typedef void (*Poly1305_t)(const uint8_t* msg, size_t n, const uint8_t key[32], uint8_t tag[16]); +static Poly1305_t gPoly1305_impl = NULL; - if (rand_s(&random32)) - { - /* rand_s failed */ - return 0; - } +#if defined(SQLITE3MC_TARGET_X86) +#if defined(HAVE_TI_MODE) || defined(SQLITE3MC_POLY1305_HAVE_128BIT) - for (; (j < sizeof(random32)) && (totalBytes < n); j++, totalBytes++) - { - const uint8_t random8 = (uint8_t)(random32 >> (j * 8)); - ((uint8_t*) buf)[totalBytes] = random8; - } - } - return n; +SQLITE_PRIVATE +void sse2_poly1305(const uint8_t* msg, size_t n, const uint8_t key[32], uint8_t tag[16]) +{ + /* libsodium poly1305 with SSE2 */ + int rc = crypto_onetimeauth_poly1305_sse2(tag, msg, n, key); } -#else +#endif +#endif -#include -#define RtlGenRandom SystemFunction036 -BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); -#pragma comment(lib, "advapi32.lib") -static size_t entropy(void* buf, size_t n) +SQLITE_PRIVATE +void donna_poly1305(const uint8_t* msg, size_t n, const uint8_t key[32], uint8_t tag[16]) { - return RtlGenRandom(buf, (ULONG) n) ? n : 0; + /* libsodium poly1305 with donna code (64 / 32 bit arithmetic) */ + int rc = crypto_onetimeauth_poly1305_donna(tag, msg, n, key); } -#endif +static void poly1305_pick_best() +{ + unsigned int features = sqlite3mcCpuFeatures(); -#elif defined(__linux__) || defined(__unix__) || defined(__APPLE__) || defined(__QNX__) +#if defined(SQLITE3MC_TARGET_X86) -#ifndef _GNU_SOURCE -#define _GNU_SOURCE +#if defined(HAVE_TI_MODE) || defined(SQLITE3MC_POLY1305_HAVE_128BIT) + if (features & SQLITE3MC_CPU_SSE2) + { + gPoly1305_impl = &sse2_poly1305; + } + else #endif -#include -#include -#include -#include -#include -#include -#include + { +#if defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) + gPoly1305_impl = &donna_poly1305; +#else + gPoly1305_impl = &sqleet_poly1305; +#endif + } -#ifdef __linux__ -#include -/* musl does not have so let's define RNDGETENTCNT here */ -#ifndef RNDGETENTCNT -#define RNDGETENTCNT _IOR('R', 0x00, int) +#elif defined(SQLITE3MC_TARGET_ARM) + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) + gPoly1305_impl = &donna_poly1305; +#else + gPoly1305_impl = &sqleet_poly1305; #endif + +#elif defined(SQLITE3MC_TARGET_PPC) + +/* +** TODO: verify that libsodium's donna version works for PPC, +** because the implementation makes use of uint128_t. +*/ + +#if defined(_ARCH_PPC64) + gPoly1305_impl = &donna_poly1305; +#else + gPoly1305_impl = &sqleet_poly1305; #endif -/* Returns the number of urandom bytes read (either 0 or n) */ -static size_t read_urandom(void* buf, size_t n) -{ - size_t i; - ssize_t ret; - int fd, count; - struct stat st; - int errnold = errno; +#elif defined(SQLITE3MC_TARGET_WASM) - do - { - fd = open("/dev/urandom", O_RDONLY, 0); - } - while (fd == -1 && errno == EINTR); - if (fd == -1) - goto fail; - fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); + gPoly1305_impl = &sqleet_poly1305; - /* Check the sanity of the device node */ - if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode) - #ifdef __linux__ - || ioctl(fd, RNDGETENTCNT, &count) == -1 - #endif - ) - { - close(fd); - goto fail; - } +#else - /* Read bytes */ - for (i = 0; i < n; i += ret) - { - while ((ret = read(fd, (char *)buf + i, n - i)) == -1) - { - if (errno != EAGAIN && errno != EINTR) - { - close(fd); - goto fail; - } - } - } - close(fd); + gPoly1305_impl = &sqleet_poly1305; - /* Verify that the random device returned non-zero data */ - for (i = 0; i < n; i++) +#endif +} + +SQLITE_PRIVATE +void poly1305(const uint8_t* msg, size_t n, const uint8_t key[32], uint8_t tag[16]) +{ + if (gPoly1305_impl == NULL) { - if (((uint8_t*) buf)[i] != 0) - { - errno = errnold; - return n; - } + poly1305_pick_best(); } - - /* Tiny n may unintentionally fall through! */ -fail: - fprintf(stderr, "bad /dev/urandom RNG\n"); - abort(); /* PANIC! */ - return 0; + (gPoly1305_impl)(msg, n, key, tag); } -#if defined(__APPLE__) - #if defined(__clang__) || defined(__GNUC__) - #if __has_include() - #include - #define HAVE_COMMONCRYPTO_COMMONRANDOM_H 1 - #endif - #endif -#endif +/* +** Switching to "best" poly1305_tagcmp implementation +*/ -static size_t entropy(void* buf, size_t n) +typedef int (*Poly1305_TagCmp_t)(const uint8_t tag1[16], const uint8_t tag2[16]); +static Poly1305_TagCmp_t gPoly1305_tagcmp_impl = NULL; + +static void poly1305_tagcmp_pick_best() { -#if defined(__APPLE__) && defined(HAVE_COMMONCRYPTO_COMMONRANDOM_H) - if (CCRandomGenerateBytes(buf, n) == kCCSuccess) - return n; -#elif defined(__linux__) && defined(SYS_getrandom) - if (syscall(SYS_getrandom, buf, n, 0) == n) - return n; -#elif defined(__linux__) && defined(SYS_getentropy) - if (syscall(SYS_getentropy, buf, n) == 0) - return n; -#endif - return read_urandom(buf, n); -} + unsigned int features = sqlite3mcCpuFeatures(); + +#if defined(SQLITE3MC_TARGET_X86) + + if (features & SQLITE3MC_CPU_SSE41) + gPoly1305_tagcmp_impl = &poly1305_tagcmp_sse41; + else if (features & SQLITE3MC_CPU_SSE2) + gPoly1305_tagcmp_impl = &poly1305_tagcmp_sse2; + else + gPoly1305_tagcmp_impl = &poly1305_tagcmp_scalar; + +#elif defined(SQLITE3MC_TARGET_ARM64) + + if (features & SQLITE3MC_CPU_NEON) + gPoly1305_tagcmp_impl = &poly1305_tagcmp_neon; + else + gPoly1305_tagcmp_impl = &poly1305_tagcmp_scalar; + +#elif defined(SQLITE3MC_TARGET_WASM) +#if defined(__wasm_simd128__) + gPoly1305_tagcmp_impl = &poly1305_tagcmp_wasm_simd; #else -# error "Secure pseudorandom number generator not implemented for this OS" + gPoly1305_tagcmp_impl = &poly1305_tagcmp_scalar; #endif -/* - * ChaCha20 random number generator - */ -SQLITE_PRIVATE -void chacha20_rng(void* out, size_t n) -{ - static uint8_t key[32], nonce[12], buffer[64] = { 0 }; - static uint32_t counter = 0; - static size_t available = 0; +#else + + gPoly1305_tagcmp_impl = &poly1305_tagcmp_scalar; -#if SQLITE_THREADSAFE - sqlite3_mutex* mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG); - sqlite3_mutex_enter(mutex); #endif +} - while (n > 0) +SQLITE_PRIVATE +int poly1305_tagcmp(const uint8_t tag1[16], const uint8_t tag2[16]) +{ + if (gPoly1305_tagcmp_impl == NULL) { - size_t m; - if (available == 0) - { - if (counter == 0) - { - if (entropy(key, sizeof(key)) != sizeof(key)) - abort(); - if (entropy(nonce, sizeof(nonce)) != sizeof(nonce)) - abort(); - } - chacha20_xor(buffer, sizeof(buffer), key, nonce, counter++); - available = sizeof(buffer); - } - m = (available < n) ? available : n; - memcpy(out, buffer + (sizeof(buffer) - available), m); - out = (uint8_t*)out + m; - available -= m; - n -= m; + poly1305_tagcmp_pick_best(); } - -#if SQLITE_THREADSAFE - sqlite3_mutex_leave(mutex); -#endif + return (gPoly1305_tagcmp_impl)(tag1, tag2); } /*** End of #include "chacha20poly1305.c" ***/ @@ -288835,80 +297138,6 @@ SQLITE_PRIVATE void RijndaelDecrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16] ** License: MIT */ -/* -** Check whether the platform offers hardware support for AES -*/ - -#define AES_HARDWARE_NONE 0 -#define AES_HARDWARE_NI 1 -#define AES_HARDWARE_NEON 2 - -#ifndef SQLITE3MC_OMIT_AES_HARDWARE_SUPPORT - -#if defined __ARM_FEATURE_CRYPTO -#define HAS_AES_HARDWARE AES_HARDWARE_NEON - - -/* --- CLang --- */ -#elif defined(__clang__) - -#if __has_attribute(target) && __has_include() && (defined(__x86_64__) || defined(__i386)) -#define HAS_AES_HARDWARE AES_HARDWARE_NI - -#elif __has_attribute(target) && __has_include() && (defined(__aarch64__)) -#define HAS_AES_HARDWARE AES_HARDWARE_NEON - -/* Crypto extension in AArch64 can be enabled using __attribute__((target)) */ -#define USE_CLANG_ATTR_TARGET_AARCH64 - -#endif - - -/* --- GNU C/C++ */ -#elif defined(__GNUC__) - -#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) && (defined(__x86_64__) || defined(__i386)) -#define HAS_AES_HARDWARE AES_HARDWARE_NI -#endif - - -/* --- Visual C/C++ --- */ -#elif defined (_MSC_VER) - -/* Architecture: x86 or x86_64 */ -#if (defined(_M_X64) || defined(_M_IX86)) && _MSC_FULL_VER >= 150030729 -#define HAS_AES_HARDWARE AES_HARDWARE_NI - -/* Architecture: ARM 64-bit */ -#elif defined(_M_ARM64) -#define HAS_AES_HARDWARE AES_HARDWARE_NEON - -/* Use header instead of */ -#define USE_ARM64_NEON_H - -/* Architecture: ARM 32-bit */ -#elif defined _M_ARM -#define HAS_AES_HARDWARE AES_HARDWARE_NEON - -/* The following #define is required to enable intrinsic definitions - that do not omit one of the parameters for vaes[ed]q_u8 */ -#define _ARM_USE_NEW_NEON_INTRINSICS - -#endif - -#else - -#define HAS_AES_HARDWARE AES_HARDWARE_NONE - -#endif - -#else /* SQLITE3MC_OMIT_AES_HARDWARE_SUPPORT defined */ - -/* Omit AES hardware support */ -#define HAS_AES_HARDWARE AES_HARDWARE_NONE - -#endif /* SQLITE3MC_OMIT_AES_HARDWARE_SUPPORT */ - #if defined(__GNUC__) #pragma GCC push_options #endif @@ -288935,70 +297164,6 @@ toUint32FromLE(const void* buffer) #if HAS_AES_HARDWARE == AES_HARDWARE_NI /* --- Implementation for AES-NI --- */ -/* Define SQLITE3MC_COMPILER_HAS_ATTRIBUTE */ -#if defined(__has_attribute) - #define SQLITE3MC_COMPILER_HAS_ATTRIBUTE(x) __has_attribute(x) - #define SQLITE3MC_COMPILER_ATTRIBUTE(x) __attribute__((x)) -#else - #define SQLITE3MC_COMPILER_HAS_ATTRIBUTE(x) 0 - #define SQLITE3MC_COMPILER_ATTRIBUTE(x) /**/ -#endif - -/* Define SQLITE3MC_FORCE_INLINE */ -#if !defined(SQLITE3MC_FORCE_INLINE) - #if SQLITE3MC_COMPILER_HAS_ATTRIBUTE(always_inline) - #define SQLITE3MC_FORCE_INLINE inline SQLITE3MC_COMPILER_ATTRIBUTE(always_inline) - #elif defined(_MSC_VER) - #define SQLITE3MC_FORCE_INLINE __forceinline - #else - #define SQLITE3MC_FORCE_INLINE inline - #endif -#endif - -/* Define SQLITE3MC_FUNC_ISA */ -#if SQLITE3MC_COMPILER_HAS_ATTRIBUTE(target) - #define SQLITE3MC_FUNC_ISA(isa) SQLITE3MC_COMPILER_ATTRIBUTE(target(isa)) -#else - #define SQLITE3MC_FUNC_ISA(isa) -#endif - -/* Define SQLITE3MC_FUNC_ISA_INLINE */ -#define SQLITE3MC_FUNC_ISA_INLINE(isa) SQLITE3MC_FUNC_ISA(isa) SQLITE3MC_FORCE_INLINE - - -/* -** Define function for detecting hardware AES support at runtime -*/ - -#if defined(__clang__) || defined(__GNUC__) -/* Compiler CLang or GCC */ - -#include - -static int -aesHardwareCheck() -{ - unsigned int cpuInfo[4]; - __cpuid(1, cpuInfo[0], cpuInfo[1], cpuInfo[2], cpuInfo[3]); - /* Check AES and SSE4.1 */ - return (cpuInfo[2] & (1 << 25)) != 0 && (cpuInfo[2] & (1 << 19)) != 0; -} - -#else /* !(defined(__clang__) || defined(__GNUC__)) */ -/* Compiler Visual C++ */ - -#include - -static int -aesHardwareCheck() -{ - unsigned int CPUInfo[4]; - __cpuid((int*) CPUInfo, 1); - return (CPUInfo[2] & (1 << 25)) != 0 && (CPUInfo[2] & (1 << 19)) != 0; /* Check AES and SSE4.1 */ -} - -#endif /* defined(__clang__) || defined(__GNUC__) */ - #if defined(__GNUC__) #pragma GCC push_options #endif @@ -289282,12 +297447,12 @@ aesDecryptCBC(const unsigned char* in, /* --- Implementation for AES-NEON --- */ /* Set target architecture manually, if necessary */ -#ifdef USE_CLANG_ATTR_TARGET_AARCH64 +#ifdef USE_ATTR_TARGET_AARCH64 #define __ARM_NEON 1 #define __ARM_FEATURE_CRYPTO 1 #define __ARM_FEATURE_AES 1 -#define FUNC_ISA __attribute__ ((target("neon,crypto"))) -#endif /* USE_CLANG_ATTR_TARGET_AARCH64 */ +#define FUNC_ISA __attribute__ ((target("+crypto"))) +#endif /* USE_ATTR_TARGET_AARCH64 */ /* FUNCtion attributes for ISA (Instruction Set Architecture) */ #ifndef FUNC_ISA @@ -289300,47 +297465,6 @@ aesDecryptCBC(const unsigned char* in, #include #endif -#if defined(__linux__) && (defined(__arm__) || defined(__aarch64__)) - -#include -#include - -static int -aesHardwareAvailableOnPlatform() -{ -#if defined HWCAP_AES - return getauxval(AT_HWCAP) & HWCAP_AES; -#elif defined HWCAP2_AES - return getauxval(AT_HWCAP2) & HWCAP2_AES; -#else - return 0; -#endif -} - -#elif defined _M_ARM || defined _M_ARM64 - -static int -aesHardwareAvailableOnPlatform() -{ - return (int) IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); -} - -#else - -static int -aesHardwareAvailableOnPlatform() -{ - return 0; -} - -#endif - -static int -aesHardwareCheck() -{ - return aesHardwareAvailableOnPlatform(); -} - /* ** Set up expanded key */ @@ -289631,34 +297755,11 @@ aesDecryptCBC(const unsigned char* in, #else /* --- No AES hardware available --- */ -static int -aesHardwareCheck() -{ - return 0; -} - #endif #if defined(__GNUC__) #pragma GCC pop_options #endif - -/* -** The top-level selection function, caching the results of -** aesHardwareCheck() so it only has to run once. -*/ -static int -aesHardwareAvailable() -{ - static int initialized = 0; - static int hwAvailable = 0; - if (!initialized) - { - hwAvailable = aesHardwareCheck(); - initialized = 1; - } - return hwAvailable; -} /*** End of #include "aes_hardware.c" ***/ @@ -333627,8 +341728,6 @@ SQLITE_PRIVATE int sqlite3mcCodecAttach(sqlite3* db, int nDb, const char* zPath, SQLITE_PRIVATE void sqlite3mcCodecGetKey(sqlite3* db, int nDb, void** zKey, int* nKey); -SQLITE_PRIVATE void sqlite3mcSecureZeroMemory(void* v, size_t n); - /* Debugging */ #if 0 @@ -334692,7 +342791,7 @@ GenerateKeyChaCha20Cipher(void* cipher, char* userPassword, int passwordLength, { ChaCha20Cipher* chacha20Cipher = (ChaCha20Cipher*) cipher; - int keyOnly = 1; + int keyOnly = 0; if (rekey == 2) { /* (rekey == 2) means database is in WAL mode, thus don't change the cipher salt */ @@ -334732,7 +342831,7 @@ EncryptPageChaCha20Cipher(void* cipher, int page, unsigned char* data, int len, ChaCha20Cipher* chacha20Cipher = (ChaCha20Cipher*) cipher; int rc = SQLITE_OK; int legacy = chacha20Cipher->m_legacy; - int nReserved = (reserved == 0 && legacy == 0) ? 0 : GetReservedChaCha20Cipher(cipher); + int nReserved = GetReservedChaCha20Cipher(cipher); int n = len - nReserved; int usePlaintextHeader = 0; @@ -334758,42 +342857,23 @@ EncryptPageChaCha20Cipher(void* cipher, int page, unsigned char* data, int len, } /* Check whether number of required reserved bytes and actually reserved bytes match */ - if ((legacy == 0 && nReserved > reserved) || ((legacy != 0 && nReserved != reserved))) + if (nReserved != reserved) { return SQLITE_CORRUPT; } - if (nReserved > 0) - { - /* Encrypt and authenticate */ - memset(otk, 0, OTK_LEN_CHACHA20); - chacha20_rng(data + n, PAGE_NONCE_LEN_CHACHA20); - counter = LOAD32_LE(data + n + PAGE_NONCE_LEN_CHACHA20 - 4) ^ page; - chacha20_xor(otk, OTK_LEN_CHACHA20, chacha20Cipher->m_key, data + n, counter); + /* Encrypt and authenticate */ + memset(otk, 0, OTK_LEN_CHACHA20); + chacha20_rng(data + n, PAGE_NONCE_LEN_CHACHA20); + counter = LOAD32_LE(data + n + PAGE_NONCE_LEN_CHACHA20 - 4) ^ page; + chacha20_xor(otk, OTK_LEN_CHACHA20, chacha20Cipher->m_key, data + n, counter); - chacha20_xor(data + offset, n - offset, otk + 32, data + n, counter + 1); - if (page == 1 && usePlaintextHeader == 0) - { - memcpy(data, chacha20Cipher->m_salt, SALTLENGTH_CHACHA20); - } - poly1305(data, n + PAGE_NONCE_LEN_CHACHA20, otk, data + n + PAGE_NONCE_LEN_CHACHA20); - } - else + chacha20_xor(data + offset, n - offset, otk + 32, data + n, counter + 1); + if (page == 1 && usePlaintextHeader == 0) { - /* Encrypt only */ - uint8_t nonce[PAGE_NONCE_LEN_CHACHA20]; - memset(otk, 0, OTK_LEN_CHACHA20); - sqlite3mcGenerateInitialVector(page, nonce); - counter = LOAD32_LE(&nonce[PAGE_NONCE_LEN_CHACHA20 - 4]) ^ page; - chacha20_xor(otk, OTK_LEN_CHACHA20, chacha20Cipher->m_key, nonce, counter); - - /* Encrypt */ - chacha20_xor(data + offset, n - offset, otk + 32, nonce, counter + 1); - if (page == 1 && usePlaintextHeader == 0) - { - memcpy(data, chacha20Cipher->m_salt, SALTLENGTH_CHACHA20); - } + memcpy(data, chacha20Cipher->m_salt, SALTLENGTH_CHACHA20); } + poly1305(data, n + PAGE_NONCE_LEN_CHACHA20, otk, data + n + PAGE_NONCE_LEN_CHACHA20); /* Zero out otk array */ sqlite3mcSecureZeroMemory(otk, OTK_LEN_CHACHA20); @@ -334820,7 +342900,7 @@ DecryptPageChaCha20Cipher(void* cipher, int page, unsigned char* data, int len, ChaCha20Cipher* chacha20Cipher = (ChaCha20Cipher*) cipher; int rc = SQLITE_OK; int legacy = chacha20Cipher->m_legacy; - int nReserved = (reserved == 0 && legacy == 0) ? 0 : GetReservedChaCha20Cipher(cipher); + int nReserved = GetReservedChaCha20Cipher(cipher); int n = len - nReserved; int usePlaintextHeader = 0; @@ -334847,57 +342927,39 @@ DecryptPageChaCha20Cipher(void* cipher, int page, unsigned char* data, int len, } /* Check whether number of required reserved bytes and actually reserved bytes match */ - if ((legacy == 0 && nReserved > reserved) || ((legacy != 0 && nReserved != reserved))) + if (nReserved != reserved) { return (page == 1) ? SQLITE_NOTADB : SQLITE_CORRUPT; } - if (nReserved > 0) - { - int allzero = 0; - /* Decrypt and verify MAC */ - memset(otk, 0, OTK_LEN_CHACHA20); - counter = LOAD32_LE(data + n + PAGE_NONCE_LEN_CHACHA20 - 4) ^ page; - chacha20_xor(otk, OTK_LEN_CHACHA20, chacha20Cipher->m_key, data + n, counter); - - /* Determine MAC and decrypt */ - allzero = chacha20_ismemset(data, 0, n); - poly1305(data, n + PAGE_NONCE_LEN_CHACHA20, otk, tag); - chacha20_xor(data + offset, n - offset, otk + 32, data + n, counter + 1); + /* Determine and verify MAC */ + memset(otk, 0, OTK_LEN_CHACHA20); + counter = LOAD32_LE(data + n + PAGE_NONCE_LEN_CHACHA20 - 4) ^ page; + chacha20_xor(otk, OTK_LEN_CHACHA20, chacha20Cipher->m_key, data + n, counter); - if (hmacCheck != 0) - { - /* Verify the MAC */ - if (poly1305_tagcmp(data + n + PAGE_NONCE_LEN_CHACHA20, tag)) - { - SQLITE3MC_DEBUG_LOG("decrypt: codec=%p page=%d\n", chacha20Cipher, page); - SQLITE3MC_DEBUG_HEX("decrypt key:", chacha20Cipher->m_key, 32); - SQLITE3MC_DEBUG_HEX("decrypt otk:", otk, OTK_LEN_CHACHA20); - SQLITE3MC_DEBUG_HEX("decrypt data+00:", data, 16); - SQLITE3MC_DEBUG_HEX("decrypt data+24:", data + 24, 16); - SQLITE3MC_DEBUG_HEX("decrypt data+n:", data + n, 16); - SQLITE3MC_DEBUG_HEX("decrypt tag r:", data + n + PAGE_NONCE_LEN_CHACHA20, PAGE_TAG_LEN_CHACHA20); - SQLITE3MC_DEBUG_HEX("decrypt tag c:", tag, PAGE_TAG_LEN_CHACHA20); - /* Bad MAC */ - rc = (page == 1) ? SQLITE_NOTADB : SQLITE_CORRUPT; - } - } - if (page == 1 && usePlaintextHeader == 0 && rc == SQLITE_OK) + poly1305(data, n + PAGE_NONCE_LEN_CHACHA20, otk, tag); + if (hmacCheck != 0) + { + /* Verify the MAC */ + if (poly1305_tagcmp(data + n + PAGE_NONCE_LEN_CHACHA20, tag)) { - memcpy(data, SQLITE_FILE_HEADER, 16); + SQLITE3MC_DEBUG_LOG("decrypt: codec=%p page=%d\n", chacha20Cipher, page); + SQLITE3MC_DEBUG_HEX("decrypt key:", chacha20Cipher->m_key, 32); + SQLITE3MC_DEBUG_HEX("decrypt otk:", otk, OTK_LEN_CHACHA20); + SQLITE3MC_DEBUG_HEX("decrypt data+00:", data, 16); + SQLITE3MC_DEBUG_HEX("decrypt data+24:", data + 24, 16); + SQLITE3MC_DEBUG_HEX("decrypt data+n:", data + n, 16); + SQLITE3MC_DEBUG_HEX("decrypt tag r:", data + n + PAGE_NONCE_LEN_CHACHA20, PAGE_TAG_LEN_CHACHA20); + SQLITE3MC_DEBUG_HEX("decrypt tag c:", tag, PAGE_TAG_LEN_CHACHA20); + /* Bad MAC */ + rc = (page == 1) ? SQLITE_NOTADB : SQLITE_CORRUPT; } } - else + + /* Decrypt only after MAC is verified (or if check is bypassed). */ + if (rc == SQLITE_OK) { - /* Decrypt only */ - uint8_t nonce[PAGE_NONCE_LEN_CHACHA20]; - memset(otk, 0, OTK_LEN_CHACHA20); - sqlite3mcGenerateInitialVector(page, nonce); - counter = LOAD32_LE(&nonce[PAGE_NONCE_LEN_CHACHA20 - 4]) ^ page; - chacha20_xor(otk, OTK_LEN_CHACHA20, chacha20Cipher->m_key, nonce, counter); - - /* Decrypt */ - chacha20_xor(data + offset, n - offset, otk + 32, nonce, counter + 1); + chacha20_xor(data + offset, n - offset, otk + 32, data + n, counter + 1); if (page == 1 && usePlaintextHeader == 0) { memcpy(data, SQLITE_FILE_HEADER, 16); @@ -335175,7 +343237,7 @@ GenerateKeySQLCipherCipher(void* cipher, char* userPassword, int passwordLength, { SQLCipherCipher* sqlCipherCipher = (SQLCipherCipher*) cipher; - int keyOnly = 1; + int keyOnly = 0; if (rekey == 2) { /* (rekey == 2) means database is in WAL mode, thus don't change the cipher salt */ @@ -335279,13 +343341,30 @@ GetHmacSizeSQLCipherCipher(int algorithm) return hmacSize; } +/* +** Compare two HMAC values in constant time, that is, without revealing +** the position of the first differing byte through the execution time. +** Returns 0 if both values are equal, 1 otherwise. +*/ +static int +CompareHmacSQLCipherCipher(const unsigned char* hmac1, const unsigned char* hmac2, int len) +{ + volatile unsigned char diff = 0; + int j; + for (j = 0; j < len; ++j) + { + diff |= hmac1[j] ^ hmac2[j]; + } + return (diff != 0); +} + static int EncryptPageSQLCipherCipher(void* cipher, int page, unsigned char* data, int len, int reserved) { SQLCipherCipher* sqlCipherCipher = (SQLCipherCipher*) cipher; int rc = SQLITE_OK; int legacy = sqlCipherCipher->m_legacy; - int nReserved = (reserved == 0 && legacy == 0) ? 0 : GetReservedSQLCipherCipher(cipher); + int nReserved = GetReservedSQLCipherCipher(cipher); int n = len - nReserved; int offset = 0; int blen; @@ -335311,28 +343390,18 @@ EncryptPageSQLCipherCipher(void* cipher, int page, unsigned char* data, int len, } /* Check whether number of required reserved bytes and actually reserved bytes match */ - if ((legacy == 0 && nReserved > reserved) || ((legacy != 0 && nReserved != reserved))) + if (nReserved != reserved) { return SQLITE_CORRUPT; } /* Generate nonce (64 bytes) */ memset(iv, 0, 128); - if (nReserved > 0) - { - chacha20_rng(iv, 128); - } - else - { - sqlite3mcGenerateInitialVector(page, iv); - } + chacha20_rng(iv, 128); RijndaelInit(sqlCipherCipher->m_aes, RIJNDAEL_Direction_Mode_CBC, RIJNDAEL_Direction_Encrypt, sqlCipherCipher->m_key, RIJNDAEL_Direction_KeyLength_Key32Bytes, iv); blen = RijndaelBlockEncrypt(sqlCipherCipher->m_aes, data + offset, (n - offset) * 8, data + offset); - if (nReserved > 0) - { - memcpy(data + n, iv, nReserved); - } + memcpy(data + n, iv, nReserved); if (page == 1 && usePlaintextHeader == 0) { memcpy(data, sqlCipherCipher->m_salt, SALTLENGTH_SQLCIPHER); @@ -335370,7 +343439,7 @@ DecryptPageSQLCipherCipher(void* cipher, int page, unsigned char* data, int len, SQLCipherCipher* sqlCipherCipher = (SQLCipherCipher*) cipher; int rc = SQLITE_OK; int legacy = sqlCipherCipher->m_legacy; - int nReserved = (reserved == 0 && legacy == 0) ? 0 : GetReservedSQLCipherCipher(cipher); + int nReserved = GetReservedSQLCipherCipher(cipher); int n = len - nReserved; int offset = 0; int hmacOk = 1; @@ -335397,20 +343466,13 @@ DecryptPageSQLCipherCipher(void* cipher, int page, unsigned char* data, int len, } /* Check whether number of required reserved bytes and actually reserved bytes match */ - if ((legacy == 0 && nReserved > reserved) || ((legacy != 0 && nReserved != reserved))) + if (nReserved != reserved) { return (page == 1) ? SQLITE_NOTADB : SQLITE_CORRUPT; } /* Get nonce from buffer */ - if (nReserved > 0) - { - memcpy(iv, data + n, nReserved); - } - else - { - sqlite3mcGenerateInitialVector(page, iv); - } + memcpy(iv, data + n, nReserved); /* hmac check */ if (sqlCipherCipher->m_hmacUse == 1 && nReserved > 0 && hmacCheck != 0) @@ -335431,7 +343493,7 @@ DecryptPageSQLCipherCipher(void* cipher, int page, unsigned char* data, int len, memcpy(pgno_raw, &page, 4); } sqlcipher_hmac(sqlCipherCipher->m_hmacAlgorithm, sqlCipherCipher->m_hmacKey, KEYLENGTH_SQLCIPHER, data + offset, n + PAGE_NONCE_LEN_SQLCIPHER - offset, pgno_raw, 4, hmac_out); - hmacOk = (memcmp(data + n + PAGE_NONCE_LEN_SQLCIPHER, hmac_out, hmac_size) == 0); + hmacOk = (CompareHmacSQLCipherCipher(data + n + PAGE_NONCE_LEN_SQLCIPHER, hmac_out, hmac_size) == 0); } if (hmacOk != 0) @@ -337053,7 +345115,7 @@ GenerateKeyAscon128Cipher(void* cipher, char* userPassword, int passwordLength, { Ascon128Cipher* ascon128Cipher = (Ascon128Cipher*) cipher; - int keyOnly = 1; + int keyOnly = 0; if (rekey == 2) { /* (rekey == 2) means database is in WAL mode, thus don't change the cipher salt */ @@ -337106,7 +345168,7 @@ EncryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len, { Ascon128Cipher* ascon128Cipher = (Ascon128Cipher*) cipher; int rc = SQLITE_OK; - int nReserved = (reserved == 0) ? 0 : GetReservedAscon128Cipher(cipher); + int nReserved = GetReservedAscon128Cipher(cipher); int n = len - nReserved; uint64_t mlen = n; int usePlaintextHeader = 0; @@ -337131,45 +345193,23 @@ EncryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len, } /* Check whether number of required reserved bytes and actually reserved bytes match */ - if (nReserved > reserved) + if (nReserved != reserved) { return SQLITE_CORRUPT; } - if (nReserved > 0) - { - /* Encrypt and authenticate */ - memset(otk, 0, ASCON_HASH_BYTES); - /* Generate nonce */ - chacha20_rng(data + n + PAGE_TAG_LEN_ASCON128, PAGE_NONCE_LEN_ASCON128); - AsconGenOtk(otk, ascon128Cipher->m_key, data + n + PAGE_TAG_LEN_ASCON128, page); - - ascon_aead_encrypt(data + offset, data + n, data + offset, mlen - offset, - NULL /* ad */, 0 /* adlen*/, - data + n + PAGE_TAG_LEN_ASCON128, otk); - if (page == 1 && usePlaintextHeader == 0) - { - memcpy(data, ascon128Cipher->m_salt, SALTLENGTH_ASCON128); - } - } - else + /* Encrypt and authenticate */ + memset(otk, 0, ASCON_HASH_BYTES); + /* Generate nonce */ + chacha20_rng(data + n + PAGE_TAG_LEN_ASCON128, PAGE_NONCE_LEN_ASCON128); + AsconGenOtk(otk, ascon128Cipher->m_key, data + n + PAGE_TAG_LEN_ASCON128, page); + + ascon_aead_encrypt(data + offset, data + n, data + offset, mlen - offset, + NULL /* ad */, 0 /* adlen*/, + data + n + PAGE_TAG_LEN_ASCON128, otk); + if (page == 1 && usePlaintextHeader == 0) { - /* Encrypt only */ - uint8_t nonce[PAGE_NONCE_LEN_ASCON128]; - uint8_t dummyTag[PAGE_TAG_LEN_ASCON128]; - memset(dummyTag, 0, PAGE_TAG_LEN_ASCON128); - memset(otk, 0, ASCON_HASH_BYTES); - sqlite3mcGenerateInitialVector(page, nonce); - AsconGenOtk(otk, ascon128Cipher->m_key, nonce, page); - - /* Encrypt */ - ascon_aead_encrypt(data + offset, dummyTag, data + offset, mlen - offset, - NULL /* ad */, 0 /* adlen*/, - nonce, otk); - if (page == 1 && usePlaintextHeader == 0) - { - memcpy(data, ascon128Cipher->m_salt, SALTLENGTH_ASCON128); - } + memcpy(data, ascon128Cipher->m_salt, SALTLENGTH_ASCON128); } /* Zero out otk array */ @@ -337183,7 +345223,7 @@ DecryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len, { Ascon128Cipher* ascon128Cipher = (Ascon128Cipher*) cipher; int rc = SQLITE_OK; - int nReserved = (reserved == 0) ? 0 : GetReservedAscon128Cipher(cipher); + int nReserved = GetReservedAscon128Cipher(cipher); int n = len - nReserved; uint64_t clen = n; int tagOk; @@ -337209,61 +345249,39 @@ DecryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len, } /* Check whether number of required reserved bytes and actually reserved bytes match */ - if (nReserved > reserved) + if (nReserved != reserved) { return (page == 1) ? SQLITE_NOTADB : SQLITE_CORRUPT; } - if (nReserved > 0) + /* Decrypt and verify MAC */ + memset(otk, 0, ASCON_HASH_BYTES); + AsconGenOtk(otk, ascon128Cipher->m_key, data + n + PAGE_TAG_LEN_ASCON128, page); + + /* Determine MAC and decrypt */ + tagOk = ascon_aead_decrypt(data + offset, data + offset, clen - offset, + NULL /* ad */, 0 /* adlen */, + data + n, data + n + PAGE_TAG_LEN_ASCON128, otk); + if (hmacCheck != 0) { - /* Decrypt and verify MAC */ - memset(otk, 0, ASCON_HASH_BYTES); - AsconGenOtk(otk, ascon128Cipher->m_key, data + n + PAGE_TAG_LEN_ASCON128, page); - - /* Determine MAC and decrypt */ - tagOk = ascon_aead_decrypt(data + offset, data + offset, clen - offset, - NULL /* ad */, 0 /* adlen */, - data + n, data + n + PAGE_TAG_LEN_ASCON128, otk); - if (hmacCheck != 0) + /* Verify the MAC */ + if (tagOk != 0) { - /* Verify the MAC */ - if (tagOk != 0) - { - SQLITE3MC_DEBUG_LOG("decrypt: codec=%p page=%d\n", ascon128Cipher, page); - SQLITE3MC_DEBUG_HEX("decrypt key:", ascon128Cipher->m_key, 32); - SQLITE3MC_DEBUG_HEX("decrypt otk:", otk, 64); - SQLITE3MC_DEBUG_HEX("decrypt data+00:", data, 16); - SQLITE3MC_DEBUG_HEX("decrypt data+24:", data + 24, 16); - SQLITE3MC_DEBUG_HEX("decrypt data+n:", data + n, 16); - SQLITE3MC_DEBUG_HEX("decrypt tag r:", data + n + PAGE_NONCE_LEN_ASCON128, PAGE_TAG_LEN_ASCON128); - SQLITE3MC_DEBUG_HEX("decrypt tag c:", tag, PAGE_TAG_LEN_ASCON128); - /* Bad MAC */ - rc = (page == 1) ? SQLITE_NOTADB : SQLITE_CORRUPT; - } - } - if (page == 1 && usePlaintextHeader == 0 && rc == SQLITE_OK) - { - memcpy(data, SQLITE_FILE_HEADER, 16); - } - } - else + SQLITE3MC_DEBUG_LOG("decrypt: codec=%p page=%d\n", ascon128Cipher, page); + SQLITE3MC_DEBUG_HEX("decrypt key:", ascon128Cipher->m_key, 32); + SQLITE3MC_DEBUG_HEX("decrypt otk:", otk, 64); + SQLITE3MC_DEBUG_HEX("decrypt data+00:", data, 16); + SQLITE3MC_DEBUG_HEX("decrypt data+24:", data + 24, 16); + SQLITE3MC_DEBUG_HEX("decrypt data+n:", data + n, 16); + SQLITE3MC_DEBUG_HEX("decrypt tag r:", data + n + PAGE_NONCE_LEN_ASCON128, PAGE_TAG_LEN_ASCON128); + SQLITE3MC_DEBUG_HEX("decrypt tag c:", tag, PAGE_TAG_LEN_ASCON128); + /* Bad MAC */ + rc = (page == 1) ? SQLITE_NOTADB : SQLITE_CORRUPT; + } + } + if (page == 1 && usePlaintextHeader == 0 && rc == SQLITE_OK) { - /* Decrypt only */ - uint8_t nonce[PAGE_NONCE_LEN_ASCON128]; - uint8_t dummyTag[PAGE_TAG_LEN_ASCON128]; - memset(dummyTag, 0, PAGE_TAG_LEN_ASCON128); - memset(otk, 0, ASCON_HASH_BYTES); - sqlite3mcGenerateInitialVector(page, nonce); - AsconGenOtk(otk, ascon128Cipher->m_key, nonce, page); - - /* Decrypt */ - tagOk = ascon_aead_decrypt(data + offset, data + offset, clen - offset, - NULL /* ad */, 0 /* adlen */, - dummyTag, nonce, otk); - if (page == 1 && usePlaintextHeader == 0) - { - memcpy(data, SQLITE_FILE_HEADER, 16); - } + memcpy(data, SQLITE_FILE_HEADER, 16); } /* Zero out otk array */ @@ -337547,7 +345565,7 @@ GenerateKeyAegisCipher(void* cipher, char* userPassword, int passwordLength, int { AegisCipher* aegisCipher = (AegisCipher*) cipher; - int keyOnly = 1; + int keyOnly = 0; if (rekey == 2) { /* (rekey == 2) means database is in WAL mode, thus don't change the cipher salt */ @@ -337607,7 +345625,7 @@ EncryptPageAegisCipher(void* cipher, int page, unsigned char* data, int len, int { AegisCipher* aegisCipher = (AegisCipher*) cipher; int rc = SQLITE_OK; - int nReserved = (reserved == 0) ? 0 : GetReservedAegisCipher(cipher); + int nReserved = GetReservedAegisCipher(cipher); int n = len - nReserved; uint64_t mlen = n; int usePlaintextHeader = 0; @@ -337633,48 +345651,26 @@ EncryptPageAegisCipher(void* cipher, int page, unsigned char* data, int len, int } /* Check whether number of required reserved bytes and actually reserved bytes match */ - if (nReserved > reserved) + if (nReserved != reserved) { return SQLITE_CORRUPT; } - if (nReserved > 0) - { - /* Encrypt and authenticate */ + /* Encrypt and authenticate */ - /* Generate nonce */ - chacha20_rng(data + n + PAGE_TAG_LEN_AEGIS, aegisCipher->m_nonceLength); - AegisGenOtk(aegisCipher, otk, aegisCipher->m_keyLength + aegisCipher->m_nonceLength, - data + n + PAGE_TAG_LEN_AEGIS, aegisCipher->m_nonceLength, page); + /* Generate nonce */ + chacha20_rng(data + n + PAGE_TAG_LEN_AEGIS, aegisCipher->m_nonceLength); + AegisGenOtk(aegisCipher, otk, aegisCipher->m_keyLength + aegisCipher->m_nonceLength, + data + n + PAGE_TAG_LEN_AEGIS, aegisCipher->m_nonceLength, page); - mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].encrypt( - data + offset, data + n, PAGE_TAG_LEN_AEGIS, - data + offset, mlen - offset, - NULL, 0, otk + aegisCipher->m_keyLength, otk); + mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].encrypt( + data + offset, data + n, PAGE_TAG_LEN_AEGIS, + data + offset, mlen - offset, + NULL, 0, otk + aegisCipher->m_keyLength, otk); - if (page == 1 && usePlaintextHeader == 0) - { - memcpy(data, aegisCipher->m_salt, SALTLENGTH_AEGIS); - } - } - else + if (page == 1 && usePlaintextHeader == 0) { - /* Encrypt only */ - uint8_t nonce[PAGE_NONCE_LEN_AEGIS_MAX]; - AegisGenNonce(aegisCipher, nonce, aegisCipher->m_nonceLength, page); - AegisGenOtk(aegisCipher, otk, aegisCipher->m_keyLength + aegisCipher->m_nonceLength, - nonce, aegisCipher->m_nonceLength, page); - - /* Encrypt */ - mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].encryptNoTag( - data + offset, - data + offset, mlen - offset, - otk + aegisCipher->m_keyLength, otk); - - if (page == 1 && usePlaintextHeader == 0) - { - memcpy(data, aegisCipher->m_salt, SALTLENGTH_AEGIS); - } + memcpy(data, aegisCipher->m_salt, SALTLENGTH_AEGIS); } /* Zero out otk array */ @@ -337688,7 +345684,7 @@ DecryptPageAegisCipher(void* cipher, int page, unsigned char* data, int len, int { AegisCipher* aegisCipher = (AegisCipher*) cipher; int rc = SQLITE_OK; - int nReserved = (reserved == 0) ? 0 : GetReservedAegisCipher(cipher); + int nReserved = GetReservedAegisCipher(cipher); int n = len - nReserved; uint64_t clen = n; int tagOk; @@ -337715,69 +345711,47 @@ DecryptPageAegisCipher(void* cipher, int page, unsigned char* data, int len, int } /* Check whether number of required reserved bytes and actually reserved bytes match */ - if (nReserved > reserved) + if (nReserved != reserved) { return (page == 1) ? SQLITE_NOTADB : SQLITE_CORRUPT; } - if (nReserved > 0) - { - /* Decrypt and verify MAC */ - AegisGenOtk(aegisCipher, otk, aegisCipher->m_keyLength + aegisCipher->m_nonceLength, - data + n + PAGE_TAG_LEN_AEGIS, aegisCipher->m_nonceLength, page); + /* Decrypt and verify MAC */ + AegisGenOtk(aegisCipher, otk, aegisCipher->m_keyLength + aegisCipher->m_nonceLength, + data + n + PAGE_TAG_LEN_AEGIS, aegisCipher->m_nonceLength, page); - /* Determine MAC and decrypt */ - if (hmacCheck != 0) - { - /* Verify the MAC */ - tagOk = mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].decrypt( - data + offset, - data + offset, clen - offset, - data + n, PAGE_TAG_LEN_AEGIS, - NULL, 0, otk + aegisCipher->m_keyLength, otk); - if (tagOk != 0) - { - SQLITE3MC_DEBUG_LOG("decrypt: codec=%p page=%d\n", aegisCipher, page); - SQLITE3MC_DEBUG_HEX("decrypt key:", aegisCipher->m_key, aegisCipher->m_keyLength); - SQLITE3MC_DEBUG_HEX("decrypt otk:", otk, 64); - SQLITE3MC_DEBUG_HEX("decrypt data+00:", data, 16); - SQLITE3MC_DEBUG_HEX("decrypt data+24:", data + 24, 16); - SQLITE3MC_DEBUG_HEX("decrypt data+n:", data + n, PAGE_TAG_LEN_AEGIS); - /* Bad MAC */ - rc = (page == 1) ? SQLITE_NOTADB : SQLITE_CORRUPT; - } - } - else - { - mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].decryptNoTag( - data + offset, - data + offset, clen - offset, - otk + aegisCipher->m_keyLength, otk); - } - - if (page == 1 && usePlaintextHeader == 0 && rc == SQLITE_OK) + /* Determine MAC and decrypt */ + if (hmacCheck != 0) + { + /* Verify the MAC */ + tagOk = mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].decrypt( + data + offset, + data + offset, clen - offset, + data + n, PAGE_TAG_LEN_AEGIS, + NULL, 0, otk + aegisCipher->m_keyLength, otk); + if (tagOk != 0) { - memcpy(data, SQLITE_FILE_HEADER, 16); + SQLITE3MC_DEBUG_LOG("decrypt: codec=%p page=%d\n", aegisCipher, page); + SQLITE3MC_DEBUG_HEX("decrypt key:", aegisCipher->m_key, aegisCipher->m_keyLength); + SQLITE3MC_DEBUG_HEX("decrypt otk:", otk, 64); + SQLITE3MC_DEBUG_HEX("decrypt data+00:", data, 16); + SQLITE3MC_DEBUG_HEX("decrypt data+24:", data + 24, 16); + SQLITE3MC_DEBUG_HEX("decrypt data+n:", data + n, PAGE_TAG_LEN_AEGIS); + /* Bad MAC */ + rc = (page == 1) ? SQLITE_NOTADB : SQLITE_CORRUPT; } } else { - /* Decrypt only */ - uint8_t nonce[PAGE_NONCE_LEN_AEGIS_MAX]; - AegisGenNonce(aegisCipher, nonce, aegisCipher->m_nonceLength, page); - AegisGenOtk(aegisCipher, otk, aegisCipher->m_keyLength + aegisCipher->m_nonceLength, - nonce, aegisCipher->m_nonceLength, page); - - /* Decrypt */ mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].decryptNoTag( data + offset, data + offset, clen - offset, otk + aegisCipher->m_keyLength, otk); + } - if (page == 1 && usePlaintextHeader == 0) - { - memcpy(data, SQLITE_FILE_HEADER, 16); - } + if (page == 1 && usePlaintextHeader == 0 && rc == SQLITE_OK) + { + memcpy(data, SQLITE_FILE_HEADER, 16); } /* Zero out otk array */ @@ -337833,6 +345807,7 @@ static CipherParams commonParams[] = { { "cipher", CODEC_TYPE_UNKNOWN, CODEC_TYPE_UNKNOWN, 1, CODEC_COUNT_MAX }, { "hmac_check", 1, 1, 0, 1 }, + { "encrypt_temp_db", 0, 0, 0, 1 }, { "mc_legacy_wal", SQLITE3MC_LEGACY_WAL, SQLITE3MC_LEGACY_WAL, 0, 1 }, CIPHER_PARAMS_SENTINEL }; @@ -337892,7 +345867,7 @@ sqlite3mcCloneCodecParameterTable() cloneCodecParams = (CodecParameter*) sqlite3_malloc((nTables + 1) * sizeof(CodecParameter)); /* Create copy of tables */ - if (cloneCodecParams != NULL) + if (cloneCodecParams != NULL && cloneCipherParams != NULL) { int offset = 0; for (j = 0; j < nTables; ++j) @@ -337919,7 +345894,9 @@ sqlite3mcCloneCodecParameterTable() } else { + sqlite3_free(cloneCodecParams); sqlite3_free(cloneCipherParams); + cloneCodecParams = NULL; } return cloneCodecParams; } @@ -338041,7 +346018,7 @@ sqlite3mcCodecTerm(Codec* codec) globalCodecDescriptorTable[codec->m_writeCipherType - 1].m_freeCipher(codec->m_writeCipher); codec->m_writeCipher = NULL; } - memset(codec, 0, sizeof(Codec)); + sqlite3mcSecureZeroMemory(codec, sizeof(Codec)); } SQLITE_PRIVATE void @@ -338234,6 +346211,10 @@ SQLITE_PRIVATE int sqlite3mcGetPageSizeReadCipher(Codec* codec) { int pageSize = (codec->m_hasReadCipher && codec->m_readCipher != NULL) ? globalCodecDescriptorTable[codec->m_readCipherType - 1].m_getPageSize(codec->m_readCipher) : -1; + if (pageSize <= 0 && codec->m_btShared != NULL) + { + pageSize = codec->m_btShared->pageSize; + } return pageSize; } @@ -338241,6 +346222,10 @@ SQLITE_PRIVATE int sqlite3mcGetPageSizeWriteCipher(Codec* codec) { int pageSize = (codec->m_hasWriteCipher && codec->m_writeCipher != NULL) ? globalCodecDescriptorTable[codec->m_writeCipherType - 1].m_getPageSize(codec->m_writeCipher) : -1; + if (pageSize <= 0 && codec->m_btShared != NULL) + { + pageSize = codec->m_btShared->pageSize; + } return pageSize; } @@ -338615,11 +346600,16 @@ sqlite3mc_config(sqlite3* db, const char* paramName, int newValue) { int allowChange = 1; - /* Allow cipher change only if new cipher is actually available */ if (sqlite3_stricmp(paramName, "cipher") == 0) { + /* Allow cipher change only if new cipher is actually available */ allowChange = newValue > 0 && newValue <= cipherCount; } + else if (sqlite3_stricmp(paramName, "encrypt_temp_db") == 0) + { + /* Allow only to enable unconditional encryption of temporary database */ + allowChange = newValue > 0; + } if (allowChange) { @@ -339281,6 +347271,19 @@ sqlite3mcConfigureFromUri(sqlite3* db, const char* zDbName, int configDefault) const char* dbFileName = zDbName; if (dbFileName != NULL) { + /* Handle ChaCha20 hardware acceleration option */ + const char* chacha20HwAccelOption = sqlite3_uri_parameter(dbFileName, "mc_chacha20_hwaccel"); + if (chacha20HwAccelOption != NULL && chacha20HwAccelOption[0] != 0) + { + const char* option = chacha20HwAccelOption; + option = sqlite3mcChaCha20HwConfig(option); + /* Invalid option values are ignored here. */ + } + + /* Enable unconditional encryption of temporary databases */ + int encryptTempDb = sqlite3_uri_boolean(dbFileName, "encrypt_temp_db", 0); + sqlite3mc_config(db, "encrypt_temp_db", encryptTempDb); + /* Check whether cipher is specified */ const char* cipherName = sqlite3_uri_parameter(dbFileName, "cipher"); if (cipherName == NULL || cipherName[0] == 0) @@ -339497,6 +347500,13 @@ sqlite3mcFileControlPragma(sqlite3* db, const char* zDbName, int op, void* pArg) ((char**)pArg)[0] = sqlite3_mprintf("%d", value); rc = SQLITE_OK; } + else if (sqlite3StrICmp(pragmaName, "encrypt_temp_db") == 0) + { + int encryptTempDb = (pragmaValue != NULL) ? sqlite3GetBoolean(pragmaValue, 0) : -1; + int value = sqlite3mc_config(db, "encrypt_temp_db", encryptTempDb); + ((char**)pArg)[0] = sqlite3_mprintf("%d", value); + rc = SQLITE_OK; + } else if (sqlite3StrICmp(pragmaName, "mc_legacy_wal") == 0) { int walLegacy = (pragmaValue != NULL) ? sqlite3GetBoolean(pragmaValue, 0) : -1; @@ -339504,6 +347514,33 @@ sqlite3mcFileControlPragma(sqlite3* db, const char* zDbName, int op, void* pArg) ((char**)pArg)[0] = sqlite3_mprintf("%d", value); rc = SQLITE_OK; } + else if (sqlite3StrICmp(pragmaName, "mc_aes_info") == 0) + { + const char* hwInfo = sqlite3mcHardwareInfo(); + ((char**)pArg)[0] = sqlite3_mprintf("%s", aesHardwareAvailable() ? "hardware" : "software"); + rc = SQLITE_OK; + } + else if (sqlite3StrICmp(pragmaName, "mc_cpu_info") == 0) + { + const char* hwInfo = sqlite3mcHardwareInfo(); + ((char**)pArg)[0] = sqlite3_mprintf("%s", hwInfo); + rc = SQLITE_OK; + } + else if (sqlite3StrICmp(pragmaName, "mc_chacha20_hwaccel") == 0) + { + const char* option = (pragmaValue != NULL) ? pragmaValue : ""; + const char* optionSelected = sqlite3mcChaCha20HwConfig(option); + if (optionSelected != NULL) + { + ((char**)pArg)[0] = sqlite3_mprintf("%s", optionSelected); + rc = SQLITE_OK; + } + else + { + ((char**)pArg)[0] = sqlite3_mprintf("Invalid ChaCha20 hardware acceleration option: %s", option); + rc = SQLITE_ERROR; + } + } else if (sqlite3StrICmp(pragmaName, "cipher_salt") == 0) { Codec* codec = sqlite3mcGetCodec(db, (zDbName) ? zDbName : "main"); @@ -339594,6 +347631,7 @@ sqlite3mcFileControlPragma(sqlite3* db, const char* zDbName, int op, void* pArg) unsigned char* zHexKey = sqlite3_malloc(nValue/2); sqlite3mcConvertHex2Bin((const unsigned char*) pragmaValue, nValue, zHexKey); rc = sqlite3_key_v2(db, zDbName, zHexKey, nValue/2); + sqlite3mcSecureZeroMemory(zHexKey, nValue/2); sqlite3_free(zHexKey); if (rc == SQLITE_OK) { @@ -339644,6 +347682,7 @@ sqlite3mcFileControlPragma(sqlite3* db, const char* zDbName, int op, void* pArg) unsigned char* zHexKey = sqlite3_malloc(nValue/2); sqlite3mcConvertHex2Bin((const unsigned char*) pragmaValue, nValue, zHexKey); rc = sqlite3_rekey_v2(db, zDbName, zHexKey, nValue/2); + sqlite3mcSecureZeroMemory(zHexKey, nValue/2); sqlite3_free(zHexKey); if (rc == SQLITE_OK) { @@ -339809,6 +347848,7 @@ sqlite3mcCodecQueryParameters(sqlite3* db, const char* zDb, const char* zUri) if ((i & 1) != 0) zDecoded[i/2] = iByte; } sqlite3_key_v2(db, zDb, zDecoded, i/2); + sqlite3mcSecureZeroMemory(zDecoded, nKey); sqlite3_free(zDecoded); } else if ((zKey = sqlite3_uri_parameter(zUri, "key")) != 0) @@ -339919,6 +347959,7 @@ sqlite3mcBtreeSetPageSize(Btree* p, int pageSize, int nReserve, int iFix) { assert((pageSize & 7) == 0); assert(!pBt->pCursor); + if( nReserve>32 && pageSize==512 ) pageSize = 1024; pBt->pageSize = (u32)pageSize; freeTempSpace(pBt); } @@ -339963,7 +348004,7 @@ sqlite3mcBtreeSetPageSize(Btree* p, int pageSize, int nReserve, int iFix) ** Change 4: Call sqlite3mcBtreeSetPageSize instead of sqlite3BtreeSetPageSize for main database ** (sqlite3mcBtreeSetPageSize allows to reduce the number of reserved bytes) ** -** This code is generated by the script rekeyvacuum.sh from SQLite version 3.53.4 amalgamation. +** This code is generated by the script rekeyvacuum.sh from SQLite version 3.54.0 amalgamation. */ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3mcRunVacuumForRekey( char **pzErrMsg, /* Write error message here */ @@ -340410,12 +348451,12 @@ mcAdjustBtree(Btree* pBt, int nPageSize, int nReserved, int isLegacy) { pBt->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED; } - rc = sqlite3BtreeSetPageSize(pBt, pagesize, reserved, 0); + rc = sqlite3mcBtreeSetPageSize(pBt, pagesize, reserved, 0); } return rc; } -static int +SQLITE_PRIVATE int sqlite3mcCodecAttach(sqlite3* db, int nDb, const char* zPath, const void* zKey, int nKey) { /* Attach a key to a database. */ @@ -340891,12 +348932,21 @@ SQLITE_PRIVATE void sqlite3mcSecureZeroMemory(void* v, size_t n) { #ifdef _WIN32 SecureZeroMemory(v, n); -#elif defined(__DARWIN__) || defined(__STDC_LIB_EXT1__) - /* memset_s() is available since OS X 10.9, */ - /* and may be available on other platforms. */ +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L + memset_explicit(v, 0, n); +#elif defined(__APPLE__) || defined(__STDC_LIB_EXT1__) + /* memset_s() is only declared by when __STDC_WANT_LIB_EXT1__ is + set before the first inclusion, which we can't control in an amalgamation. + Declare it ourselves; errno_t is int and rsize_t is size_t, so this is a + compatible redeclaration if the header also provided it. */ + extern int memset_s(void*, size_t, int, size_t); memset_s(v, n, 0, n); -#elif defined(__OpenBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 11) - /* Non-standard function */ +#elif defined(__ANDROID__) && __ANDROID_API__ >= 34 + memset_explicit(v, 0, n); +#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ + (defined(__FreeBSD__) && __FreeBSD__ >= 11) || \ + (defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))) || \ + (defined(__EMSCRIPTEN__) && defined(__EMSCRIPTEN_major__) && __EMSCRIPTEN_major__ >= 3) || defined(__wasi__) explicit_bzero(v, n); #else /* Generic implementation based on volatile pointers */ @@ -345866,11 +353916,11 @@ static int vsvtabColumn( #else if (!hasExtended) { if (sizeof(long double) > sizeof(double)) { - volatile unsigned long long i = ULLONG_MAX; + volatile unsigned long long j = ULLONG_MAX; volatile long double l; volatile double d; - l = i; - d = i; + l = j; + d = j; hasExtended = (d == l) ? -1 : 1; } else { hasExtended = -1; @@ -362326,7 +370376,7 @@ int sqlite3_zipfile_init( /* ** VLE - Value Level Encryption */ -#define SQLITE3MC_ENABLE_VLE 1 + #ifdef SQLITE3MC_ENABLE_VLE SQLITE_API int sqlite3_vle_init(sqlite3* db, char** pzErrMsg, const sqlite3_api_routines* pApi); @@ -362688,6 +370738,12 @@ static const char* VLE_CONTEXT_KEY = "vle_context"; // ---------- Helper Functions ---------- +static void vle_freeContext(void* ctx) +{ + sqlite3mcSecureZeroMemory(ctx, sizeof(VleContext)); + sqlite3_free(ctx); +} + static VleContext* vle_getContext(sqlite3* db) { VleContext* ctx = sqlite3_get_clientdata(db, VLE_CONTEXT_KEY); @@ -362699,7 +370755,7 @@ static VleContext* vle_getContext(sqlite3* db) ctx->flags = 0; ctx->nonceLen = VLE_NONCE_LEN; ctx->tagLen = VLE_TAG_LEN; - sqlite3_set_clientdata(db, VLE_CONTEXT_KEY, ctx, sqlite3_free); + sqlite3_set_clientdata(db, VLE_CONTEXT_KEY, ctx, vle_freeContext); } return ctx; } @@ -363200,6 +371256,7 @@ int sqlite3_vle_init(sqlite3* db, char** pzErrMsg, const sqlite3_api_routines* p typedef struct sqlite3mc_file sqlite3mc_file; typedef struct sqlite3mc_vfs sqlite3mc_vfs; +typedef struct mcTempCipher mcTempCipher; /* ** SQLite3 Multiple Ciphers file structure @@ -363216,6 +371273,8 @@ struct sqlite3mc_file sqlite3mc_file* pMainDb; /* Main database to which this one is attached */ Codec* codec; /* Codec if encrypted */ int pageNo; /* Page number (in case of journal files) */ + int pageSize; /* Page size of temporary or transient database */ + mcTempCipher* tempCipher; /* Cipher of a temporary file opened without a name */ }; /* @@ -363276,6 +371335,463 @@ static int mcIoShmUnmap(sqlite3_file* pFile, int deleteFlag); static int mcIoFetch(sqlite3_file* pFile, sqlite3_int64 iOfst, int iAmt, void** pp); static int mcIoUnfetch(sqlite3_file* pFile, sqlite3_int64 iOfst, void* p); +/* +** Encryption of temporary files +** +** SQLite opens temporary files without a name: temporary and transient +** databases, temporary journals, sorter files and statement journals. Such a +** file is private and deleted on close (see xOpen in sqlite3.h), and it can't +** be linked to the codec of a database. Therefore every file opened without a +** name is encrypted with its own random key, which exists only in memory and +** is wiped when the file is closed. +** +** A file is encrypted in blocks with ChaCha20. Each block is stored with the +** value of a counter in front of it, which the file increments for every block +** it writes, so the offsets within the file move by 8 bytes per block. The +** counter is the nonce of the block and is read back from the file, so no +** state per block has to be kept in memory. A write that appends to the last +** block continues its keystream, every other write re-encrypts the block with +** the next counter value. A keystream is therefore never used twice. +** +** Blocks below the last one are always complete, so the size of the file tells +** how many bytes of the last block are valid. A block that was never written +** holds the counter value 0 and reads as zeros. +** +** The encryption protects the confidentiality of temporary files, not their +** integrity. +*/ + +#ifndef SQLITE3MC_ENCRYPT_TEMP_FILES +#define SQLITE3MC_ENCRYPT_TEMP_FILES 1 +#endif + +#define MC_TEMP_BLOCK 4096 /* Block size unless the database page size is known */ +#define MC_TEMP_MAX_BLOCK 65536 /* Largest database page size SQLite supports */ +#define MC_TEMP_HEADER 8 /* Size of the counter in front of every block */ +#define MC_TEMP_MAX_BROKEN 8 /* Blocks whose failed write is remembered individually */ + +struct mcTempCipher +{ + uint8_t key[32]; /* Random key */ + int blockSize; /* Payload bytes per block */ + sqlite3_uint64 counter; /* Last counter value used; 0 if nothing was written yet */ + sqlite3_int64 size; /* Size of the file as SQLite sees it */ + sqlite3_int64 iTail; /* Block whose keystream may be continued, or -1 */ + sqlite3_uint64 tailCounter; /* Counter value of that block */ + int nTailUsed; /* Bytes of its keystream that are already used */ + sqlite3_int64 aBroken[MC_TEMP_MAX_BROKEN]; + /* Blocks left unreadable by a failed write */ + int nBroken; /* Entries used in aBroken */ + int allBroken; /* More blocks were broken than aBroken can hold */ + int tailStale; /* Data of a failed write may still sit behind the end */ + uint8_t* buffer; /* Work buffer for one block, allocated when the block size is + ** known; holds only ciphertext between calls, and SQLite uses a + ** file from one thread at a time */ +}; + +/* +** Create the cipher of a temporary file with a fresh random key +*/ +static mcTempCipher* mcTempCipherCreate(void) +{ + mcTempCipher* pTemp = (mcTempCipher*) sqlite3_malloc(sizeof(mcTempCipher)); + if (pTemp != NULL) + { + memset(pTemp, 0, sizeof(mcTempCipher)); + pTemp->blockSize = MC_TEMP_BLOCK; + pTemp->iTail = -1; + chacha20_rng(pTemp->key, sizeof(pTemp->key)); + } + return pTemp; +} + +/* +** Wipe and release the cipher of a temporary file +*/ +static void mcTempCipherFree(mcTempCipher* pTemp) +{ + if (pTemp != NULL) + { + if (pTemp->buffer != NULL) + { + sqlite3mcSecureZeroMemory(pTemp->buffer, (size_t) (MC_TEMP_HEADER + pTemp->blockSize)); + sqlite3_free(pTemp->buffer); + } + sqlite3mcSecureZeroMemory(pTemp, sizeof(mcTempCipher)); + sqlite3_free(pTemp); + } +} + +/* +** The work buffer is allocated when the first write has settled the block size +*/ +static int mcTempBufferAllocated(mcTempCipher* pTemp) +{ + if (pTemp->buffer == NULL) + { + pTemp->buffer = (uint8_t*) sqlite3_malloc(MC_TEMP_HEADER + pTemp->blockSize); + if (pTemp->buffer == NULL) return SQLITE_NOMEM; + } + return SQLITE_OK; +} + +/* +** Position of a block in the file +*/ +static sqlite3_int64 mcTempSlot(mcTempCipher* pTemp, sqlite3_int64 iBlock) +{ + return iBlock * (MC_TEMP_HEADER + pTemp->blockSize); +} + +/* +** Payload bytes of a block that belong to the file +*/ +static int mcTempBlockValid(mcTempCipher* pTemp, sqlite3_int64 iBlock) +{ + sqlite3_int64 start = iBlock * pTemp->blockSize; + if (pTemp->size <= start) return 0; + return (pTemp->size - start < pTemp->blockSize) ? (int) (pTemp->size - start) : pTemp->blockSize; +} + +/* +** Blocks whose rewrite failed are unreadable; if there are more of them than +** can be remembered, the whole file is treated as unreadable +*/ +static int mcTempBlockIsBroken(mcTempCipher* pTemp, sqlite3_int64 iBlock) +{ + int i; + if (pTemp->allBroken) return 1; + for (i = 0; i < pTemp->nBroken; i++) + { + if (pTemp->aBroken[i] == iBlock) return 1; + } + return 0; +} + +static void mcTempBlockMarkBroken(mcTempCipher* pTemp, sqlite3_int64 iBlock) +{ + if (mcTempBlockIsBroken(pTemp, iBlock)) return; + if (pTemp->nBroken < MC_TEMP_MAX_BROKEN) pTemp->aBroken[pTemp->nBroken++] = iBlock; + else pTemp->allBroken = 1; +} + +static void mcTempClearBroken(mcTempCipher* pTemp, sqlite3_int64 iBlock) +{ + int i; + for (i = 0; i < pTemp->nBroken; i++) + { + if (pTemp->aBroken[i] == iBlock) pTemp->aBroken[i] = pTemp->aBroken[--pTemp->nBroken]; + } +} + +/* +** Blocks that a truncate removed are no longer unreadable +*/ +static void mcTempClearBrokenFrom(mcTempCipher* pTemp, sqlite3_int64 iFirst) +{ + int i; + for (i = 0; i < pTemp->nBroken; ) + { + if (pTemp->aBroken[i] >= iFirst) + pTemp->aBroken[i] = pTemp->aBroken[--pTemp->nBroken]; + else + i++; + } +} + +/* +** XOR the keystream of a counter value into data, which starts at byte iOff of +** the block +*/ +static void mcTempXorKeystream(mcTempCipher* pTemp, sqlite3_uint64 counter, + uint8_t* data, int iOff, int n) +{ + uint8_t nonce[12]; + uint32_t block = (uint32_t) (iOff / 64); + int skip = iOff % 64; + int i; + memset(nonce, 0, sizeof(nonce)); + for (i = 0; i < 8; i++) nonce[i] = (uint8_t) (counter >> (8 * i)); + if (skip > 0) + { + uint8_t ks[64]; + int m = (n < 64 - skip) ? n : 64 - skip; + memset(ks, 0, sizeof(ks)); + chacha20_xor(ks, sizeof(ks), pTemp->key, nonce, block++); + for (i = 0; i < m; i++) data[i] ^= ks[skip + i]; + sqlite3mcSecureZeroMemory(ks, sizeof(ks)); + data += m; + n -= m; + } + if (n > 0) + { + chacha20_xor(data, (size_t) n, pTemp->key, nonce, block); + } +} + +/* +** Read the counter value in front of a block; 0 means the block was never +** written +*/ +static sqlite3_uint64 mcTempCounterOf(const uint8_t* header) +{ + sqlite3_uint64 counter = 0; + int i; + for (i = 0; i < 8; i++) counter |= ((sqlite3_uint64) header[i]) << (8 * i); + return counter; +} + +static void mcTempPutCounter(uint8_t* header, sqlite3_uint64 counter) +{ + int i; + for (i = 0; i < 8; i++) header[i] = (uint8_t) (counter >> (8 * i)); +} + +/* +** Remove what sits behind the end of the file: the rest of a failed write, or +** the blocks that a truncate kept because the file has a chunk size. Their +** counter value is cleared, so that they read as never written. +*/ +static void mcTempDropTail(sqlite3mc_file* mcFile) +{ + static const uint8_t zero[MC_TEMP_HEADER] = { 0 }; + mcTempCipher* pTemp = mcFile->tempCipher; + sqlite3_file* pReal = REALFILE(mcFile); + sqlite3_int64 slot = MC_TEMP_HEADER + pTemp->blockSize; + sqlite3_int64 iBlock = pTemp->size / pTemp->blockSize; + int iOff = (int) (pTemp->size % pTemp->blockSize); + sqlite3_int64 physical = iBlock * slot + (iOff > 0 ? MC_TEMP_HEADER + iOff : 0); + sqlite3_int64 kept = 0; + sqlite3_int64 b = (pTemp->size + pTemp->blockSize - 1) / pTemp->blockSize; + + pTemp->tailStale = (pReal->pMethods->xTruncate(pReal, physical) != SQLITE_OK); + if (pReal->pMethods->xFileSize(pReal, &kept) != SQLITE_OK) { pTemp->tailStale = 1; return; } + while (b * slot + MC_TEMP_HEADER <= kept) + { + if (pReal->pMethods->xWrite(pReal, zero, MC_TEMP_HEADER, b * slot) != SQLITE_OK) + { + mcTempBlockMarkBroken(pTemp, b); + pTemp->tailStale = 1; + } + b++; + } +} + +/* +** Read from a temporary file. Everything that was never written, and +** everything behind the end of the file, is returned as zeros. +*/ +static int mcTempRead(sqlite3mc_file* mcFile, void* buffer, int count, sqlite3_int64 offset) +{ + mcTempCipher* pTemp = mcFile->tempCipher; + sqlite3_file* pReal = REALFILE(mcFile); + sqlite3_int64 pos, end = offset + count; + int rc = SQLITE_OK; + assert(offset >= 0 && count >= 0); + if (end > pTemp->size) rc = SQLITE_IOERR_SHORT_READ; + for (pos = offset; pos < end; ) + { + sqlite3_int64 iBlock = pos / pTemp->blockSize; + int iOff = (int) (pos % pTemp->blockSize); + int n = (pTemp->blockSize - iOff < end - pos) ? pTemp->blockSize - iOff : (int) (end - pos); + int nValid = mcTempBlockValid(pTemp, iBlock); + int nDecrypt = 0; + uint8_t* data = (uint8_t*) buffer + (pos - offset); + + if (mcTempBlockIsBroken(pTemp, iBlock)) return SQLITE_IOERR_READ; + if (iOff < nValid) + { + int nRead = MC_TEMP_HEADER + iOff + n; + sqlite3_uint64 counter; + if (mcTempBufferAllocated(pTemp) != SQLITE_OK) return SQLITE_NOMEM; + int rcRead = pReal->pMethods->xRead(pReal, pTemp->buffer, nRead, mcTempSlot(pTemp, iBlock)); + if (rcRead != SQLITE_OK && rcRead != SQLITE_IOERR_SHORT_READ) return rcRead; + counter = mcTempCounterOf(pTemp->buffer); + if (counter != 0) + { + nDecrypt = (iOff + n < nValid) ? n : nValid - iOff; + memcpy(data, pTemp->buffer + MC_TEMP_HEADER + iOff, (size_t) nDecrypt); + mcTempXorKeystream(pTemp, counter, data, iOff, nDecrypt); + } + } + if (nDecrypt < n) memset(data + nDecrypt, 0, (size_t) (n - nDecrypt)); + pos += n; + } + return rc; +} + +/* +** Write one block: the counter value and the payload from the work buffer, or +** only the new bytes when the keystream of the block is continued +*/ +static int mcTempWriteBlock(sqlite3mc_file* mcFile, sqlite3_int64 iBlock, int iStart, int nEnd, + sqlite3_uint64 counter) +{ + mcTempCipher* pTemp = mcFile->tempCipher; + sqlite3_file* pReal = REALFILE(mcFile); + mcTempXorKeystream(pTemp, counter, pTemp->buffer + MC_TEMP_HEADER + iStart, iStart, nEnd - iStart); + if (iStart == 0) + { + mcTempPutCounter(pTemp->buffer, counter); + return pReal->pMethods->xWrite(pReal, pTemp->buffer, MC_TEMP_HEADER + nEnd, mcTempSlot(pTemp, iBlock)); + } + return pReal->pMethods->xWrite(pReal, pTemp->buffer + MC_TEMP_HEADER + iStart, nEnd - iStart, + mcTempSlot(pTemp, iBlock) + MC_TEMP_HEADER + iStart); +} + +/* +** Fill up the last, incomplete block of the file with zeros, so that a write +** behind it never leaves a partly written block in the middle of the file +*/ +static int mcTempWrite(sqlite3mc_file* mcFile, const void* buffer, int count, sqlite3_int64 offset); + +static int mcTempFillTail(sqlite3mc_file* mcFile, sqlite3_int64 iBlock) +{ + static const uint8_t zeros[MC_TEMP_BLOCK] = { 0 }; + mcTempCipher* pTemp = mcFile->tempCipher; + sqlite3_int64 iLast = (pTemp->size > 0) ? (pTemp->size - 1) / pTemp->blockSize : -1; + int nValid, nFill; + if (iLast < 0 || iLast >= iBlock) return SQLITE_OK; + nValid = mcTempBlockValid(pTemp, iLast); + if (nValid == 0 || nValid == pTemp->blockSize) return SQLITE_OK; + for (nFill = pTemp->blockSize - nValid; nFill > 0; ) + { + int n = (nFill < MC_TEMP_BLOCK) ? nFill : MC_TEMP_BLOCK; + int rc = mcTempWrite(mcFile, zeros, n, pTemp->size); + if (rc != SQLITE_OK) return rc; + nFill -= n; + } + return SQLITE_OK; +} + +/* +** Encrypt and write to a temporary file, block by block +*/ +static int mcTempWrite(sqlite3mc_file* mcFile, const void* buffer, int count, sqlite3_int64 offset) +{ + mcTempCipher* pTemp = mcFile->tempCipher; + sqlite3_file* pReal = REALFILE(mcFile); + sqlite3_int64 pos, end = offset + count; + int rc; + assert(offset >= 0 && count >= 0); + if (pTemp->buffer == NULL && + (mcFile->openFlags & (SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_TRANSIENT_DB)) && + count >= 512 && count <= MC_TEMP_MAX_BLOCK && (count & (count - 1)) == 0 && offset % count == 0) + { + /* A database uses its page size as block size, so that writing a page + ** never rewrites another; the first write tells the size */ + pTemp->blockSize = count; + } + if (mcTempBufferAllocated(pTemp) != SQLITE_OK) return SQLITE_NOMEM; + + if (offset > pTemp->size) + { + /* Only the last block of a file may be incomplete, and nothing that a + ** failed write left behind its end may look like a block */ + rc = mcTempFillTail(mcFile, offset / pTemp->blockSize); + if (rc != SQLITE_OK) return rc; + if (pTemp->tailStale) mcTempDropTail(mcFile); + } + for (pos = offset; pos < end; ) + { + sqlite3_int64 iBlock = pos / pTemp->blockSize; + int iOff = (int) (pos % pTemp->blockSize); + int n = (pTemp->blockSize - iOff < end - pos) ? pTemp->blockSize - iOff : (int) (end - pos); + int nValid = mcTempBlockValid(pTemp, iBlock); + sqlite3_uint64 counter; + int iStart; /* First byte of the block to encrypt and write */ + int nKeep; /* Bytes at the start of the block whose content is kept */ + int nEnd; /* Bytes of the block that are valid afterwards */ + + if (iBlock == pTemp->iTail && iOff == pTemp->nTailUsed && nValid == iOff) + { + /* Append: the keystream of the block behind its valid part is unused */ + counter = pTemp->tailCounter; + iStart = nKeep = iOff; + } + else + { + /* Rewrite the block with the next counter value, keeping the bytes + ** before and behind the new data */ + counter = ++pTemp->counter; + iStart = nKeep = 0; + if (nValid > 0 && (iOff > 0 || iOff + n < nValid)) + { + sqlite3_uint64 old; + if (mcTempBlockIsBroken(pTemp, iBlock)) return SQLITE_IOERR_WRITE; + nKeep = nValid; + rc = pReal->pMethods->xRead(pReal, pTemp->buffer, MC_TEMP_HEADER + nKeep, mcTempSlot(pTemp, iBlock)); + if (rc != SQLITE_OK) return (rc == SQLITE_IOERR_SHORT_READ) ? SQLITE_IOERR_READ : rc; + old = mcTempCounterOf(pTemp->buffer); + if (old != 0) mcTempXorKeystream(pTemp, old, pTemp->buffer + MC_TEMP_HEADER, 0, nKeep); + else memset(pTemp->buffer + MC_TEMP_HEADER, 0, (size_t) nKeep); + } + } + /* A gap before the new data reads as zeros */ + if (nKeep < iOff) memset(pTemp->buffer + MC_TEMP_HEADER + nKeep, 0, (size_t) (iOff - nKeep)); + memcpy(pTemp->buffer + MC_TEMP_HEADER + iOff, (const uint8_t*) buffer + (pos - offset), (size_t) n); + + nEnd = (iOff + n > nKeep) ? iOff + n : nKeep; + rc = mcTempWriteBlock(mcFile, iBlock, iStart, nEnd, counter); + pTemp->iTail = iBlock; + pTemp->tailCounter = counter; + pTemp->nTailUsed = nEnd; + if (rc != SQLITE_OK) + { + /* Bytes behind the end of the file read as zeros, as if the write had + ** not happened. If the write reached into the part of the block that was + ** already valid, reading the block fails until it is written completely + ** again, because half of it may still be encrypted with the old counter + ** value. */ + if (iStart < nValid) mcTempBlockMarkBroken(pTemp, iBlock); + mcTempDropTail(mcFile); + return rc; + } + if (iStart == 0) mcTempClearBroken(pTemp, iBlock); + if (iBlock * pTemp->blockSize + pTemp->nTailUsed > pTemp->size) + { + pTemp->size = iBlock * pTemp->blockSize + pTemp->nTailUsed; + } + pos += n; + } + return SQLITE_OK; +} + +/* +** Truncate a temporary file. The counter values are kept, so no keystream is +** used twice when the file grows again. +*/ +static int mcTempTruncate(sqlite3mc_file* mcFile, sqlite3_int64 size) +{ + mcTempCipher* pTemp = mcFile->tempCipher; + sqlite3_int64 iBlock = size / pTemp->blockSize; + int iOff = (int) (size % pTemp->blockSize); + sqlite3_int64 physical = mcTempSlot(pTemp, iBlock) + (iOff > 0 ? MC_TEMP_HEADER + iOff : 0); + int rc; + if (size > pTemp->size) + { + rc = mcTempFillTail(mcFile, iBlock); + if (rc != SQLITE_OK) return rc; + } + rc = REALFILE(mcFile)->pMethods->xTruncate(REALFILE(mcFile), physical); + if (rc == SQLITE_OK) + { + pTemp->size = size; + mcTempClearBrokenFrom(pTemp, (size + pTemp->blockSize - 1) / pTemp->blockSize); + mcTempDropTail(mcFile); + } + return rc; +} + +/* +** Size of a temporary file as SQLite sees it, without the counter values +*/ +static int mcTempFileSize(sqlite3mc_file* mcFile, sqlite3_int64* pSize) +{ + *pSize = mcFile->tempCipher->size; + return SQLITE_OK; +} + #define SQLITE3MC_VFS_NAME ("multipleciphers") #define SQLITE3MC_FCNTL_PVFS 0x3f98c078 @@ -363476,6 +371992,86 @@ SQLITE_PRIVATE Codec* sqlite3mcGetMainCodec(sqlite3* db) return sqlite3mcGetCodec(db, "main"); } +SQLITE_PRIVATE int sqlite3mcIsAnyDbEncrypted(sqlite3* db) +{ + int encrypted = -1; + if (db != NULL) + { + int nDb = db->nDb; + int j; + encrypted = 0; + for (j = 0; j < nDb; ++j) + { + if (j == 1) continue; + Codec* codec = sqlite3mcGetCodec(db, db->aDb[j].zDbSName); + if (codec != NULL && sqlite3mcIsEncrypted(codec)) + { + encrypted = 1; + break; + } + } + } + return encrypted; +} + +static int mcCheckEncryptTempDb(sqlite3mc_file* mcFile, sqlite3* db) +{ + int encryptTempDb = sqlite3mc_config(db, "encrypt_temp_db", -1); + return (mcFile->openFlags & SQLITE_OPEN_TEMP_DB) && encryptTempDb != 0; +} + +SQLITE_PRIVATE int sqlite3mcOpenTempFile(Pager* pPager, sqlite3_file* pFile) +{ + if (pFile != NULL && pPager != NULL) + { + if (sqlite3JournalIsInMemory(pFile)) + { + MemJournal* pMemJournal = (MemJournal*)pFile; + pMemJournal->mcDb = pPager->mcDb; + } + else if (pFile->pMethods == &mcIoMethodsGlobal1 || + pFile->pMethods == &mcIoMethodsGlobal2 || + pFile->pMethods == &mcIoMethodsGlobal3) + { + sqlite3mc_file* mcFile = (sqlite3mc_file*)pFile; + mcFile->pageSize = (int)pPager->pageSize; + + int forceEncrypt = mcCheckEncryptTempDb(mcFile, pPager->mcDb); + if (!forceEncrypt && sqlite3mcIsAnyDbEncrypted(pPager->mcDb) == 0) + { + /* Remove temp cipher, if no database within this connection is encrypted */ + if (mcFile->tempCipher != NULL) + { + mcTempCipherFree(mcFile->tempCipher); + mcFile->tempCipher = 0; + } + } + } + } + return 0; +} + +SQLITE_PRIVATE int sqlite3mcOpenTempJournal(sqlite3* pDb, sqlite3_file* pFile) +{ + if (pFile != NULL && + (pFile->pMethods == &mcIoMethodsGlobal1 || + pFile->pMethods == &mcIoMethodsGlobal2 || + pFile->pMethods == &mcIoMethodsGlobal3)) + { + sqlite3mc_file* mcFile = (sqlite3mc_file*)pFile; + int forceEncrypt = mcCheckEncryptTempDb(mcFile, pDb); + if (!forceEncrypt && sqlite3mcIsAnyDbEncrypted(pDb) == 0) + { + if (mcFile->tempCipher != NULL) + { + mcTempCipherFree(mcFile->tempCipher); + mcFile->tempCipher = 0; + } + } + } + return 0; +} + SQLITE_PRIVATE int sqlite3mcIsBackupSupported(sqlite3* pSrc, const char* zSrc, sqlite3* pDest, const char* zDest) { int ok = 1; @@ -363595,6 +372191,33 @@ static int mcVfsOpen(sqlite3_vfs* pVfs, const char* zName, sqlite3_file* pFile, mcFile->pMainDb = 0; mcFile->pMainNext = 0; mcFile->pageNo = 0; + mcFile->tempCipher = 0; + + /* + ** For every file one of the following open flags is set. + ** If a valid filename is given, encryption is fully under + ** user/applicationcontrol (PRAGMA key). If the filename + ** is not given, the file is a temporary file. Encryption + ** will be enabled, if at least one database belonging to + ** the current connection is encrypted. + ** + ** Typically with filename: + ** - SQLITE_OPEN_MAIN_DB + ** - SQLITE_OPEN_MAIN_JOURNAL + ** - SQLITE_OPEN_SUBJOURNAL + ** - SQLITE_OPEN_SUPER_JOURNAL + ** - SQLITE_OPEN_WAL + ** + ** Always without filename: + ** - SQLITE_OPEN_TEMP_DB (block size = page size) + ** - SQLITE_OPEN_TRANSIENT_DB (block size = page size) + ** - SQLITE_OPEN_TEMP_JOURNAL (default block size) + */ + if (SQLITE3MC_ENCRYPT_TEMP_FILES && zName == NULL) + { + mcFile->tempCipher = mcTempCipherCreate(); + if (mcFile->tempCipher == NULL) return SQLITE_NOMEM; + } if (zName) { @@ -363603,19 +372226,6 @@ static int mcVfsOpen(sqlite3_vfs* pVfs, const char* zName, sqlite3_file* pFile, mcFile->zFileName = zName; SQLITE3MC_DEBUG_LOG("mcVfsOpen MAIN: mcFile=%p fileName=%s\n", mcFile, mcFile->zFileName); } - else if (flags & SQLITE_OPEN_TEMP_DB) - { - mcFile->zFileName = zName; - SQLITE3MC_DEBUG_LOG("mcVfsOpen TEMP: mcFile=%p fileName=%s\n", mcFile, mcFile->zFileName); - } -#if 0 - else if (flags & SQLITE_OPEN_TRANSIENT_DB) - { - /* - ** TODO: When does SQLite open a transient DB? Could/Should it be encrypted? - */ - } -#endif else if (flags & SQLITE_OPEN_MAIN_JOURNAL) { const char* dbFileName = sqlite3_filename_database(zName); @@ -363623,14 +372233,6 @@ static int mcVfsOpen(sqlite3_vfs* pVfs, const char* zName, sqlite3_file* pFile, mcFile->zFileName = zName; SQLITE3MC_DEBUG_LOG("mcVfsOpen MAIN Journal: mcFile=%p fileName=%s dbFileName=%s\n", mcFile, mcFile->zFileName, dbFileName); } -#if 0 - else if (flags & SQLITE_OPEN_TEMP_JOURNAL) - { - /* - ** TODO: When does SQLite open a temporary journal? Could/Should it be encrypted? - */ - } -#endif else if (flags & SQLITE_OPEN_SUBJOURNAL) { const char* dbFileName = sqlite3_filename_database(zName); @@ -363639,10 +372241,10 @@ static int mcVfsOpen(sqlite3_vfs* pVfs, const char* zName, sqlite3_file* pFile, SQLITE3MC_DEBUG_LOG("mcVfsOpen SUB Journal: mcFile=%p fileName=%s dbFileName=%s\n", mcFile, mcFile->zFileName, dbFileName); } #if 0 - else if (flags & SQLITE_OPEN_MASTER_JOURNAL) + else if (flags & SQLITE_OPEN_SUPER_JOURNAL) { /* - ** Master journal contains only administrative information + ** Super journal contains only administrative information ** No encryption necessary */ } @@ -363677,6 +372279,11 @@ static int mcVfsOpen(sqlite3_vfs* pVfs, const char* zName, sqlite3_file* pFile, mcMainListAdd(mcFile); } } + else + { + mcTempCipherFree(mcFile->tempCipher); + mcFile->tempCipher = 0; + } return rc; } @@ -363780,6 +372387,8 @@ static int mcIoClose(sqlite3_file* pFile) sqlite3mcCodecFree(p->codec); p->codec = 0; } + mcTempCipherFree(p->tempCipher); + p->tempCipher = 0; assert(p->pMainNext == 0 && p->pVfsMC->pMain != p); rc = REALFILE(pFile)->pMethods->xClose(REALFILE(pFile)); @@ -363995,8 +372604,14 @@ static int mcReadWal(sqlite3_file* pFile, const void* buffer, int count, sqlite3 static int mcIoRead(sqlite3_file* pFile, void* buffer, int count, sqlite3_int64 offset) { sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile; - int rc = REALFILE(pFile)->pMethods->xRead(REALFILE(pFile), buffer, count, offset); - if (rc == SQLITE_IOERR_SHORT_READ) + int rc; + if (mcFile->tempCipher) + { + return mcTempRead(mcFile, buffer, count, offset); + } + + rc = REALFILE(pFile)->pMethods->xRead(REALFILE(pFile), buffer, count, offset); + if (rc != SQLITE_OK) { return rc; } @@ -364005,43 +372620,19 @@ static int mcIoRead(sqlite3_file* pFile, void* buffer, int count, sqlite3_int64 { rc = mcReadMainDb(pFile, buffer, count, offset); } -#if 0 - else if (mcFile->openFlags & SQLITE_OPEN_TEMP_DB) - { - /* - ** TODO: Could/Should a temporary database file be encrypted? - */ - } -#endif -#if 0 - else if (mcFile->openFlags & SQLITE_OPEN_TRANSIENT_DB) - { - /* - ** TODO: Could/Should a transient database file be encrypted? - */ - } -#endif else if (mcFile->openFlags & SQLITE_OPEN_MAIN_JOURNAL) { rc = mcReadMainJournal(pFile, buffer, count, offset); } -#if 0 - else if (mcFile->openFlags & SQLITE_OPEN_TEMP_JOURNAL) - { - /* - ** TODO: Could/Should a temporary journal file be encrypted? - */ - } -#endif else if (mcFile->openFlags & SQLITE_OPEN_SUBJOURNAL) { rc = mcReadSubJournal(pFile, buffer, count, offset); } #if 0 - else if (mcFile->openFlags & SQLITE_OPEN_MASTER_JOURNAL) + else if (mcFile->openFlags & SQLITE_OPEN_SUPER_JOURNAL) { /* - ** Master journal contains only administrative information + ** Super journal contains only administrative information ** No encryption necessary */ } @@ -364298,47 +372889,27 @@ static int mcIoWrite(sqlite3_file* pFile, const void* buffer, int count, sqlite3 int doDefault = 1; sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile; - if (mcFile->openFlags & SQLITE_OPEN_MAIN_DB) - { - rc = mcWriteMainDb(pFile, buffer, count, offset); - } -#if 0 - else if (mcFile->openFlags & SQLITE_OPEN_TEMP_DB) + if (mcFile->tempCipher) { - /* - ** TODO: Could/Should a temporary database file be encrypted? - */ + rc = mcTempWrite(mcFile, buffer, count, offset); } -#endif -#if 0 - else if (mcFile->openFlags & SQLITE_OPEN_TRANSIENT_DB) + else if (mcFile->openFlags & SQLITE_OPEN_MAIN_DB) { - /* - ** TODO: Could/Should a transient database file be encrypted? - */ + rc = mcWriteMainDb(pFile, buffer, count, offset); } -#endif else if (mcFile->openFlags & SQLITE_OPEN_MAIN_JOURNAL) { rc = mcWriteMainJournal(pFile, buffer, count, offset); } -#if 0 - else if (mcFile->openFlags & SQLITE_OPEN_TEMP_JOURNAL) - { - /* - ** TODO: Could/Should a temporary journal file be encrypted? - */ - } -#endif else if (mcFile->openFlags & SQLITE_OPEN_SUBJOURNAL) { rc = mcWriteSubJournal(pFile, buffer, count, offset); } #if 0 - else if (mcFile->openFlags & SQLITE_OPEN_MASTER_JOURNAL) + else if (mcFile->openFlags & SQLITE_OPEN_SUPER_JOURNAL) { /* - ** Master journal contains only administrative information + ** Super journal contains only administrative information ** No encryption necessary */ } @@ -364361,6 +372932,11 @@ static int mcIoWrite(sqlite3_file* pFile, const void* buffer, int count, sqlite3 static int mcIoTruncate(sqlite3_file* pFile, sqlite3_int64 size) { + sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile; + if (mcFile->tempCipher) + { + return mcTempTruncate(mcFile, size); + } return REALFILE(pFile)->pMethods->xTruncate(REALFILE(pFile), size); } @@ -364371,6 +372947,11 @@ static int mcIoSync(sqlite3_file* pFile, int flags) static int mcIoFileSize(sqlite3_file* pFile, sqlite3_int64* pSize) { + sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile; + if (mcFile->tempCipher) + { + return mcTempFileSize(mcFile, pSize); + } return REALFILE(pFile)->pMethods->xFileSize(REALFILE(pFile), pSize); } @@ -364502,6 +373083,12 @@ static int mcIoShmUnmap(sqlite3_file* pFile, int deleteFlag) static int mcIoFetch(sqlite3_file* pFile, sqlite3_int64 iOfst, int iAmt, void** pp) { + if (((sqlite3mc_file*) pFile)->tempCipher) + { + /* No memory mapping for encrypted temporary files; SQLite falls back to xRead */ + *pp = 0; + return SQLITE_OK; + } return REALFILE(pFile)->pMethods->xFetch(REALFILE(pFile), iOfst, iAmt, pp); } @@ -364736,7 +373323,12 @@ mcRegisterCodecExtensions(sqlite3* db, char** pzErrMsg, const sqlite3_api_routin rc = (codecParameterTable != NULL) ? SQLITE_OK : SQLITE_NOMEM; if (rc == SQLITE_OK) { - sqlite3_set_clientdata(db, globalConfigTableName, codecParameterTable, sqlite3mcFreeCodecParameterTable); + rc = sqlite3_set_clientdata(db, globalConfigTableName, codecParameterTable, sqlite3mcFreeCodecParameterTable); + if (rc != SQLITE_OK) + { + /* sqlite3_set_clientdata failed with OOM */ + codecParameterTable = NULL; + } } rc = (codecParameterTable != NULL) ? SQLITE_OK : SQLITE_NOMEM; @@ -364881,10 +373473,35 @@ sqlite3mcRegisterCipher(const CipherDescriptor* desc, const CipherParams* params if (!cipherParams) return SQLITE_NOMEM; + /* Copy parameters */ + { + int n; + for (n = 0; n < np; ++n) + { + char* paramName = (char*)sqlite3_malloc((int)strlen(params[n].m_name) + 1); + if (paramName == NULL) + { + /* Memory allocation for parameter names failed, clean up */ + int k; + for (k = n - 1; k >= 0; --k) + { + sqlite3_free((char*)cipherParams[k].m_name); + } + sqlite3_free(cipherParams); + return SQLITE_NOMEM; + } + strcpy(paramName, params[n].m_name); + cipherParams[n] = params[n]; + cipherParams[n].m_name = paramName; + } + /* Add sentinel */ + cipherParams[n] = params[n]; + cipherParams[n].m_name = globalSentinelName; + } + /* Check for */ if (globalCipherCount < CODEC_COUNT_MAX) { - int n; char* cipherName; ++globalCipherCount; cipherName = globalCipherNameTable[globalCipherCount].m_name; @@ -364897,18 +373514,6 @@ sqlite3mcRegisterCipher(const CipherDescriptor* desc, const CipherParams* params globalCodecParameterTable[globalCipherCount].m_id = globalCipherCount; globalCodecParameterTable[globalCipherCount].m_params = cipherParams; - /* Copy parameters */ - for (n = 0; n < np; ++n) - { - char* paramName = (char*) sqlite3_malloc((int)strlen(params[n].m_name) + 1); - strcpy(paramName, params[n].m_name); - cipherParams[n] = params[n]; - cipherParams[n].m_name = paramName; - } - /* Add sentinel */ - cipherParams[n] = params[n]; - cipherParams[n].m_name = globalSentinelName; - /* Make cipher default, if requested */ if (makeDefault) { @@ -364999,6 +373604,8 @@ sqlite3mcTermCipherTables() sqlite3_free((char*) params[k].m_name); } sqlite3_free(globalCodecParameterTable[n].m_params); + globalCodecParameterTable[n].m_params = NULL; + globalCodecParameterTable[n].m_name[0] = 0; } } globalCipherCount = 0; @@ -365052,6 +373659,12 @@ sqlite3mc_initialize(const char* arg) } #endif + if (rc != SQLITE_OK) + { + /* Initialization failed, clean up cipher tables */ + sqlite3mcTermCipherTables(); + } + /* ** Initialize and register MultiCipher VFS as default VFS ** if it isn't already registered @@ -365063,6 +373676,11 @@ sqlite3mc_initialize(const char* arg) { /* Add encryption VFS shim to default VFS */ rc = sqlite3mc_vfs_create(NULL, 1); + if (rc != SQLITE_OK) + { + /* Registering MultiCipher VFS failed, clean up */ + sqlite3mc_shutdown(); + } } } return rc; diff --git a/sqlite3mc/sqlite3mc_amalgamation.h b/sqlite3mc/sqlite3mc_amalgamation.h index cdc9d86..325f106 100644 --- a/sqlite3mc/sqlite3mc_amalgamation.h +++ b/sqlite3mc/sqlite3mc_amalgamation.h @@ -30,10 +30,10 @@ #define SQLITE3MC_VERSION_H_ #define SQLITE3MC_VERSION_MAJOR 2 -#define SQLITE3MC_VERSION_MINOR 5 +#define SQLITE3MC_VERSION_MINOR 6 #define SQLITE3MC_VERSION_RELEASE 1 #define SQLITE3MC_VERSION_SUBRELEASE 0 -#define SQLITE3MC_VERSION_STRING "SQLite3 Multiple Ciphers 2.5.1" +#define SQLITE3MC_VERSION_STRING "SQLite3 Multiple Ciphers 2.6.1" #endif /* SQLITE3MC_VERSION_H_ */ /*** End of #include "sqlite3mc_version.h" ***/ @@ -192,12 +192,12 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.53.4" -#define SQLITE_VERSION_NUMBER 3053004 -#define SQLITE_SOURCE_ID "2026-07-24 19:02:57 bf7c7f30031888f4e796e429ab3978879485813aaca6f641c7b33e4e09459bcc" -#define SQLITE_SCM_BRANCH "branch-3.53" -#define SQLITE_SCM_TAGS "release version-3.53.4" -#define SQLITE_SCM_DATETIME "2026-07-24T19:02:57.525Z" +#define SQLITE_VERSION "3.54.0" +#define SQLITE_VERSION_NUMBER 3054000 +#define SQLITE_SOURCE_ID "2026-10-09 15:46:58 be8d059e9a49089ab2dce5ed26dd87aaf598fdc5fbe0b107c0dd758464bcd5e3" +#define SQLITE_SCM_BRANCH "trunk" +#define SQLITE_SCM_TAGS "release major-release version-3.54.0" +#define SQLITE_SCM_DATETIME "2026-10-09T15:46:58.543Z" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -509,7 +509,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_FULL 13 /* Insertion failed because database is full */ #define SQLITE_CANTOPEN 14 /* Unable to open the database file */ #define SQLITE_PROTOCOL 15 /* Database lock protocol error */ -#define SQLITE_EMPTY 16 /* Internal use only */ +#define SQLITE_EMPTY 16 /* No content */ #define SQLITE_SCHEMA 17 /* The database schema changed */ #define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ #define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ @@ -3006,8 +3006,9 @@ SQLITE_API int sqlite3_is_interrupted(sqlite3*); ** These routines are useful during command-line input to determine if the ** currently entered text seems to form a complete SQL statement or ** if additional input is needed before sending the text into -** SQLite for parsing. ^These routines return 1 if the input string -** appears to be a complete SQL statement. ^A statement is judged to be +** SQLite for parsing. ^The sqlite3_complete(X) and sqlite3_complete16(X) +** routines return 1 if the input string X appears to be a complete SQL +** statement. ^A statement is judged to be ** complete if it ends with a semicolon token and is not a prefix of a ** well-formed CREATE TRIGGER statement. ^Semicolons that are embedded within ** string literals or quoted identifier names or comments are not @@ -3015,11 +3016,25 @@ SQLITE_API int sqlite3_is_interrupted(sqlite3*); ** embedded) and thus do not count as a statement terminator. ^Whitespace ** and comments that follow the final semicolon are ignored. ** -** ^These routines return 0 if the statement is incomplete. ^If a -** memory allocation fails, then SQLITE_NOMEM is returned. -** -** ^These routines do not parse the SQL statements and thus -** will not detect syntactically incorrect SQL. +** ^The sqlite3_complete(X) and sqlite3_complete16(X) routines return 0 +** if the statement is incomplete. ^If a memory allocation fails, then +** SQLITE_NOMEM is returned. +** +** The [sqlite3_incomplete(X)] routine is similar to [sqlite3_complete(X)] +** except that sqlite3_incomplete(X) returns SQLITE_OK if the input X is +** complete, SQLITE_EMPTY if input X consists entirely of whitespace and/or +** comments, SQLITE_MISUSE if X is a NULL pointer, and some other non-zero +** value if X is incomplete. The non-zero return from +** sqlite3_incomplete(X) contains additional information about what is +** needed to complete the input X. See the header comment on the +** implemenation of the sqlite3_incomplete() routine for a full description +** of its non-zero return values. The sqlite3_incomplete(X) interface +** is only available for UTF-8 text. +** +** ^None of these routines do a full parse the SQL statements and thus +** will not detect syntactically incorrect SQL. They only determine if +** input text has properly terminated comments, string literals, and +** quoted identifiers, and if the statement ends with a semicolon. ** ** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior ** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked @@ -3027,14 +3042,15 @@ SQLITE_API int sqlite3_is_interrupted(sqlite3*); ** then the return value from sqlite3_complete16() will be non-zero ** regardless of whether or not the input SQL is complete.)^ ** -** The input to [sqlite3_complete()] must be a zero-terminated -** UTF-8 string. +** The X input to [sqlite3_complete(X)] and [sqlite3_incomplete(X)] +** must be a zero-terminated UTF-8 string. ** ** The input to [sqlite3_complete16()] must be a zero-terminated ** UTF-16 string in native byte order. */ SQLITE_API int sqlite3_complete(const char *sql); SQLITE_API int sqlite3_complete16(const void *sql); +SQLITE_API sqlite3_int64 sqlite3_incomplete(const char *sql); /* ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors @@ -3447,7 +3463,7 @@ SQLITE_API void sqlite3_randomness(int N, void *P); ** ** ^The first parameter to the authorizer callback is a copy of the third ** parameter to the sqlite3_set_authorizer() interface. ^The second parameter -** to the callback is an integer [SQLITE_COPY | action code] that specifies +** to the callback is an integer [SQLITE_READ | action code] that specifies ** the particular action to be authorized. ^The third through sixth parameters ** to the callback are either NULL pointers or zero-terminated strings ** that contain additional details about the action to be authorized. @@ -3490,21 +3506,33 @@ SQLITE_API void sqlite3_randomness(int N, void *P); ** previous call.)^ ^Disable the authorizer by installing a NULL callback. ** The authorizer is disabled by default. ** -** The authorizer callback must not do anything that will modify +**

    Limitations And Caveats

      +** +**
    • The authorizer callback must not do anything that will modify ** the database connection that invoked the authorizer callback. ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their ** database connections for the meaning of "modify" in this paragraph. ** -** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the +**
    • ^When [sqlite3_prepare_v2()] is used to prepare a statement, the ** statement might be re-prepared during [sqlite3_step()] due to a ** schema change. Hence, the application should ensure that the ** correct authorizer callback remains in place during the [sqlite3_step()]. ** -** ^Note that the authorizer callback is invoked only during +**
    • ^The authorizer callback is invoked only during ** [sqlite3_prepare()] or its variants. Authorization is not ** performed during statement evaluation in [sqlite3_step()], unless ** as stated in the previous paragraph, sqlite3_step() invokes ** sqlite3_prepare_v2() to reprepare a statement after a schema change. +** +**
    • Authorizer callbacks for the expressions of a +** [generated column] are invoked when the schema is parsed (and specifically +** when the [CREATE TABLE] statement that contains the generated column is +** parsed) not when the generated column is used in a DML statement. +** This is deliberate, as one of the purposes of generated columns +** is to give schema designers the ability to provide gated access +** to privileged columns and/or functions. +** +**
    */ SQLITE_API int sqlite3_set_authorizer( sqlite3*, @@ -3545,6 +3573,11 @@ SQLITE_API int sqlite3_set_authorizer( ** is the name of the inner-most trigger or view that is responsible for ** the access attempt or NULL if this access attempt is directly from ** top-level SQL code. +** +** The case of strings in the 3rd through the 6th argument to the +** authorization callback is arbitrary. Authorization callbacks +** implementations should use [sqlite3_stricmp()] or similar when +** doing comparisons against those values. */ /******************************************* 3rd ************ 4th ***********/ #define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */ @@ -3579,9 +3612,14 @@ SQLITE_API int sqlite3_set_authorizer( #define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */ #define SQLITE_FUNCTION 31 /* NULL Function Name */ #define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ -#define SQLITE_COPY 0 /* No longer used */ #define SQLITE_RECURSIVE 33 /* NULL NULL */ +/* +** Note: The SQLITE_COPY macro (with value 0) used to be one of the +** action codes above. That macro has now been repurposed as a possible +** value to the 3rd argument to sqlite3_result_str(). +*/ + /* ** CAPI3REF: Deprecated Tracing And Profiling Functions ** DEPRECATED @@ -4088,8 +4126,7 @@ SQLITE_API int sqlite3_open_v2( ** ** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a ** 64-bit signed integer and returns that integer, or D if P does not -** exist. If the value of P is something other than an integer, then -** zero is returned. +** exist or if the value of P is something other than an integer. ** ** The sqlite3_uri_key(F,N) returns a pointer to the name (not ** the value) of the N-th query parameter for filename F, or a NULL @@ -4450,6 +4487,14 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** [[SQLITE_LIMIT_WORKER_THREADS]] ^(
    SQLITE_LIMIT_WORKER_THREADS
    **
    The maximum number of auxiliary worker threads that a single ** [prepared statement] may start.
    )^ +** +** [[SQLITE_LIMIT_SCHEMA]] ^(
    SQLITE_LIMIT_SCHEMA
    +**
    The maximum number of objects (tables, indexes, triggers, and views) +** defined by the database schema.
    )^ +** +** [[SQLITE_LIMIT_TRIGGER_STEPS]] ^(
    SQLITE_LIMIT_TRIGGER_STEPS
    +**
    The maximum number of SQL statements that can be contained within +** a single trigger.
    )^ ** */ #define SQLITE_LIMIT_LENGTH 0 @@ -4465,6 +4510,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); #define SQLITE_LIMIT_TRIGGER_DEPTH 10 #define SQLITE_LIMIT_WORKER_THREADS 11 #define SQLITE_LIMIT_PARSER_DEPTH 12 +#define SQLITE_LIMIT_SCHEMA 13 +#define SQLITE_LIMIT_TRIGGER_STEPS 14 /* ** CAPI3REF: Prepare Flags @@ -4576,6 +4623,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** the nul-terminator. ** Note that nByte measures the length of the input in bytes, not ** characters, even for the UTF-16 interfaces. +** For the sqlite3_prepare16() and sqlite3_prepare16_v2() interfaces, +** the nByte value must be even or undefined behavior can result. ** ** ^If pzTail is not NULL then *pzTail is made to point to the first byte ** past the end of the first SQL statement in zSql. These routines only @@ -5322,7 +5371,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** [prepared statement]. ^In the "v2" interface, ** the more specific error code is returned directly by sqlite3_step(). ** -** [SQLITE_MISUSE] means that the this routine was called inappropriately. +** [SQLITE_MISUSE] means that this routine was called inappropriately. ** Perhaps it was called on a [prepared statement] that has ** already been [sqlite3_finalize | finalized] or on one that had ** previously returned [SQLITE_ERROR] or [SQLITE_DONE]. Or it could @@ -6495,7 +6544,11 @@ typedef void (*sqlite3_destructor_type)(void*); ** ** ^The sqlite3_result_zeroblob(C,N) and sqlite3_result_zeroblob64(C,N) ** interfaces set the result of the application-defined function to be -** a BLOB containing all zero bytes and N bytes in size. +** a BLOB containing all zero bytes and N bytes in size. The +** zeroblob64(C,N) interface returns a [result code], which is normally +** [SQLITE_OK] but might be some other value if the requested operation +** could not be complete, for example if insufficient memory is available +** or if the value of N is out of range. ** ** ^The sqlite3_result_double() interface sets the result from ** an application-defined function to be a floating point value specified @@ -8833,8 +8886,8 @@ SQLITE_API int sqlite3_keyword_check(const char*,int); **
  • ^The sqlite3_str object is created using [sqlite3_str_new()]. **
  • ^Text is appended to the sqlite3_str object using various ** methods, such as [sqlite3_str_appendf()]. -**
  • ^The sqlite3_str object is destroyed and the string it created -** is returned using the [sqlite3_str_finish()] interface. +**
  • The sqlite3_str object is destroyed and the string it created +** is returned using [sqlite3_str_finish()] or [sqlite3_result_str()]. ** */ typedef struct sqlite3_str sqlite3_str; @@ -8886,6 +8939,40 @@ SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3*); SQLITE_API char *sqlite3_str_finish(sqlite3_str*); SQLITE_API void sqlite3_str_free(sqlite3_str*); +/* +** CAPI3REF: Return A Dynamic String From an SQL Function +** +** The [sqlite3_result_str(C,S,F)] interface causes the +** [sqlite3_str|dynamic string] S to become the return value for the +** application-defined function or virtual table that uses +** [sqlite3_context] C. The F flag can be one of [SQLITE_COPY] +** or [SQLITE_XFER] or [SQLITE_FINISH]. +** +** If the dynamic string is invalid or incomplete due to an out-of-memory +** or string-too-large error, then this routine transfers that error +** over to the SQL function. +** +** If the F argument is SQLITE_COPY, then a copy of the dynamic string +** content is made and the dynamic string object is unchanged. +** If the F argument is SQLITE_XFER, then ownership of the content +** in the dynamic is transferred to the SQL function (via a pointer copy +** rather than a string copy) and the dynamic string is reset to an +** empty string. The SQLITE_FINISH value for F works like SQLITE_RESET +** except that it also invokes the [sqlite3_str_free(S)] destructor +** on the dynamic string object. +*/ +SQLITE_API void sqlite3_result_str(sqlite3_context*, sqlite3_str*, int); + +/* +** CAPI3REF: Control Flags For sqlite3_result_str() +** +** The following integers can be used as the third "F" argument +** to [sqlite3_result_str(C,S,F)]. +*/ +#define SQLITE_COPY 0 /* Results copied. Dynamic string unchanged */ +#define SQLITE_XFER 1 /* Results transfered. Dynamic string reset */ +#define SQLITE_FINISH 2 /* Like SQLITE_XFER, plus dynamic string freed */ + /* ** CAPI3REF: Add Content To A Dynamic String ** METHOD: sqlite3_str @@ -11251,8 +11338,19 @@ SQLITE_API unsigned char *sqlite3_serialize( ** used. The serialized database P is N bytes in size. M is the size ** of the buffer P, which might be larger than N. If M is larger than ** N, and the SQLITE_DESERIALIZE_READONLY bit is not set in F, then -** SQLite is permitted to add content to the in-memory database as -** long as the total size does not exceed M bytes. +** SQLite is permitted to add content to the in-memory database, in +** page-sized chunks, as long as the total size does not exceed M bytes. +** +** The parameter M must be greater than or equal to N. Ideally, M +** should have a value which is N+(512×K)+20 where K determines how +** must extra space is available to hold new content as the database +** grows. K can be 0 if the database is read-only. +** +** If the database content in P is malformed in a malicious way then +** it is possible that SQLite might try to read a few more than N bytes +** from P. If the veracity of the database content P is uncertain, +** then applications are advised to allocate about 20 extra bytes on +** the end of the P buffer to avoid a memory error. ** ** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will ** invoke sqlite3_free() on the serialization buffer when the database @@ -14777,7 +14875,7 @@ struct sqlite3_api_routines { const char * (*libversion)(void); int (*libversion_number)(void); void *(*malloc)(int); - char * (*mprintf)(const char*,...); + char *(SQLITE_CDECL*mprintf)(const char*,...); int (*open)(const char*,sqlite3**); int (*open16)(const void*,sqlite3**); int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); @@ -14798,11 +14896,11 @@ struct sqlite3_api_routines { void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*)); void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*)); void (*result_value)(sqlite3_context*,sqlite3_value*); - void * (*rollback_hook)(sqlite3*,void(*)(void*),void*); + void *(*rollback_hook)(sqlite3*,void(*)(void*),void*); int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, const char*,const char*),void*); void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); - char * (*xsnprintf)(int,char*,const char*,...); + char *(SQLITE_CDECL*xsnprintf)(int,char*,const char*,...); int (*step)(sqlite3_stmt*); int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, char const**,char const**,int*,int*,int*); @@ -14866,7 +14964,7 @@ struct sqlite3_api_routines { int (*xthreadsafe)(void); void (*result_zeroblob)(sqlite3_context*,int); void (*result_error_code)(sqlite3_context*,int); - int (*test_control)(int, ...); + int (SQLITE_CDECL*test_control)(int, ...); void (*randomness)(int,void*); sqlite3 *(*context_db_handle)(sqlite3_context*); int (*extended_result_codes)(sqlite3*,int); @@ -14886,11 +14984,11 @@ struct sqlite3_api_routines { void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*), void(*xDestroy)(void*)); - int (*db_config)(sqlite3*,int,...); + int (SQLITE_CDECL*db_config)(sqlite3*,int,...); sqlite3_mutex *(*db_mutex)(sqlite3*); int (*db_status)(sqlite3*,int,int*,int*,int); int (*extended_errcode)(sqlite3*); - void (*log)(int,const char*,...); + void (SQLITE_CDECL*log)(int,const char*,...); sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64); const char *(*sourceid)(void); int (*stmt_status)(sqlite3_stmt*,int,int); @@ -14900,7 +14998,7 @@ struct sqlite3_api_routines { int (*wal_checkpoint)(sqlite3*,const char*); void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); - int (*vtab_config)(sqlite3*,int op,...); + int (SQLITE_CDECL*vtab_config)(sqlite3*,int op,...); int (*vtab_on_conflict)(sqlite3*); /* Version 3.7.16 and later */ int (*close_v2)(sqlite3*); @@ -14969,7 +15067,7 @@ struct sqlite3_api_routines { int (*keyword_check)(const char*,int); sqlite3_str *(*str_new)(sqlite3*); char *(*str_finish)(sqlite3_str*); - void (*str_appendf)(sqlite3_str*, const char *zFormat, ...); + void (SQLITE_CDECL*str_appendf)(sqlite3_str*, const char *zFormat, ...); void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list); void (*str_append)(sqlite3_str*, const char *zIn, int N); void (*str_appendall)(sqlite3_str*, const char *zIn); @@ -15044,6 +15142,9 @@ struct sqlite3_api_routines { void (*str_free)(sqlite3_str*); int (*carray_bind)(sqlite3_stmt*,int,void*,int,int,void(*)(void*)); int (*carray_bind_v2)(sqlite3_stmt*,int,void*,int,int,void(*)(void*),void*); + /* Version 3.54.0 and later */ + sqlite3_int64 (*incomplete)(const char*); + void (*result_str)(sqlite3_context*,sqlite3_str*,int); }; /* @@ -15387,6 +15488,9 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_str_free sqlite3_api->str_free #define sqlite3_carray_bind sqlite3_api->carray_bind #define sqlite3_carray_bind_v2 sqlite3_api->carray_bind_v2 +/* Version 3.54.0 and later */ +#define sqlite3_incomplete sqlite3_api->incomplete +#define sqlite3_result_str sqlite3_api->result_str #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) diff --git a/src/lib.rs b/src/lib.rs index 64e3dc7..4f3f295 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,10 +3,10 @@ use std::path::Path; /// SQLite3 Multiple Ciphers release the vendored amalgamation comes from. -pub const SQLITE3MC_VERSION: &str = "2.5.1"; +pub const SQLITE3MC_VERSION: &str = "2.6.1"; /// SQLite release that amalgamation wraps. -pub const SQLITE_VERSION: &str = "3.53.4"; +pub const SQLITE_VERSION: &str = "3.54.0"; /// Amalgamation source inside [`source_dir`], under its upstream name. pub const SOURCE_FILE: &str = "sqlite3mc_amalgamation.c"; diff --git a/upgrade.sh b/upgrade.sh index 55229c3..951524c 100755 --- a/upgrade.sh +++ b/upgrade.sh @@ -2,9 +2,9 @@ # Re-vendors the pinned release byte for byte, trusting the pinned checksum only while the release's signed SHA256SUMS lists it. bump.sh moves the pins. -SQLITE3MC_VERSION="2.5.1" -SQLITE_VERSION="3.53.4" -ARCHIVE_SHA256="4125f8ff275ea953dabb3289331b20a0e76d4fc060f57148f4a5df3bf3b0d5e0" +SQLITE3MC_VERSION="2.6.1" +SQLITE_VERSION="3.54.0" +ARCHIVE_SHA256="3f25af603566a23c821d8e581778b5ece2a541d2435776de57b8d845c176815a" cd "$(dirname "$0")" . ./sigstore.sh