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
+**
+** - 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*,
@@ -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; i";
const char *zEnd = "";
const char *zEllipsis = "...";
- int iCol = -1;
- int nToken = 15; /* Default number of tokens in snippet */
+ i64 iCol = -1;
+ i64 nToken = 15; /* Default number of tokens in snippet */
/* There must be at least one argument passed to this function (otherwise
** the non-overloaded version would have been called instead of this one).
@@ -197872,11 +198848,12 @@ static void fts3SnippetFunc(
return;
}
if( fts3FunctionArg(pContext, "snippet", apVal[0], &pCsr) ) return;
+ pTab = (Fts3Table *)pCsr->base.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