11027 lines
423 KiB
Diff
11027 lines
423 KiB
Diff
diff --color -ruN node-v22.16.0/deps/sqlite/sqlite3.c node-modded/deps/sqlite/sqlite3.c
|
|
--- node-v22.16.0/deps/sqlite/sqlite3.c 2025-05-21 06:12:48.000000000 +0200
|
|
+++ node-modded/deps/sqlite/sqlite3.c 2025-07-17 16:20:17.619643827 +0200
|
|
@@ -1,6 +1,6 @@
|
|
/******************************************************************************
|
|
** This file is an amalgamation of many separate C source files from SQLite
|
|
-** version 3.49.1. By combining all the individual C code files into this
|
|
+** version 3.50.3. 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
|
|
@@ -18,7 +18,7 @@
|
|
** separate file. This file contains only code for the core SQLite library.
|
|
**
|
|
** The content in this amalgamation comes from Fossil check-in
|
|
-** 873d4e274b4988d260ba8354a9718324a1c2 with changes in files:
|
|
+** 3ce993b8657d6d9deda380a93cdd6404a8c8 with changes in files:
|
|
**
|
|
**
|
|
*/
|
|
@@ -452,7 +452,7 @@
|
|
**
|
|
** Since [version 3.6.18] ([dateof:3.6.18]),
|
|
** SQLite source code has been stored in the
|
|
-** <a href="http://www.fossil-scm.org/">Fossil configuration management
|
|
+** <a href="http://fossil-scm.org/">Fossil configuration management
|
|
** system</a>. ^The SQLITE_SOURCE_ID macro evaluates to
|
|
** a string which identifies a particular check-in of SQLite
|
|
** within its configuration management system. ^The SQLITE_SOURCE_ID
|
|
@@ -465,9 +465,9 @@
|
|
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
|
** [sqlite_version()] and [sqlite_source_id()].
|
|
*/
|
|
-#define SQLITE_VERSION "3.49.1"
|
|
-#define SQLITE_VERSION_NUMBER 3049001
|
|
-#define SQLITE_SOURCE_ID "2025-02-18 13:38:58 873d4e274b4988d260ba8354a9718324a1c26187a4ab4c1cc0227c03d0f10e70"
|
|
+#define SQLITE_VERSION "3.50.3"
|
|
+#define SQLITE_VERSION_NUMBER 3050003
|
|
+#define SQLITE_SOURCE_ID "2025-07-17 13:25:10 3ce993b8657d6d9deda380a93cdd6404a8c8ba1b185b2bc423703e41ae5f2543"
|
|
|
|
/*
|
|
** CAPI3REF: Run-Time Library Version Numbers
|
|
@@ -1482,6 +1482,12 @@
|
|
** the value that M is to be set to. Before returning, the 32-bit signed
|
|
** integer is overwritten with the previous value of M.
|
|
**
|
|
+** <li>[[SQLITE_FCNTL_BLOCK_ON_CONNECT]]
|
|
+** The [SQLITE_FCNTL_BLOCK_ON_CONNECT] opcode is used to configure the
|
|
+** VFS to block when taking a SHARED lock to connect to a wal mode database.
|
|
+** This is used to implement the functionality associated with
|
|
+** SQLITE_SETLK_BLOCK_ON_CONNECT.
|
|
+**
|
|
** <li>[[SQLITE_FCNTL_DATA_VERSION]]
|
|
** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to
|
|
** a database file. The argument is a pointer to a 32-bit unsigned integer.
|
|
@@ -1578,6 +1584,7 @@
|
|
#define SQLITE_FCNTL_CKSM_FILE 41
|
|
#define SQLITE_FCNTL_RESET_CACHE 42
|
|
#define SQLITE_FCNTL_NULL_IO 43
|
|
+#define SQLITE_FCNTL_BLOCK_ON_CONNECT 44
|
|
|
|
/* deprecated names */
|
|
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
|
|
@@ -2308,13 +2315,16 @@
|
|
**
|
|
** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt>
|
|
** <dd> ^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine
|
|
-** the default size of lookaside memory on each [database connection].
|
|
+** the default size of [lookaside memory] on each [database connection].
|
|
** The first argument is the
|
|
-** size of each lookaside buffer slot and the second is the number of
|
|
-** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE
|
|
-** sets the <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE]
|
|
-** option to [sqlite3_db_config()] can be used to change the lookaside
|
|
-** configuration on individual connections.)^ </dd>
|
|
+** size of each lookaside buffer slot ("sz") and the second is the number of
|
|
+** slots allocated to each database connection ("cnt").)^
|
|
+** ^(SQLITE_CONFIG_LOOKASIDE sets the <i>default</i> lookaside size.
|
|
+** The [SQLITE_DBCONFIG_LOOKASIDE] option to [sqlite3_db_config()] can
|
|
+** be used to change the lookaside configuration on individual connections.)^
|
|
+** The [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to change the
|
|
+** default lookaside configuration at compile-time.
|
|
+** </dd>
|
|
**
|
|
** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt>
|
|
** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is
|
|
@@ -2551,31 +2561,50 @@
|
|
** [[SQLITE_DBCONFIG_LOOKASIDE]]
|
|
** <dt>SQLITE_DBCONFIG_LOOKASIDE</dt>
|
|
** <dd> The SQLITE_DBCONFIG_LOOKASIDE option is used to adjust the
|
|
-** configuration of the lookaside memory allocator within a database
|
|
+** configuration of the [lookaside memory allocator] within a database
|
|
** connection.
|
|
** The arguments to the SQLITE_DBCONFIG_LOOKASIDE option are <i>not</i>
|
|
** in the [DBCONFIG arguments|usual format].
|
|
** The SQLITE_DBCONFIG_LOOKASIDE option takes three arguments, not two,
|
|
** so that a call to [sqlite3_db_config()] that uses SQLITE_DBCONFIG_LOOKASIDE
|
|
** should have a total of five parameters.
|
|
-** ^The first argument (the third parameter to [sqlite3_db_config()] is a
|
|
+** <ol>
|
|
+** <li><p>The first argument ("buf") is a
|
|
** pointer to a memory buffer to use for lookaside memory.
|
|
-** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb
|
|
-** may be NULL in which case SQLite will allocate the
|
|
-** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the
|
|
-** size of each lookaside buffer slot. ^The third argument is the number of
|
|
-** slots. The size of the buffer in the first argument must be greater than
|
|
-** or equal to the product of the second and third arguments. The buffer
|
|
-** must be aligned to an 8-byte boundary. ^If the second argument to
|
|
-** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally
|
|
-** rounded down to the next smaller multiple of 8. ^(The lookaside memory
|
|
+** The first argument may be NULL in which case SQLite will allocate the
|
|
+** lookaside buffer itself using [sqlite3_malloc()].
|
|
+** <li><P>The second argument ("sz") is the
|
|
+** size of each lookaside buffer slot. Lookaside is disabled if "sz"
|
|
+** is less than 8. The "sz" argument should be a multiple of 8 less than
|
|
+** 65536. If "sz" does not meet this constraint, it is reduced in size until
|
|
+** it does.
|
|
+** <li><p>The third argument ("cnt") is the number of slots. Lookaside is disabled
|
|
+** if "cnt"is less than 1. The "cnt" value will be reduced, if necessary, so
|
|
+** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt"
|
|
+** parameter is usually chosen so that the product of "sz" and "cnt" is less
|
|
+** than 1,000,000.
|
|
+** </ol>
|
|
+** <p>If the "buf" argument is not NULL, then it must
|
|
+** point to a memory buffer with a size that is greater than
|
|
+** or equal to the product of "sz" and "cnt".
|
|
+** The buffer must be aligned to an 8-byte boundary.
|
|
+** The lookaside memory
|
|
** configuration for a database connection can only be changed when that
|
|
** connection is not currently using lookaside memory, or in other words
|
|
-** when the "current value" returned by
|
|
-** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero.
|
|
+** when the value returned by [SQLITE_DBSTATUS_LOOKASIDE_USED] is zero.
|
|
** Any attempt to change the lookaside memory configuration when lookaside
|
|
** memory is in use leaves the configuration unchanged and returns
|
|
-** [SQLITE_BUSY].)^</dd>
|
|
+** [SQLITE_BUSY].
|
|
+** If the "buf" argument is NULL and an attempt
|
|
+** to allocate memory based on "sz" and "cnt" fails, then
|
|
+** lookaside is silently disabled.
|
|
+** <p>
|
|
+** The [SQLITE_CONFIG_LOOKASIDE] configuration option can be used to set the
|
|
+** default lookaside configuration at initialization. The
|
|
+** [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to set the default lookaside
|
|
+** configuration at compile-time. Typical values for lookaside are 1200 for
|
|
+** "sz" and 40 to 100 for "cnt".
|
|
+** </dd>
|
|
**
|
|
** [[SQLITE_DBCONFIG_ENABLE_FKEY]]
|
|
** <dt>SQLITE_DBCONFIG_ENABLE_FKEY</dt>
|
|
@@ -3313,6 +3342,44 @@
|
|
SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
|
|
|
|
/*
|
|
+** CAPI3REF: Set the Setlk Timeout
|
|
+** METHOD: sqlite3
|
|
+**
|
|
+** This routine is only useful in SQLITE_ENABLE_SETLK_TIMEOUT builds. If
|
|
+** the VFS supports blocking locks, it sets the timeout in ms used by
|
|
+** eligible locks taken on wal mode databases by the specified database
|
|
+** handle. In non-SQLITE_ENABLE_SETLK_TIMEOUT builds, or if the VFS does
|
|
+** not support blocking locks, this function is a no-op.
|
|
+**
|
|
+** Passing 0 to this function disables blocking locks altogether. Passing
|
|
+** -1 to this function requests that the VFS blocks for a long time -
|
|
+** indefinitely if possible. The results of passing any other negative value
|
|
+** are undefined.
|
|
+**
|
|
+** Internally, each SQLite database handle store two timeout values - the
|
|
+** busy-timeout (used for rollback mode databases, or if the VFS does not
|
|
+** support blocking locks) and the setlk-timeout (used for blocking locks
|
|
+** on wal-mode databases). The sqlite3_busy_timeout() method sets both
|
|
+** values, this function sets only the setlk-timeout value. Therefore,
|
|
+** to configure separate busy-timeout and setlk-timeout values for a single
|
|
+** database handle, call sqlite3_busy_timeout() followed by this function.
|
|
+**
|
|
+** Whenever the number of connections to a wal mode database falls from
|
|
+** 1 to 0, the last connection takes an exclusive lock on the database,
|
|
+** then checkpoints and deletes the wal file. While it is doing this, any
|
|
+** new connection that tries to read from the database fails with an
|
|
+** SQLITE_BUSY error. Or, if the SQLITE_SETLK_BLOCK_ON_CONNECT flag is
|
|
+** passed to this API, the new connection blocks until the exclusive lock
|
|
+** has been released.
|
|
+*/
|
|
+SQLITE_API int sqlite3_setlk_timeout(sqlite3*, int ms, int flags);
|
|
+
|
|
+/*
|
|
+** CAPI3REF: Flags for sqlite3_setlk_timeout()
|
|
+*/
|
|
+#define SQLITE_SETLK_BLOCK_ON_CONNECT 0x01
|
|
+
|
|
+/*
|
|
** CAPI3REF: Convenience Routines For Running Queries
|
|
** METHOD: sqlite3
|
|
**
|
|
@@ -4331,7 +4398,7 @@
|
|
**
|
|
** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
|
|
** database filename D with corresponding journal file J and WAL file W and
|
|
-** with N URI parameters key/values pairs in the array P. The result from
|
|
+** an array P of N URI Key/Value pairs. The result from
|
|
** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that
|
|
** is safe to pass to routines like:
|
|
** <ul>
|
|
@@ -5012,7 +5079,7 @@
|
|
** METHOD: sqlite3_stmt
|
|
**
|
|
** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants,
|
|
-** literals may be replaced by a [parameter] that matches one of following
|
|
+** literals may be replaced by a [parameter] that matches one of the following
|
|
** templates:
|
|
**
|
|
** <ul>
|
|
@@ -5057,7 +5124,7 @@
|
|
**
|
|
** [[byte-order determination rules]] ^The byte-order of
|
|
** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF)
|
|
-** found in first character, which is removed, or in the absence of a BOM
|
|
+** found in the first character, which is removed, or in the absence of a BOM
|
|
** the byte order is the native byte order of the host
|
|
** machine for sqlite3_bind_text16() or the byte order specified in
|
|
** the 6th parameter for sqlite3_bind_text64().)^
|
|
@@ -5077,7 +5144,7 @@
|
|
** or sqlite3_bind_text16() or sqlite3_bind_text64() then
|
|
** that parameter must be the byte offset
|
|
** where the NUL terminator would occur assuming the string were NUL
|
|
-** terminated. If any NUL characters occurs at byte offsets less than
|
|
+** terminated. If any NUL characters occur at byte offsets less than
|
|
** the value of the fourth parameter then the resulting string value will
|
|
** contain embedded NULs. The result of expressions involving strings
|
|
** with embedded NULs is undefined.
|
|
@@ -5289,7 +5356,7 @@
|
|
** METHOD: sqlite3_stmt
|
|
**
|
|
** ^These routines provide a means to determine the database, table, and
|
|
-** table column that is the origin of a particular result column in
|
|
+** table column that is the origin of a particular result column in a
|
|
** [SELECT] statement.
|
|
** ^The name of the database or table or column can be returned as
|
|
** either a UTF-8 or UTF-16 string. ^The _database_ routines return
|
|
@@ -5427,7 +5494,7 @@
|
|
** other than [SQLITE_ROW] before any subsequent invocation of
|
|
** sqlite3_step(). Failure to reset the prepared statement using
|
|
** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
|
|
-** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1],
|
|
+** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1]),
|
|
** sqlite3_step() began
|
|
** calling [sqlite3_reset()] automatically in this circumstance rather
|
|
** than returning [SQLITE_MISUSE]. This is not considered a compatibility
|
|
@@ -5858,8 +5925,8 @@
|
|
**
|
|
** For best security, the [SQLITE_DIRECTONLY] flag is recommended for
|
|
** all application-defined SQL functions that do not need to be
|
|
-** used inside of triggers, view, CHECK constraints, or other elements of
|
|
-** the database schema. This flags is especially recommended for SQL
|
|
+** used inside of triggers, views, CHECK constraints, or other elements of
|
|
+** the database schema. This flag is especially recommended for SQL
|
|
** functions that have side effects or reveal internal application state.
|
|
** Without this flag, an attacker might be able to modify the schema of
|
|
** a database file to include invocations of the function with parameters
|
|
@@ -5890,7 +5957,7 @@
|
|
** [user-defined window functions|available here].
|
|
**
|
|
** ^(If the final parameter to sqlite3_create_function_v2() or
|
|
-** sqlite3_create_window_function() is not NULL, then it is destructor for
|
|
+** sqlite3_create_window_function() is not NULL, then it is the destructor for
|
|
** the application data pointer. The destructor is invoked when the function
|
|
** is deleted, either by being overloaded or when the database connection
|
|
** closes.)^ ^The destructor is also invoked if the call to
|
|
@@ -6290,7 +6357,7 @@
|
|
** METHOD: sqlite3_value
|
|
**
|
|
** ^The sqlite3_value_dup(V) interface makes a copy of the [sqlite3_value]
|
|
-** object D and returns a pointer to that copy. ^The [sqlite3_value] returned
|
|
+** object V and returns a pointer to that copy. ^The [sqlite3_value] returned
|
|
** is a [protected sqlite3_value] object even if the input is not.
|
|
** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a
|
|
** memory allocation fails. ^If V is a [pointer value], then the result
|
|
@@ -6328,7 +6395,7 @@
|
|
** allocation error occurs.
|
|
**
|
|
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
|
|
-** determined by the N parameter on first successful call. Changing the
|
|
+** determined by the N parameter on the first successful call. Changing the
|
|
** value of N in any subsequent call to sqlite3_aggregate_context() within
|
|
** the same aggregate function instance will not resize the memory
|
|
** allocation.)^ Within the xFinal callback, it is customary to set
|
|
@@ -6490,7 +6557,7 @@
|
|
**
|
|
** Security Warning: These interfaces should not be exposed in scripting
|
|
** languages or in other circumstances where it might be possible for an
|
|
-** an attacker to invoke them. Any agent that can invoke these interfaces
|
|
+** attacker to invoke them. Any agent that can invoke these interfaces
|
|
** can probably also take control of the process.
|
|
**
|
|
** Database connection client data is only available for SQLite
|
|
@@ -6604,7 +6671,7 @@
|
|
** pointed to by the 2nd parameter are taken as the application-defined
|
|
** function result. If the 3rd parameter is non-negative, then it
|
|
** must be the byte offset into the string where the NUL terminator would
|
|
-** appear if the string where NUL terminated. If any NUL characters occur
|
|
+** appear if the string were NUL terminated. If any NUL characters occur
|
|
** in the string at a byte offset that is less than the value of the 3rd
|
|
** parameter, then the resulting string will contain embedded NULs and the
|
|
** result of expressions operating on strings with embedded NULs is undefined.
|
|
@@ -6662,7 +6729,7 @@
|
|
** string and preferably a string literal. The sqlite3_result_pointer()
|
|
** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
|
|
**
|
|
-** If these routines are called from within the different thread
|
|
+** If these routines are called from within a different thread
|
|
** than the one containing the application-defined function that received
|
|
** the [sqlite3_context] pointer, the results are undefined.
|
|
*/
|
|
@@ -7068,7 +7135,7 @@
|
|
** METHOD: sqlite3
|
|
**
|
|
** ^The sqlite3_db_name(D,N) interface returns a pointer to the schema name
|
|
-** for the N-th database on database connection D, or a NULL pointer of N is
|
|
+** for the N-th database on database connection D, or a NULL pointer if N is
|
|
** out of range. An N value of 0 means the main database file. An N of 1 is
|
|
** the "temp" schema. Larger values of N correspond to various ATTACH-ed
|
|
** databases.
|
|
@@ -7163,7 +7230,7 @@
|
|
** <dd>The SQLITE_TXN_READ state means that the database is currently
|
|
** in a read transaction. Content has been read from the database file
|
|
** but nothing in the database file has changed. The transaction state
|
|
-** will advanced to SQLITE_TXN_WRITE if any changes occur and there are
|
|
+** will be advanced to SQLITE_TXN_WRITE if any changes occur and there are
|
|
** no other conflicting concurrent write transactions. The transaction
|
|
** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or
|
|
** [COMMIT].</dd>
|
|
@@ -7172,7 +7239,7 @@
|
|
** <dd>The SQLITE_TXN_WRITE state means that the database is currently
|
|
** in a write transaction. Content has been written to the database file
|
|
** but has not yet committed. The transaction state will change to
|
|
-** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].</dd>
|
|
+** SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].</dd>
|
|
*/
|
|
#define SQLITE_TXN_NONE 0
|
|
#define SQLITE_TXN_READ 1
|
|
@@ -7323,6 +7390,8 @@
|
|
**
|
|
** ^The second argument is a pointer to the function to invoke when a
|
|
** row is updated, inserted or deleted in a rowid table.
|
|
+** ^The update hook is disabled by invoking sqlite3_update_hook()
|
|
+** with a NULL pointer as the second parameter.
|
|
** ^The first argument to the callback is a copy of the third argument
|
|
** to sqlite3_update_hook().
|
|
** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE],
|
|
@@ -7451,7 +7520,7 @@
|
|
** CAPI3REF: Impose A Limit On Heap Size
|
|
**
|
|
** These interfaces impose limits on the amount of heap memory that will be
|
|
-** by all database connections within a single process.
|
|
+** used by all database connections within a single process.
|
|
**
|
|
** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the
|
|
** soft limit on the amount of heap memory that may be allocated by SQLite.
|
|
@@ -7509,7 +7578,7 @@
|
|
** </ul>)^
|
|
**
|
|
** The circumstances under which SQLite will enforce the heap limits may
|
|
-** changes in future releases of SQLite.
|
|
+** change in future releases of SQLite.
|
|
*/
|
|
SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
|
|
SQLITE_API sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 N);
|
|
@@ -7624,8 +7693,8 @@
|
|
** ^The entry point is zProc.
|
|
** ^(zProc may be 0, in which case SQLite will try to come up with an
|
|
** entry point name on its own. It first tries "sqlite3_extension_init".
|
|
-** If that does not work, it constructs a name "sqlite3_X_init" where the
|
|
-** X is consists of the lower-case equivalent of all ASCII alphabetic
|
|
+** If that does not work, it constructs a name "sqlite3_X_init" where
|
|
+** X consists of the lower-case equivalent of all ASCII alphabetic
|
|
** characters in the filename from the last "/" to the first following
|
|
** "." and omitting any initial "lib".)^
|
|
** ^The sqlite3_load_extension() interface returns
|
|
@@ -7696,7 +7765,7 @@
|
|
** ^(Even though the function prototype shows that xEntryPoint() takes
|
|
** no arguments and returns void, SQLite invokes xEntryPoint() with three
|
|
** arguments and expects an integer result as if the signature of the
|
|
-** entry point where as follows:
|
|
+** entry point were as follows:
|
|
**
|
|
** <blockquote><pre>
|
|
** int xEntryPoint(
|
|
@@ -7860,7 +7929,7 @@
|
|
** virtual table and might not be checked again by the byte code.)^ ^(The
|
|
** aConstraintUsage[].omit flag is an optimization hint. When the omit flag
|
|
** is left in its default setting of false, the constraint will always be
|
|
-** checked separately in byte code. If the omit flag is change to true, then
|
|
+** checked separately in byte code. If the omit flag is changed to true, then
|
|
** the constraint may or may not be checked in byte code. In other words,
|
|
** when the omit flag is true there is no guarantee that the constraint will
|
|
** not be checked again using byte code.)^
|
|
@@ -7886,7 +7955,7 @@
|
|
** The xBestIndex method may optionally populate the idxFlags field with a
|
|
** mask of SQLITE_INDEX_SCAN_* flags. One such flag is
|
|
** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN]
|
|
-** output to show the idxNum has hex instead of as decimal. Another flag is
|
|
+** output to show the idxNum as hex instead of as decimal. Another flag is
|
|
** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will
|
|
** return at most one row.
|
|
**
|
|
@@ -8027,7 +8096,7 @@
|
|
** the implementation of the [virtual table module]. ^The fourth
|
|
** parameter is an arbitrary client data pointer that is passed through
|
|
** into the [xCreate] and [xConnect] methods of the virtual table module
|
|
-** when a new virtual table is be being created or reinitialized.
|
|
+** when a new virtual table is being created or reinitialized.
|
|
**
|
|
** ^The sqlite3_create_module_v2() interface has a fifth parameter which
|
|
** is a pointer to a destructor for the pClientData. ^SQLite will
|
|
@@ -8192,7 +8261,7 @@
|
|
** in *ppBlob. Otherwise an [error code] is returned and, unless the error
|
|
** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided
|
|
** the API is not misused, it is always safe to call [sqlite3_blob_close()]
|
|
-** on *ppBlob after this function it returns.
|
|
+** on *ppBlob after this function returns.
|
|
**
|
|
** This function fails with SQLITE_ERROR if any of the following are true:
|
|
** <ul>
|
|
@@ -8312,7 +8381,7 @@
|
|
**
|
|
** ^Returns the size in bytes of the BLOB accessible via the
|
|
** successfully opened [BLOB handle] in its only argument. ^The
|
|
-** incremental blob I/O routines can only read or overwriting existing
|
|
+** incremental blob I/O routines can only read or overwrite existing
|
|
** blob content; they cannot change the size of a blob.
|
|
**
|
|
** This routine only works on a [BLOB handle] which has been created
|
|
@@ -8462,7 +8531,7 @@
|
|
** ^The sqlite3_mutex_alloc() routine allocates a new
|
|
** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc()
|
|
** routine returns NULL if it is unable to allocate the requested
|
|
-** mutex. The argument to sqlite3_mutex_alloc() must one of these
|
|
+** mutex. The argument to sqlite3_mutex_alloc() must be one of these
|
|
** integer constants:
|
|
**
|
|
** <ul>
|
|
@@ -8695,7 +8764,7 @@
|
|
** CAPI3REF: Retrieve the mutex for a database connection
|
|
** METHOD: sqlite3
|
|
**
|
|
-** ^This interface returns a pointer the [sqlite3_mutex] object that
|
|
+** ^This interface returns a pointer to the [sqlite3_mutex] object that
|
|
** serializes access to the [database connection] given in the argument
|
|
** when the [threading mode] is Serialized.
|
|
** ^If the [threading mode] is Single-thread or Multi-thread then this
|
|
@@ -8818,7 +8887,7 @@
|
|
** CAPI3REF: SQL Keyword Checking
|
|
**
|
|
** These routines provide access to the set of SQL language keywords
|
|
-** recognized by SQLite. Applications can uses these routines to determine
|
|
+** recognized by SQLite. Applications can use these routines to determine
|
|
** whether or not a specific identifier needs to be escaped (for example,
|
|
** by enclosing in double-quotes) so as not to confuse the parser.
|
|
**
|
|
@@ -8986,7 +9055,7 @@
|
|
** content of the dynamic string under construction in X. The value
|
|
** returned by [sqlite3_str_value(X)] is managed by the sqlite3_str object X
|
|
** and might be freed or altered by any subsequent method on the same
|
|
-** [sqlite3_str] object. Applications must not used the pointer returned
|
|
+** [sqlite3_str] object. Applications must not use the pointer returned by
|
|
** [sqlite3_str_value(X)] after any subsequent method call on the same
|
|
** object. ^Applications may change the content of the string returned
|
|
** by [sqlite3_str_value(X)] as long as they do not write into any bytes
|
|
@@ -9072,7 +9141,7 @@
|
|
** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE]
|
|
** buffer and where forced to overflow to [sqlite3_malloc()]. The
|
|
** returned value includes allocations that overflowed because they
|
|
-** where too large (they were larger than the "sz" parameter to
|
|
+** were too large (they were larger than the "sz" parameter to
|
|
** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because
|
|
** no space was left in the page cache.</dd>)^
|
|
**
|
|
@@ -9156,28 +9225,29 @@
|
|
** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
|
|
** <dd>This parameter returns the number of malloc attempts that were
|
|
** satisfied using lookaside memory. Only the high-water value is meaningful;
|
|
-** the current value is always zero.)^
|
|
+** the current value is always zero.</dd>)^
|
|
**
|
|
** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]]
|
|
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt>
|
|
-** <dd>This parameter returns the number malloc attempts that might have
|
|
+** <dd>This parameter returns the number of malloc attempts that might have
|
|
** been satisfied using lookaside memory but failed due to the amount of
|
|
** memory requested being larger than the lookaside slot size.
|
|
** Only the high-water value is meaningful;
|
|
-** the current value is always zero.)^
|
|
+** the current value is always zero.</dd>)^
|
|
**
|
|
** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]]
|
|
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt>
|
|
-** <dd>This parameter returns the number malloc attempts that might have
|
|
+** <dd>This parameter returns the number of malloc attempts that might have
|
|
** been satisfied using lookaside memory but failed due to all lookaside
|
|
** memory already being in use.
|
|
** Only the high-water value is meaningful;
|
|
-** the current value is always zero.)^
|
|
+** the current value is always zero.</dd>)^
|
|
**
|
|
** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
|
|
** <dd>This parameter returns the approximate number of bytes of heap
|
|
** memory used by all pager caches associated with the database connection.)^
|
|
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
|
|
+** </dd>
|
|
**
|
|
** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]]
|
|
** ^(<dt>SQLITE_DBSTATUS_CACHE_USED_SHARED</dt>
|
|
@@ -9186,10 +9256,10 @@
|
|
** memory used by that pager cache is divided evenly between the attached
|
|
** connections.)^ In other words, if none of the pager caches associated
|
|
** with the database connection are shared, this request returns the same
|
|
-** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are
|
|
+** value as DBSTATUS_CACHE_USED. Or, if one or more of the pager caches are
|
|
** shared, the value returned by this call will be smaller than that returned
|
|
** by DBSTATUS_CACHE_USED. ^The highwater mark associated with
|
|
-** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0.
|
|
+** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0.</dd>
|
|
**
|
|
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
|
|
** <dd>This parameter returns the approximate number of bytes of heap
|
|
@@ -9199,6 +9269,7 @@
|
|
** schema memory is shared with other database connections due to
|
|
** [shared cache mode] being enabled.
|
|
** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0.
|
|
+** </dd>
|
|
**
|
|
** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt>
|
|
** <dd>This parameter returns the approximate number of bytes of heap
|
|
@@ -9235,7 +9306,7 @@
|
|
** been written to disk in the middle of a transaction due to the page
|
|
** cache overflowing. Transactions are more efficient if they are written
|
|
** to disk all at once. When pages spill mid-transaction, that introduces
|
|
-** additional overhead. This parameter can be used help identify
|
|
+** additional overhead. This parameter can be used to help identify
|
|
** inefficiencies that can be resolved by increasing the cache size.
|
|
** </dd>
|
|
**
|
|
@@ -9306,13 +9377,13 @@
|
|
** [[SQLITE_STMTSTATUS_SORT]] <dt>SQLITE_STMTSTATUS_SORT</dt>
|
|
** <dd>^This is the number of sort operations that have occurred.
|
|
** A non-zero value in this counter may indicate an opportunity to
|
|
-** improvement performance through careful use of indices.</dd>
|
|
+** improve performance through careful use of indices.</dd>
|
|
**
|
|
** [[SQLITE_STMTSTATUS_AUTOINDEX]] <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt>
|
|
** <dd>^This is the number of rows inserted into transient indices that
|
|
** were created automatically in order to help joins run faster.
|
|
** A non-zero value in this counter may indicate an opportunity to
|
|
-** improvement performance by adding permanent indices that do not
|
|
+** improve performance by adding permanent indices that do not
|
|
** need to be reinitialized each time the statement is run.</dd>
|
|
**
|
|
** [[SQLITE_STMTSTATUS_VM_STEP]] <dt>SQLITE_STMTSTATUS_VM_STEP</dt>
|
|
@@ -9321,19 +9392,19 @@
|
|
** to 2147483647. The number of virtual machine operations can be
|
|
** used as a proxy for the total work done by the prepared statement.
|
|
** If the number of virtual machine operations exceeds 2147483647
|
|
-** then the value returned by this statement status code is undefined.
|
|
+** then the value returned by this statement status code is undefined.</dd>
|
|
**
|
|
** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt>
|
|
** <dd>^This is the number of times that the prepare statement has been
|
|
** automatically regenerated due to schema changes or changes to
|
|
-** [bound parameters] that might affect the query plan.
|
|
+** [bound parameters] that might affect the query plan.</dd>
|
|
**
|
|
** [[SQLITE_STMTSTATUS_RUN]] <dt>SQLITE_STMTSTATUS_RUN</dt>
|
|
** <dd>^This is the number of times that the prepared statement has
|
|
** been run. A single "run" for the purposes of this counter is one
|
|
** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()].
|
|
** The counter is incremented on the first [sqlite3_step()] call of each
|
|
-** cycle.
|
|
+** cycle.</dd>
|
|
**
|
|
** [[SQLITE_STMTSTATUS_FILTER_MISS]]
|
|
** [[SQLITE_STMTSTATUS_FILTER HIT]]
|
|
@@ -9343,7 +9414,7 @@
|
|
** step was bypassed because a Bloom filter returned not-found. The
|
|
** corresponding SQLITE_STMTSTATUS_FILTER_MISS value is the number of
|
|
** times that the Bloom filter returned a find, and thus the join step
|
|
-** had to be processed as normal.
|
|
+** had to be processed as normal.</dd>
|
|
**
|
|
** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt>
|
|
** <dd>^This is the approximate number of bytes of heap memory
|
|
@@ -9448,9 +9519,9 @@
|
|
** SQLite will typically create one cache instance for each open database file,
|
|
** though this is not guaranteed. ^The
|
|
** first parameter, szPage, is the size in bytes of the pages that must
|
|
-** be allocated by the cache. ^szPage will always a power of two. ^The
|
|
+** be allocated by the cache. ^szPage will always be a power of two. ^The
|
|
** second parameter szExtra is a number of bytes of extra storage
|
|
-** associated with each page cache entry. ^The szExtra parameter will
|
|
+** associated with each page cache entry. ^The szExtra parameter will be
|
|
** a number less than 250. SQLite will use the
|
|
** extra szExtra bytes on each page to store metadata about the underlying
|
|
** database page on disk. The value passed into szExtra depends
|
|
@@ -9458,17 +9529,17 @@
|
|
** ^The third argument to xCreate(), bPurgeable, is true if the cache being
|
|
** created will be used to cache database pages of a file stored on disk, or
|
|
** false if it is used for an in-memory database. The cache implementation
|
|
-** does not have to do anything special based with the value of bPurgeable;
|
|
+** does not have to do anything special based upon the value of bPurgeable;
|
|
** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will
|
|
** never invoke xUnpin() except to deliberately delete a page.
|
|
** ^In other words, calls to xUnpin() on a cache with bPurgeable set to
|
|
** false will always have the "discard" flag set to true.
|
|
-** ^Hence, a cache created with bPurgeable false will
|
|
+** ^Hence, a cache created with bPurgeable set to false will
|
|
** never contain any unpinned pages.
|
|
**
|
|
** [[the xCachesize() page cache method]]
|
|
** ^(The xCachesize() method may be called at any time by SQLite to set the
|
|
-** suggested maximum cache-size (number of pages stored by) the cache
|
|
+** suggested maximum cache-size (number of pages stored) for the cache
|
|
** instance passed as the first argument. This is the value configured using
|
|
** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable
|
|
** parameter, the implementation is not required to do anything with this
|
|
@@ -9495,12 +9566,12 @@
|
|
** implementation must return a pointer to the page buffer with its content
|
|
** intact. If the requested page is not already in the cache, then the
|
|
** cache implementation should use the value of the createFlag
|
|
-** parameter to help it determined what action to take:
|
|
+** parameter to help it determine what action to take:
|
|
**
|
|
** <table border=1 width=85% align=center>
|
|
** <tr><th> createFlag <th> Behavior when page is not already in cache
|
|
** <tr><td> 0 <td> Do not allocate a new page. Return NULL.
|
|
-** <tr><td> 1 <td> Allocate a new page if it easy and convenient to do so.
|
|
+** <tr><td> 1 <td> Allocate a new page if it is easy and convenient to do so.
|
|
** Otherwise return NULL.
|
|
** <tr><td> 2 <td> Make every effort to allocate a new page. Only return
|
|
** NULL if allocating a new page is effectively impossible.
|
|
@@ -9517,7 +9588,7 @@
|
|
** as its second argument. If the third parameter, discard, is non-zero,
|
|
** then the page must be evicted from the cache.
|
|
** ^If the discard parameter is
|
|
-** zero, then the page may be discarded or retained at the discretion of
|
|
+** zero, then the page may be discarded or retained at the discretion of the
|
|
** page cache implementation. ^The page cache implementation
|
|
** may choose to evict unpinned pages at any time.
|
|
**
|
|
@@ -9535,7 +9606,7 @@
|
|
** When SQLite calls the xTruncate() method, the cache must discard all
|
|
** existing cache entries with page numbers (keys) greater than or equal
|
|
** to the value of the iLimit parameter passed to xTruncate(). If any
|
|
-** of these pages are pinned, they are implicitly unpinned, meaning that
|
|
+** of these pages are pinned, they become implicitly unpinned, meaning that
|
|
** they can be safely discarded.
|
|
**
|
|
** [[the xDestroy() page cache method]]
|
|
@@ -9715,7 +9786,7 @@
|
|
** external process or via a database connection other than the one being
|
|
** used by the backup operation, then the backup will be automatically
|
|
** restarted by the next call to sqlite3_backup_step(). ^If the source
|
|
-** database is modified by the using the same database connection as is used
|
|
+** database is modified by using the same database connection as is used
|
|
** by the backup operation, then the backup database is automatically
|
|
** updated at the same time.
|
|
**
|
|
@@ -9732,7 +9803,7 @@
|
|
** and may not be used following a call to sqlite3_backup_finish().
|
|
**
|
|
** ^The value returned by sqlite3_backup_finish is [SQLITE_OK] if no
|
|
-** sqlite3_backup_step() errors occurred, regardless or whether or not
|
|
+** sqlite3_backup_step() errors occurred, regardless of whether or not
|
|
** sqlite3_backup_step() completed.
|
|
** ^If an out-of-memory condition or IO error occurred during any prior
|
|
** sqlite3_backup_step() call on the same [sqlite3_backup] object, then
|
|
@@ -9834,7 +9905,7 @@
|
|
** application receives an SQLITE_LOCKED error, it may call the
|
|
** sqlite3_unlock_notify() method with the blocked connection handle as
|
|
** the first argument to register for a callback that will be invoked
|
|
-** when the blocking connections current transaction is concluded. ^The
|
|
+** when the blocking connection's current transaction is concluded. ^The
|
|
** callback is invoked from within the [sqlite3_step] or [sqlite3_close]
|
|
** call that concludes the blocking connection's transaction.
|
|
**
|
|
@@ -9854,7 +9925,7 @@
|
|
** blocked connection already has a registered unlock-notify callback,
|
|
** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is
|
|
** called with a NULL pointer as its second argument, then any existing
|
|
-** unlock-notify callback is canceled. ^The blocked connections
|
|
+** unlock-notify callback is canceled. ^The blocked connection's
|
|
** unlock-notify callback may also be canceled by closing the blocked
|
|
** connection using [sqlite3_close()].
|
|
**
|
|
@@ -10252,7 +10323,7 @@
|
|
** support constraints. In this configuration (which is the default) if
|
|
** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire
|
|
** statement is rolled back as if [ON CONFLICT | OR ABORT] had been
|
|
-** specified as part of the users SQL statement, regardless of the actual
|
|
+** specified as part of the user's SQL statement, regardless of the actual
|
|
** ON CONFLICT mode specified.
|
|
**
|
|
** If X is non-zero, then the virtual table implementation guarantees
|
|
@@ -10286,7 +10357,7 @@
|
|
** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
|
|
** <dd>Calls of the form
|
|
** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
|
|
-** the [xConnect] or [xCreate] methods of a [virtual table] implementation
|
|
+** [xConnect] or [xCreate] methods of a [virtual table] implementation
|
|
** identify that virtual table as being safe to use from within triggers
|
|
** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
|
|
** virtual table can do no serious harm even if it is controlled by a
|
|
@@ -10454,7 +10525,7 @@
|
|
** </table>
|
|
**
|
|
** ^For the purposes of comparing virtual table output values to see if the
|
|
-** values are same value for sorting purposes, two NULL values are considered
|
|
+** values are the same value for sorting purposes, two NULL values are considered
|
|
** to be the same. In other words, the comparison operator is "IS"
|
|
** (or "IS NOT DISTINCT FROM") and not "==".
|
|
**
|
|
@@ -10464,7 +10535,7 @@
|
|
**
|
|
** ^A virtual table implementation is always free to return rows in any order
|
|
** it wants, as long as the "orderByConsumed" flag is not set. ^When the
|
|
-** the "orderByConsumed" flag is unset, the query planner will add extra
|
|
+** "orderByConsumed" flag is unset, the query planner will add extra
|
|
** [bytecode] to ensure that the final results returned by the SQL query are
|
|
** ordered correctly. The use of the "orderByConsumed" flag and the
|
|
** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful
|
|
@@ -10561,7 +10632,7 @@
|
|
** sqlite3_vtab_in_next(X,P) should be one of the parameters to the
|
|
** xFilter method which invokes these routines, and specifically
|
|
** a parameter that was previously selected for all-at-once IN constraint
|
|
-** processing use the [sqlite3_vtab_in()] interface in the
|
|
+** processing using the [sqlite3_vtab_in()] interface in the
|
|
** [xBestIndex|xBestIndex method]. ^(If the X parameter is not
|
|
** an xFilter argument that was selected for all-at-once IN constraint
|
|
** processing, then these routines return [SQLITE_ERROR].)^
|
|
@@ -10616,7 +10687,7 @@
|
|
** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V)
|
|
** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th
|
|
** constraint is not available. ^The sqlite3_vtab_rhs_value() interface
|
|
-** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if
|
|
+** can return a result code other than SQLITE_OK or SQLITE_NOTFOUND if
|
|
** something goes wrong.
|
|
**
|
|
** The sqlite3_vtab_rhs_value() interface is usually only successful if
|
|
@@ -10644,8 +10715,8 @@
|
|
** KEYWORDS: {conflict resolution mode}
|
|
**
|
|
** These constants are returned by [sqlite3_vtab_on_conflict()] to
|
|
-** inform a [virtual table] implementation what the [ON CONFLICT] mode
|
|
-** is for the SQL statement being evaluated.
|
|
+** inform a [virtual table] implementation of the [ON CONFLICT] mode
|
|
+** for the SQL statement being evaluated.
|
|
**
|
|
** Note that the [SQLITE_IGNORE] constant is also used as a potential
|
|
** return value from the [sqlite3_set_authorizer()] callback and that
|
|
@@ -10685,39 +10756,39 @@
|
|
** [[SQLITE_SCANSTAT_EST]] <dt>SQLITE_SCANSTAT_EST</dt>
|
|
** <dd>^The "double" variable pointed to by the V parameter will be set to the
|
|
** query planner's estimate for the average number of rows output from each
|
|
-** iteration of the X-th loop. If the query planner's estimates was accurate,
|
|
+** iteration of the X-th loop. If the query planner's estimate was accurate,
|
|
** then this value will approximate the quotient NVISIT/NLOOP and the
|
|
** product of this value for all prior loops with the same SELECTID will
|
|
-** be the NLOOP value for the current loop.
|
|
+** be the NLOOP value for the current loop.</dd>
|
|
**
|
|
** [[SQLITE_SCANSTAT_NAME]] <dt>SQLITE_SCANSTAT_NAME</dt>
|
|
** <dd>^The "const char *" variable pointed to by the V parameter will be set
|
|
** to a zero-terminated UTF-8 string containing the name of the index or table
|
|
-** used for the X-th loop.
|
|
+** used for the X-th loop.</dd>
|
|
**
|
|
** [[SQLITE_SCANSTAT_EXPLAIN]] <dt>SQLITE_SCANSTAT_EXPLAIN</dt>
|
|
** <dd>^The "const char *" variable pointed to by the V parameter will be set
|
|
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
|
|
-** description for the X-th loop.
|
|
+** description for the X-th loop.</dd>
|
|
**
|
|
** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECTID</dt>
|
|
** <dd>^The "int" variable pointed to by the V parameter will be set to the
|
|
** id for the X-th query plan element. The id value is unique within the
|
|
** statement. The select-id is the same value as is output in the first
|
|
-** column of an [EXPLAIN QUERY PLAN] query.
|
|
+** column of an [EXPLAIN QUERY PLAN] query.</dd>
|
|
**
|
|
** [[SQLITE_SCANSTAT_PARENTID]] <dt>SQLITE_SCANSTAT_PARENTID</dt>
|
|
** <dd>The "int" variable pointed to by the V parameter will be set to the
|
|
-** the id of the parent of the current query element, if applicable, or
|
|
+** id of the parent of the current query element, if applicable, or
|
|
** to zero if the query element has no parent. This is the same value as
|
|
-** returned in the second column of an [EXPLAIN QUERY PLAN] query.
|
|
+** returned in the second column of an [EXPLAIN QUERY PLAN] query.</dd>
|
|
**
|
|
** [[SQLITE_SCANSTAT_NCYCLE]] <dt>SQLITE_SCANSTAT_NCYCLE</dt>
|
|
** <dd>The sqlite3_int64 output value is set to the number of cycles,
|
|
** according to the processor time-stamp counter, that elapsed while the
|
|
** query element was being processed. This value is not available for
|
|
** all query elements - if it is unavailable the output variable is
|
|
-** set to -1.
|
|
+** set to -1.</dd>
|
|
** </dl>
|
|
*/
|
|
#define SQLITE_SCANSTAT_NLOOP 0
|
|
@@ -10758,8 +10829,8 @@
|
|
** sqlite3_stmt_scanstatus_v2() with a zeroed flags parameter.
|
|
**
|
|
** Parameter "idx" identifies the specific query element to retrieve statistics
|
|
-** for. Query elements are numbered starting from zero. A value of -1 may be
|
|
-** to query for statistics regarding the entire query. ^If idx is out of range
|
|
+** for. Query elements are numbered starting from zero. A value of -1 may
|
|
+** retrieve statistics for the entire query. ^If idx is out of range
|
|
** - less than -1 or greater than or equal to the total number of query
|
|
** elements used to implement the statement - a non-zero value is returned and
|
|
** the variable that pOut points to is unchanged.
|
|
@@ -10802,7 +10873,7 @@
|
|
** METHOD: sqlite3
|
|
**
|
|
** ^If a write-transaction is open on [database connection] D when the
|
|
-** [sqlite3_db_cacheflush(D)] interface invoked, any dirty
|
|
+** [sqlite3_db_cacheflush(D)] interface is invoked, any dirty
|
|
** pages in the pager-cache that are not currently in use are written out
|
|
** to disk. A dirty page may be in use if a database cursor created by an
|
|
** active SQL statement is reading from it, or if it is page 1 of a database
|
|
@@ -10916,8 +10987,8 @@
|
|
** triggers; and so forth.
|
|
**
|
|
** When the [sqlite3_blob_write()] API is used to update a blob column,
|
|
-** the pre-update hook is invoked with SQLITE_DELETE. This is because the
|
|
-** in this case the new values are not available. In this case, when a
|
|
+** the pre-update hook is invoked with SQLITE_DELETE, because
|
|
+** the new values are not yet available. In this case, when a
|
|
** callback made with op==SQLITE_DELETE is actually a write using the
|
|
** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns
|
|
** the index of the column being written. In other cases, where the
|
|
@@ -11170,7 +11241,7 @@
|
|
** For an ordinary on-disk database file, the serialization is just a
|
|
** copy of the disk file. For an in-memory database or a "TEMP" database,
|
|
** the serialization is the same sequence of bytes which would be written
|
|
-** to disk if that database where backed up to disk.
|
|
+** to disk if that database were backed up to disk.
|
|
**
|
|
** The usual case is that sqlite3_serialize() copies the serialization of
|
|
** the database into memory obtained from [sqlite3_malloc64()] and returns
|
|
@@ -11179,7 +11250,7 @@
|
|
** contains the SQLITE_SERIALIZE_NOCOPY bit, then no memory allocations
|
|
** are made, and the sqlite3_serialize() function will return a pointer
|
|
** to the contiguous memory representation of the database that SQLite
|
|
-** is currently using for that database, or NULL if the no such contiguous
|
|
+** is currently using for that database, or NULL if no such contiguous
|
|
** memory representation of the database exists. A contiguous memory
|
|
** representation of the database will usually only exist if there has
|
|
** been a prior call to [sqlite3_deserialize(D,S,...)] with the same
|
|
@@ -11250,7 +11321,7 @@
|
|
** database is currently in a read transaction or is involved in a backup
|
|
** operation.
|
|
**
|
|
-** It is not possible to deserialized into the TEMP database. If the
|
|
+** It is not possible to deserialize into the TEMP database. If the
|
|
** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the
|
|
** function returns SQLITE_ERROR.
|
|
**
|
|
@@ -11272,7 +11343,7 @@
|
|
sqlite3 *db, /* The database connection */
|
|
const char *zSchema, /* Which DB to reopen with the deserialization */
|
|
unsigned char *pData, /* The serialized database content */
|
|
- sqlite3_int64 szDb, /* Number bytes in the deserialization */
|
|
+ sqlite3_int64 szDb, /* Number of bytes in the deserialization */
|
|
sqlite3_int64 szBuf, /* Total size of buffer pData[] */
|
|
unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */
|
|
);
|
|
@@ -11280,7 +11351,7 @@
|
|
/*
|
|
** CAPI3REF: Flags for sqlite3_deserialize()
|
|
**
|
|
-** The following are allowed values for 6th argument (the F argument) to
|
|
+** The following are allowed values for the 6th argument (the F argument) to
|
|
** the [sqlite3_deserialize(D,S,P,N,M,F)] interface.
|
|
**
|
|
** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization
|
|
@@ -11805,9 +11876,10 @@
|
|
** is inserted while a session object is enabled, then later deleted while
|
|
** the same session object is disabled, no INSERT record will appear in the
|
|
** changeset, even though the delete took place while the session was disabled.
|
|
-** Or, if one field of a row is updated while a session is disabled, and
|
|
-** another field of the same row is updated while the session is enabled, the
|
|
-** resulting changeset will contain an UPDATE change that updates both fields.
|
|
+** Or, if one field of a row is updated while a session is enabled, and
|
|
+** then another field of the same row is updated while the session is disabled,
|
|
+** the resulting changeset will contain an UPDATE change that updates both
|
|
+** fields.
|
|
*/
|
|
SQLITE_API int sqlite3session_changeset(
|
|
sqlite3_session *pSession, /* Session object */
|
|
@@ -11879,8 +11951,9 @@
|
|
** database zFrom the contents of the two compatible tables would be
|
|
** identical.
|
|
**
|
|
-** It an error if database zFrom does not exist or does not contain the
|
|
-** required compatible table.
|
|
+** Unless the call to this function is a no-op as described above, it is an
|
|
+** error if database zFrom does not exist or does not contain the required
|
|
+** compatible table.
|
|
**
|
|
** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite
|
|
** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
|
|
@@ -12015,7 +12088,7 @@
|
|
** The following flags may passed via the 4th parameter to
|
|
** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]:
|
|
**
|
|
-** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd>
|
|
+** <dt>SQLITE_CHANGESETSTART_INVERT <dd>
|
|
** Invert the changeset while iterating through it. This is equivalent to
|
|
** inverting a changeset using sqlite3changeset_invert() before applying it.
|
|
** It is an error to specify this flag with a patchset.
|
|
@@ -12330,19 +12403,6 @@
|
|
void **ppOut /* OUT: Buffer containing output changeset */
|
|
);
|
|
|
|
-
|
|
-/*
|
|
-** CAPI3REF: Upgrade the Schema of a Changeset/Patchset
|
|
-*/
|
|
-SQLITE_API int sqlite3changeset_upgrade(
|
|
- sqlite3 *db,
|
|
- const char *zDb,
|
|
- int nIn, const void *pIn, /* Input changeset */
|
|
- int *pnOut, void **ppOut /* OUT: Inverse of input */
|
|
-);
|
|
-
|
|
-
|
|
-
|
|
/*
|
|
** CAPI3REF: Changegroup Handle
|
|
**
|
|
@@ -14090,14 +14150,22 @@
|
|
** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement.
|
|
** * Terms in the VALUES clause of an INSERT statement
|
|
**
|
|
-** The hard upper limit here is 32676. Most database people will
|
|
+** The hard upper limit here is 32767. Most database people will
|
|
** tell you that in a well-normalized database, you usually should
|
|
** not have more than a dozen or so columns in any table. And if
|
|
** that is the case, there is no point in having more than a few
|
|
** dozen values in any of the other situations described above.
|
|
+**
|
|
+** An index can only have SQLITE_MAX_COLUMN columns from the user
|
|
+** point of view, but the underlying b-tree that implements the index
|
|
+** might have up to twice as many columns in a WITHOUT ROWID table,
|
|
+** since must also store the primary key at the end. Hence the
|
|
+** column count for Index is u16 instead of i16.
|
|
*/
|
|
-#ifndef SQLITE_MAX_COLUMN
|
|
+#if !defined(SQLITE_MAX_COLUMN)
|
|
# define SQLITE_MAX_COLUMN 2000
|
|
+#elif SQLITE_MAX_COLUMN>32767
|
|
+# error SQLITE_MAX_COLUMN may not exceed 32767
|
|
#endif
|
|
|
|
/*
|
|
@@ -14749,6 +14817,7 @@
|
|
HashElem *next, *prev; /* Next and previous elements in the table */
|
|
void *data; /* Data associated with this element */
|
|
const char *pKey; /* Key associated with this element */
|
|
+ unsigned int h; /* hash for pKey */
|
|
};
|
|
|
|
/*
|
|
@@ -15109,7 +15178,17 @@
|
|
** ourselves.
|
|
*/
|
|
#ifndef offsetof
|
|
-#define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD))
|
|
+#define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD))
|
|
+#endif
|
|
+
|
|
+/*
|
|
+** Work around C99 "flex-array" syntax for pre-C99 compilers, so as
|
|
+** to avoid complaints from -fsanitize=strict-bounds.
|
|
+*/
|
|
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
|
|
+# define FLEXARRAY
|
|
+#else
|
|
+# define FLEXARRAY 1
|
|
#endif
|
|
|
|
/*
|
|
@@ -15187,6 +15266,11 @@
|
|
typedef UINT8_TYPE u8; /* 1-byte unsigned integer */
|
|
typedef INT8_TYPE i8; /* 1-byte signed integer */
|
|
|
|
+/* A bitfield type for use inside of structures. Always follow with :N where
|
|
+** N is the number of bits.
|
|
+*/
|
|
+typedef unsigned bft; /* Bit Field Type */
|
|
+
|
|
/*
|
|
** SQLITE_MAX_U32 is a u64 constant that is the maximum u64 value
|
|
** that can be stored in a u32 without loss of data. The value
|
|
@@ -15356,6 +15440,14 @@
|
|
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
|
|
|
|
/*
|
|
+** Macro SMXV(n) return the maximum value that can be held in variable n,
|
|
+** assuming n is a signed integer type. UMXV(n) is similar for unsigned
|
|
+** integer types.
|
|
+*/
|
|
+#define SMXV(n) ((((i64)1)<<(sizeof(n)*8-1))-1)
|
|
+#define UMXV(n) ((((i64)1)<<(sizeof(n)*8))-1)
|
|
+
|
|
+/*
|
|
** Round up a number to the next larger multiple of 8. This is used
|
|
** to force 8-byte alignment on 64-bit architectures.
|
|
**
|
|
@@ -17331,8 +17423,8 @@
|
|
SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3*);
|
|
#endif
|
|
|
|
-/* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on
|
|
-** each VDBE opcode.
|
|
+/* Use SQLITE_ENABLE_EXPLAIN_COMMENTS to enable generation of extra
|
|
+** comments on each VDBE opcode.
|
|
**
|
|
** Use the SQLITE_ENABLE_MODULE_COMMENTS macro to see some extra no-op
|
|
** comments in VDBE programs that show key decision points in the code
|
|
@@ -18055,6 +18147,10 @@
|
|
Savepoint *pSavepoint; /* List of active savepoints */
|
|
int nAnalysisLimit; /* Number of index rows to ANALYZE */
|
|
int busyTimeout; /* Busy handler timeout, in msec */
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ int setlkTimeout; /* Blocking lock timeout, in msec. -1 -> inf. */
|
|
+ int setlkFlags; /* Flags passed to setlk_timeout() */
|
|
+#endif
|
|
int nSavepoint; /* Number of non-transaction savepoints */
|
|
int nStatement; /* Number of nested statement-transactions */
|
|
i64 nDeferredCons; /* Net deferred constraints this transaction. */
|
|
@@ -18609,6 +18705,7 @@
|
|
#define SQLITE_AFF_INTEGER 0x44 /* 'D' */
|
|
#define SQLITE_AFF_REAL 0x45 /* 'E' */
|
|
#define SQLITE_AFF_FLEXNUM 0x46 /* 'F' */
|
|
+#define SQLITE_AFF_DEFER 0x58 /* 'X' - defer computation until later */
|
|
|
|
#define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC)
|
|
|
|
@@ -18733,6 +18830,7 @@
|
|
} u;
|
|
Trigger *pTrigger; /* List of triggers on this object */
|
|
Schema *pSchema; /* Schema that contains this table */
|
|
+ u8 aHx[16]; /* Column aHt[K%sizeof(aHt)] might have hash K */
|
|
};
|
|
|
|
/*
|
|
@@ -18866,9 +18964,13 @@
|
|
struct sColMap { /* Mapping of columns in pFrom to columns in zTo */
|
|
int iFrom; /* Index of column in pFrom */
|
|
char *zCol; /* Name of column in zTo. If NULL use PRIMARY KEY */
|
|
- } aCol[1]; /* One entry for each of nCol columns */
|
|
+ } aCol[FLEXARRAY]; /* One entry for each of nCol columns */
|
|
};
|
|
|
|
+/* The size (in bytes) of an FKey object holding N columns. The answer
|
|
+** does NOT include space to hold the zTo name. */
|
|
+#define SZ_FKEY(N) (offsetof(FKey,aCol)+(N)*sizeof(struct sColMap))
|
|
+
|
|
/*
|
|
** SQLite supports many different ways to resolve a constraint
|
|
** error. ROLLBACK processing means that a constraint violation
|
|
@@ -18930,9 +19032,12 @@
|
|
u16 nAllField; /* Total columns, including key plus others */
|
|
sqlite3 *db; /* The database connection */
|
|
u8 *aSortFlags; /* Sort order for each column. */
|
|
- CollSeq *aColl[1]; /* Collating sequence for each term of the key */
|
|
+ CollSeq *aColl[FLEXARRAY]; /* Collating sequence for each term of the key */
|
|
};
|
|
|
|
+/* The size (in bytes) of a KeyInfo object with up to N fields */
|
|
+#define SZ_KEYINFO(N) (offsetof(KeyInfo,aColl) + (N)*sizeof(CollSeq*))
|
|
+
|
|
/*
|
|
** Allowed bit values for entries in the KeyInfo.aSortFlags[] array.
|
|
*/
|
|
@@ -19052,7 +19157,7 @@
|
|
Pgno tnum; /* DB Page containing root of this index */
|
|
LogEst szIdxRow; /* Estimated average row size in bytes */
|
|
u16 nKeyCol; /* Number of columns forming the key */
|
|
- u16 nColumn; /* Number of columns stored in the index */
|
|
+ u16 nColumn; /* Nr columns in btree. Can be 2*Table.nCol */
|
|
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
|
|
unsigned idxType:2; /* 0:Normal 1:UNIQUE, 2:PRIMARY KEY, 3:IPK */
|
|
unsigned bUnordered:1; /* Use this index for == or IN queries only */
|
|
@@ -19061,7 +19166,6 @@
|
|
unsigned isCovering:1; /* True if this is a covering index */
|
|
unsigned noSkipScan:1; /* Do not try to use skip-scan if true */
|
|
unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */
|
|
- unsigned bLowQual:1; /* sqlite_stat1 says this is a low-quality index */
|
|
unsigned bNoQuery:1; /* Do not use this index to optimize queries */
|
|
unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */
|
|
unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */
|
|
@@ -19151,7 +19255,7 @@
|
|
** from source tables rather than from accumulators */
|
|
u8 useSortingIdx; /* In direct mode, reference the sorting index rather
|
|
** than the source table */
|
|
- u16 nSortingColumn; /* Number of columns in the sorting index */
|
|
+ u32 nSortingColumn; /* Number of columns in the sorting index */
|
|
int sortingIdx; /* Cursor number of the sorting index */
|
|
int sortingIdxPTab; /* Cursor number of pseudo-table */
|
|
int iFirstReg; /* First register in range for aCol[] and aFunc[] */
|
|
@@ -19160,8 +19264,8 @@
|
|
Table *pTab; /* Source table */
|
|
Expr *pCExpr; /* The original expression */
|
|
int iTable; /* Cursor number of the source table */
|
|
- i16 iColumn; /* Column number within the source table */
|
|
- i16 iSorterColumn; /* Column number in the sorting index */
|
|
+ int iColumn; /* Column number within the source table */
|
|
+ int iSorterColumn; /* Column number in the sorting index */
|
|
} *aCol;
|
|
int nColumn; /* Number of used entries in aCol[] */
|
|
int nAccumulator; /* Number of columns that show through to the output.
|
|
@@ -19390,10 +19494,10 @@
|
|
/* Macros can be used to test, set, or clear bits in the
|
|
** Expr.flags field.
|
|
*/
|
|
-#define ExprHasProperty(E,P) (((E)->flags&(P))!=0)
|
|
-#define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P))
|
|
-#define ExprSetProperty(E,P) (E)->flags|=(P)
|
|
-#define ExprClearProperty(E,P) (E)->flags&=~(P)
|
|
+#define ExprHasProperty(E,P) (((E)->flags&(u32)(P))!=0)
|
|
+#define ExprHasAllProperty(E,P) (((E)->flags&(u32)(P))==(u32)(P))
|
|
+#define ExprSetProperty(E,P) (E)->flags|=(u32)(P)
|
|
+#define ExprClearProperty(E,P) (E)->flags&=~(u32)(P)
|
|
#define ExprAlwaysTrue(E) (((E)->flags&(EP_OuterON|EP_IsTrue))==EP_IsTrue)
|
|
#define ExprAlwaysFalse(E) (((E)->flags&(EP_OuterON|EP_IsFalse))==EP_IsFalse)
|
|
#define ExprIsFullSize(E) (((E)->flags&(EP_Reduced|EP_TokenOnly))==0)
|
|
@@ -19505,9 +19609,14 @@
|
|
int iConstExprReg; /* Register in which Expr value is cached. Used only
|
|
** by Parse.pConstExpr */
|
|
} u;
|
|
- } a[1]; /* One slot for each expression in the list */
|
|
+ } a[FLEXARRAY]; /* One slot for each expression in the list */
|
|
};
|
|
|
|
+/* The size (in bytes) of an ExprList object that is big enough to hold
|
|
+** as many as N expressions. */
|
|
+#define SZ_EXPRLIST(N) \
|
|
+ (offsetof(ExprList,a) + (N)*sizeof(struct ExprList_item))
|
|
+
|
|
/*
|
|
** Allowed values for Expr.a.eEName
|
|
*/
|
|
@@ -19535,9 +19644,12 @@
|
|
int nId; /* Number of identifiers on the list */
|
|
struct IdList_item {
|
|
char *zName; /* Name of the identifier */
|
|
- } a[1];
|
|
+ } a[FLEXARRAY];
|
|
};
|
|
|
|
+/* The size (in bytes) of an IdList object that can hold up to N IDs. */
|
|
+#define SZ_IDLIST(N) (offsetof(IdList,a)+(N)*sizeof(struct IdList_item))
|
|
+
|
|
/*
|
|
** Allowed values for IdList.eType, which determines which value of the a.u4
|
|
** is valid.
|
|
@@ -19657,11 +19769,19 @@
|
|
**
|
|
*/
|
|
struct SrcList {
|
|
- int nSrc; /* Number of tables or subqueries in the FROM clause */
|
|
- u32 nAlloc; /* Number of entries allocated in a[] below */
|
|
- SrcItem a[1]; /* One entry for each identifier on the list */
|
|
+ int nSrc; /* Number of tables or subqueries in the FROM clause */
|
|
+ u32 nAlloc; /* Number of entries allocated in a[] below */
|
|
+ SrcItem a[FLEXARRAY]; /* One entry for each identifier on the list */
|
|
};
|
|
|
|
+/* Size (in bytes) of a SrcList object that can hold as many as N
|
|
+** SrcItem objects. */
|
|
+#define SZ_SRCLIST(N) (offsetof(SrcList,a)+(N)*sizeof(SrcItem))
|
|
+
|
|
+/* Size (in bytes( of a SrcList object that holds 1 SrcItem. This is a
|
|
+** special case of SZ_SRCITEM(1) that comes up often. */
|
|
+#define SZ_SRCLIST_1 (offsetof(SrcList,a)+sizeof(SrcItem))
|
|
+
|
|
/*
|
|
** Permitted values of the SrcList.a.jointype field
|
|
*/
|
|
@@ -20130,25 +20250,32 @@
|
|
char *zErrMsg; /* An error message */
|
|
Vdbe *pVdbe; /* An engine for executing database bytecode */
|
|
int rc; /* Return code from execution */
|
|
- u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */
|
|
- u8 checkSchema; /* Causes schema cookie check after an error */
|
|
+ LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
|
|
u8 nested; /* Number of nested calls to the parser/code generator */
|
|
u8 nTempReg; /* Number of temporary registers in aTempReg[] */
|
|
u8 isMultiWrite; /* True if statement may modify/insert multiple rows */
|
|
u8 mayAbort; /* True if statement may throw an ABORT exception */
|
|
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
|
|
- u8 okConstFactor; /* OK to factor out constants */
|
|
u8 disableLookaside; /* Number of times lookaside has been disabled */
|
|
u8 prepFlags; /* SQLITE_PREPARE_* flags */
|
|
u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */
|
|
- u8 bHasWith; /* True if statement contains WITH */
|
|
u8 mSubrtnSig; /* mini Bloom filter on available SubrtnSig.selId */
|
|
+ u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
|
|
+ u8 bReturning; /* Coding a RETURNING trigger */
|
|
+ u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
|
|
+ u8 disableTriggers; /* True to disable triggers */
|
|
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
|
|
u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */
|
|
#endif
|
|
#ifdef SQLITE_DEBUG
|
|
u8 ifNotExists; /* Might be true if IF NOT EXISTS. Assert()s only */
|
|
+ u8 isCreate; /* CREATE TABLE, INDEX, or VIEW (but not TRIGGER)
|
|
+ ** and ALTER TABLE ADD COLUMN. */
|
|
#endif
|
|
+ bft colNamesSet :1; /* TRUE after OP_ColumnName has been issued to pVdbe */
|
|
+ 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 */
|
|
int nRangeReg; /* Size of the temporary register block */
|
|
int iRangeReg; /* First register in temporary register block */
|
|
int nErr; /* Number of errors seen */
|
|
@@ -20163,12 +20290,9 @@
|
|
ExprList *pConstExpr;/* Constant expressions */
|
|
IndexedExpr *pIdxEpr;/* List of expressions used by active indexes */
|
|
IndexedExpr *pIdxPartExpr; /* Exprs constrained by index WHERE clauses */
|
|
- Token constraintName;/* Name of the constraint currently being parsed */
|
|
yDbMask writeMask; /* Start a write transaction on these databases */
|
|
yDbMask cookieMask; /* Bitmask of schema verified databases */
|
|
- int regRowid; /* Register holding rowid of CREATE TABLE entry */
|
|
- int regRoot; /* Register holding root page number for new objects */
|
|
- int nMaxArg; /* Max args passed to user function by sub-program */
|
|
+ int nMaxArg; /* Max args to xUpdate and xFilter vtab methods */
|
|
int nSelect; /* Number of SELECT stmts. Counter for Select.selId */
|
|
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
|
u32 nProgressSteps; /* xProgress steps taken during sqlite3_prepare() */
|
|
@@ -20182,17 +20306,6 @@
|
|
Table *pTriggerTab; /* Table triggers are being coded for */
|
|
TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
|
|
ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */
|
|
- union {
|
|
- int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */
|
|
- Returning *pReturning; /* The RETURNING clause */
|
|
- } u1;
|
|
- u32 oldmask; /* Mask of old.* columns referenced */
|
|
- u32 newmask; /* Mask of new.* columns referenced */
|
|
- LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
|
|
- u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
|
|
- u8 bReturning; /* Coding a RETURNING trigger */
|
|
- u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
|
|
- u8 disableTriggers; /* True to disable triggers */
|
|
|
|
/**************************************************************************
|
|
** Fields above must be initialized to zero. The fields that follow,
|
|
@@ -20204,6 +20317,19 @@
|
|
int aTempReg[8]; /* Holding area for temporary registers */
|
|
Parse *pOuterParse; /* Outer Parse object when nested */
|
|
Token sNameToken; /* Token with unqualified schema object name */
|
|
+ u32 oldmask; /* Mask of old.* columns referenced */
|
|
+ u32 newmask; /* Mask of new.* columns referenced */
|
|
+ union {
|
|
+ struct { /* These fields available when isCreate is true */
|
|
+ int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */
|
|
+ int regRowid; /* Register holding rowid of CREATE TABLE entry */
|
|
+ int regRoot; /* Register holding root page for new objects */
|
|
+ Token constraintName; /* Name of the constraint currently being parsed */
|
|
+ } cr;
|
|
+ struct { /* These fields available to all other statements */
|
|
+ Returning *pReturning; /* The RETURNING clause */
|
|
+ } d;
|
|
+ } u1;
|
|
|
|
/************************************************************************
|
|
** Above is constant between recursions. Below is reset before and after
|
|
@@ -20719,9 +20845,13 @@
|
|
int nCte; /* Number of CTEs in the WITH clause */
|
|
int bView; /* Belongs to the outermost Select of a view */
|
|
With *pOuter; /* Containing WITH clause, or NULL */
|
|
- Cte a[1]; /* For each CTE in the WITH clause.... */
|
|
+ Cte a[FLEXARRAY]; /* For each CTE in the WITH clause.... */
|
|
};
|
|
|
|
+/* The size (in bytes) of a With object that can hold as many
|
|
+** as N different CTEs. */
|
|
+#define SZ_WITH(N) (offsetof(With,a) + (N)*sizeof(Cte))
|
|
+
|
|
/*
|
|
** The Cte object is not guaranteed to persist for the entire duration
|
|
** of code generation. (The query flattener or other parser tree
|
|
@@ -20750,9 +20880,13 @@
|
|
DbClientData *pNext; /* Next in a linked list */
|
|
void *pData; /* The data */
|
|
void (*xDestructor)(void*); /* Destructor. Might be NULL */
|
|
- char zName[1]; /* Name of this client data. MUST BE LAST */
|
|
+ char zName[FLEXARRAY]; /* Name of this client data. MUST BE LAST */
|
|
};
|
|
|
|
+/* The size (in bytes) of a DbClientData object that can has a name
|
|
+** that is N bytes long, including the zero-terminator. */
|
|
+#define SZ_DBCLIENTDATA(N) (offsetof(DbClientData,zName)+(N))
|
|
+
|
|
#ifdef SQLITE_DEBUG
|
|
/*
|
|
** An instance of the TreeView object is used for printing the content of
|
|
@@ -21195,7 +21329,7 @@
|
|
SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*,char);
|
|
SQLITE_PRIVATE void sqlite3OpenSchemaTable(Parse *, int);
|
|
SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*);
|
|
-SQLITE_PRIVATE i16 sqlite3TableColumnToIndex(Index*, i16);
|
|
+SQLITE_PRIVATE int sqlite3TableColumnToIndex(Index*, int);
|
|
#ifdef SQLITE_OMIT_GENERATED_COLUMNS
|
|
# define sqlite3TableColumnToStorage(T,X) (X) /* No-op pass-through */
|
|
# define sqlite3StorageColumnToTable(T,X) (X) /* No-op pass-through */
|
|
@@ -21293,7 +21427,7 @@
|
|
SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*);
|
|
SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3*, OnOrUsing*);
|
|
SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3*, SrcList*);
|
|
-SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**);
|
|
+SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,int,int,char**);
|
|
SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
|
|
Expr*, int, int, u8);
|
|
SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int);
|
|
@@ -21429,7 +21563,8 @@
|
|
SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch(int,const char*);
|
|
SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int);
|
|
SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8);
|
|
-SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum*,sqlite3_value*);
|
|
+SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum*,sqlite3_value*,int);
|
|
+SQLITE_PRIVATE int sqlite3AppendOneUtf8Character(char*, u32);
|
|
SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void);
|
|
SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void);
|
|
SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void);
|
|
@@ -22294,6 +22429,9 @@
|
|
#ifdef SQLITE_BUG_COMPATIBLE_20160819
|
|
"BUG_COMPATIBLE_20160819",
|
|
#endif
|
|
+#ifdef SQLITE_BUG_COMPATIBLE_20250510
|
|
+ "BUG_COMPATIBLE_20250510",
|
|
+#endif
|
|
#ifdef SQLITE_CASE_SENSITIVE_LIKE
|
|
"CASE_SENSITIVE_LIKE",
|
|
#endif
|
|
@@ -22530,6 +22668,9 @@
|
|
#ifdef SQLITE_ENABLE_SESSION
|
|
"ENABLE_SESSION",
|
|
#endif
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ "ENABLE_SETLK_TIMEOUT",
|
|
+#endif
|
|
#ifdef SQLITE_ENABLE_SNAPSHOT
|
|
"ENABLE_SNAPSHOT",
|
|
#endif
|
|
@@ -22584,6 +22725,9 @@
|
|
#ifdef SQLITE_EXTRA_INIT
|
|
"EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT),
|
|
#endif
|
|
+#ifdef SQLITE_EXTRA_INIT_MUTEXED
|
|
+ "EXTRA_INIT_MUTEXED=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT_MUTEXED),
|
|
+#endif
|
|
#ifdef SQLITE_EXTRA_SHUTDOWN
|
|
"EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN),
|
|
#endif
|
|
@@ -23568,12 +23712,19 @@
|
|
#endif
|
|
VdbeTxtBlbCache *pCache; /* Cache of large TEXT or BLOB values */
|
|
|
|
- /* 2*nField extra array elements allocated for aType[], beyond the one
|
|
- ** static element declared in the structure. nField total array slots for
|
|
- ** aType[] and nField+1 array slots for aOffset[] */
|
|
- u32 aType[1]; /* Type values record decode. MUST BE LAST */
|
|
+ /* Space is allocated for aType to hold at least 2*nField+1 entries:
|
|
+ ** nField slots for aType[] and nField+1 array slots for aOffset[] */
|
|
+ u32 aType[FLEXARRAY]; /* Type values record decode. MUST BE LAST */
|
|
};
|
|
|
|
+/*
|
|
+** The size (in bytes) of a VdbeCursor object that has an nField value of N
|
|
+** or less. The value of SZ_VDBECURSOR(n) is guaranteed to be a multiple
|
|
+** of 8.
|
|
+*/
|
|
+#define SZ_VDBECURSOR(N) \
|
|
+ (ROUND8(offsetof(VdbeCursor,aType)) + ((N)+1)*sizeof(u64))
|
|
+
|
|
/* Return true if P is a null-only cursor
|
|
*/
|
|
#define IsNullCursor(P) \
|
|
@@ -23830,13 +23981,16 @@
|
|
u8 enc; /* Encoding to use for results */
|
|
u8 skipFlag; /* Skip accumulator loading if true */
|
|
u16 argc; /* Number of arguments */
|
|
- sqlite3_value *argv[1]; /* Argument set */
|
|
+ sqlite3_value *argv[FLEXARRAY]; /* Argument set */
|
|
};
|
|
|
|
-/* A bitfield type for use inside of structures. Always follow with :N where
|
|
-** N is the number of bits.
|
|
+/*
|
|
+** The size (in bytes) of an sqlite3_context object that holds N
|
|
+** argv[] arguments.
|
|
*/
|
|
-typedef unsigned bft; /* Bit Field Type */
|
|
+#define SZ_CONTEXT(N) \
|
|
+ (offsetof(sqlite3_context,argv)+(N)*sizeof(sqlite3_value*))
|
|
+
|
|
|
|
/* The ScanStatus object holds a single value for the
|
|
** sqlite3_stmt_scanstatus() interface.
|
|
@@ -23897,7 +24051,7 @@
|
|
i64 nStmtDefCons; /* Number of def. constraints when stmt started */
|
|
i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */
|
|
Mem *aMem; /* The memory locations */
|
|
- Mem **apArg; /* Arguments to currently executing user function */
|
|
+ Mem **apArg; /* Arguments xUpdate and xFilter vtab methods */
|
|
VdbeCursor **apCsr; /* One element of this array for each open cursor */
|
|
Mem *aVar; /* Values for the OP_Variable opcode. */
|
|
|
|
@@ -23917,6 +24071,7 @@
|
|
#ifdef SQLITE_DEBUG
|
|
int rcApp; /* errcode set by sqlite3_result_error_code() */
|
|
u32 nWrite; /* Number of write operations that have occurred */
|
|
+ int napArg; /* Size of the apArg[] array */
|
|
#endif
|
|
u16 nResColumn; /* Number of columns in one row of the result set */
|
|
u16 nResAlloc; /* Column slots allocated to aColName[] */
|
|
@@ -23969,7 +24124,7 @@
|
|
VdbeCursor *pCsr; /* Cursor to read old values from */
|
|
int op; /* One of SQLITE_INSERT, UPDATE, DELETE */
|
|
u8 *aRecord; /* old.* database record */
|
|
- KeyInfo keyinfo;
|
|
+ KeyInfo *pKeyinfo; /* Key information */
|
|
UnpackedRecord *pUnpacked; /* Unpacked version of aRecord[] */
|
|
UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */
|
|
int iNewReg; /* Register for new.* values */
|
|
@@ -23981,6 +24136,7 @@
|
|
Table *pTab; /* Schema object being updated */
|
|
Index *pPk; /* PK index if pTab is WITHOUT ROWID */
|
|
sqlite3_value **apDflt; /* Array of default values, if required */
|
|
+ u8 keyinfoSpace[SZ_KEYINFO(0)]; /* Space to hold pKeyinfo[0] content */
|
|
};
|
|
|
|
/*
|
|
@@ -24347,8 +24503,9 @@
|
|
nInit += countLookasideSlots(db->lookaside.pSmallInit);
|
|
nFree += countLookasideSlots(db->lookaside.pSmallFree);
|
|
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
|
|
- if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit;
|
|
- return db->lookaside.nSlot - (nInit+nFree);
|
|
+ assert( db->lookaside.nSlot >= nInit+nFree );
|
|
+ if( pHighwater ) *pHighwater = (int)(db->lookaside.nSlot - nInit);
|
|
+ return (int)(db->lookaside.nSlot - (nInit+nFree));
|
|
}
|
|
|
|
/*
|
|
@@ -24401,7 +24558,7 @@
|
|
assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 );
|
|
assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 );
|
|
*pCurrent = 0;
|
|
- *pHighwater = db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT];
|
|
+ *pHighwater = (int)db->lookaside.anStat[op-SQLITE_DBSTATUS_LOOKASIDE_HIT];
|
|
if( resetFlag ){
|
|
db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0;
|
|
}
|
|
@@ -25913,7 +26070,7 @@
|
|
** In other words, return the day of the week according
|
|
** to this code:
|
|
**
|
|
-** 0=Sunday, 1=Monday, 2=Tues, ..., 6=Saturday
|
|
+** 0=Sunday, 1=Monday, 2=Tuesday, ..., 6=Saturday
|
|
*/
|
|
static int daysAfterSunday(DateTime *pDate){
|
|
assert( pDate->validJD );
|
|
@@ -30122,6 +30279,8 @@
|
|
|
|
#ifdef __CYGWIN__
|
|
# include <sys/cygwin.h>
|
|
+# include <sys/stat.h> /* amalgamator: dontcache */
|
|
+# include <unistd.h> /* amalgamator: dontcache */
|
|
# include <errno.h> /* amalgamator: dontcache */
|
|
#endif
|
|
|
|
@@ -31516,17 +31675,17 @@
|
|
#define etPERCENT 7 /* Percent symbol. %% */
|
|
#define etCHARX 8 /* Characters. %c */
|
|
/* The rest are extensions, not normally found in printf() */
|
|
-#define etSQLESCAPE 9 /* Strings with '\'' doubled. %q */
|
|
-#define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '',
|
|
- NULL pointers replaced by SQL NULL. %Q */
|
|
-#define etTOKEN 11 /* a pointer to a Token structure */
|
|
-#define etSRCITEM 12 /* a pointer to a SrcItem */
|
|
-#define etPOINTER 13 /* The %p conversion */
|
|
-#define etSQLESCAPE3 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_q 9 /* Strings with '\'' doubled. %q */
|
|
+#define etESCAPE_Q 10 /* Strings with '\'' doubled and enclosed in '',
|
|
+ NULL pointers replaced by SQL NULL. %Q */
|
|
+#define etTOKEN 11 /* a pointer to a Token structure */
|
|
+#define etSRCITEM 12 /* a pointer to a SrcItem */
|
|
+#define etPOINTER 13 /* The %p conversion */
|
|
+#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 etINVALID 17 /* Any unrecognized conversion type */
|
|
+#define etINVALID 17 /* Any unrecognized conversion type */
|
|
|
|
|
|
/*
|
|
@@ -31565,9 +31724,9 @@
|
|
{ 's', 0, 4, etSTRING, 0, 0 },
|
|
{ 'g', 0, 1, etGENERIC, 30, 0 },
|
|
{ 'z', 0, 4, etDYNSTRING, 0, 0 },
|
|
- { 'q', 0, 4, etSQLESCAPE, 0, 0 },
|
|
- { 'Q', 0, 4, etSQLESCAPE2, 0, 0 },
|
|
- { 'w', 0, 4, etSQLESCAPE3, 0, 0 },
|
|
+ { 'q', 0, 4, etESCAPE_q, 0, 0 },
|
|
+ { 'Q', 0, 4, etESCAPE_Q, 0, 0 },
|
|
+ { 'w', 0, 4, etESCAPE_w, 0, 0 },
|
|
{ 'c', 0, 0, etCHARX, 0, 0 },
|
|
{ 'o', 8, 0, etRADIX, 0, 2 },
|
|
{ 'u', 10, 0, etDECIMAL, 0, 0 },
|
|
@@ -32164,25 +32323,7 @@
|
|
}
|
|
}else{
|
|
unsigned int ch = va_arg(ap,unsigned int);
|
|
- if( ch<0x00080 ){
|
|
- buf[0] = ch & 0xff;
|
|
- length = 1;
|
|
- }else if( ch<0x00800 ){
|
|
- buf[0] = 0xc0 + (u8)((ch>>6)&0x1f);
|
|
- buf[1] = 0x80 + (u8)(ch & 0x3f);
|
|
- length = 2;
|
|
- }else if( ch<0x10000 ){
|
|
- buf[0] = 0xe0 + (u8)((ch>>12)&0x0f);
|
|
- buf[1] = 0x80 + (u8)((ch>>6) & 0x3f);
|
|
- buf[2] = 0x80 + (u8)(ch & 0x3f);
|
|
- length = 3;
|
|
- }else{
|
|
- buf[0] = 0xf0 + (u8)((ch>>18) & 0x07);
|
|
- buf[1] = 0x80 + (u8)((ch>>12) & 0x3f);
|
|
- buf[2] = 0x80 + (u8)((ch>>6) & 0x3f);
|
|
- buf[3] = 0x80 + (u8)(ch & 0x3f);
|
|
- length = 4;
|
|
- }
|
|
+ length = sqlite3AppendOneUtf8Character(buf, ch);
|
|
}
|
|
if( precision>1 ){
|
|
i64 nPrior = 1;
|
|
@@ -32262,22 +32403,31 @@
|
|
while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++;
|
|
}
|
|
break;
|
|
- case etSQLESCAPE: /* %q: Escape ' characters */
|
|
- case etSQLESCAPE2: /* %Q: Escape ' and enclose in '...' */
|
|
- case etSQLESCAPE3: { /* %w: Escape " characters */
|
|
+ case etESCAPE_q: /* %q: Escape ' characters */
|
|
+ case etESCAPE_Q: /* %Q: Escape ' and enclose in '...' */
|
|
+ case etESCAPE_w: { /* %w: Escape " characters */
|
|
i64 i, j, k, n;
|
|
- int needQuote, isnull;
|
|
+ int needQuote = 0;
|
|
char ch;
|
|
- char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */
|
|
char *escarg;
|
|
+ char q;
|
|
|
|
if( bArgList ){
|
|
escarg = getTextArg(pArgList);
|
|
}else{
|
|
escarg = va_arg(ap,char*);
|
|
}
|
|
- isnull = escarg==0;
|
|
- if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
|
|
+ if( escarg==0 ){
|
|
+ escarg = (xtype==etESCAPE_Q ? "NULL" : "(NULL)");
|
|
+ }else if( xtype==etESCAPE_Q ){
|
|
+ needQuote = 1;
|
|
+ }
|
|
+ if( xtype==etESCAPE_w ){
|
|
+ q = '"';
|
|
+ flag_alternateform = 0;
|
|
+ }else{
|
|
+ q = '\'';
|
|
+ }
|
|
/* For %q, %Q, and %w, the precision is the number of bytes (or
|
|
** characters if the ! flags is present) to use from the input.
|
|
** Because of the extra quoting characters inserted, the number
|
|
@@ -32290,7 +32440,30 @@
|
|
while( (escarg[i+1]&0xc0)==0x80 ){ i++; }
|
|
}
|
|
}
|
|
- needQuote = !isnull && xtype==etSQLESCAPE2;
|
|
+ if( flag_alternateform ){
|
|
+ /* For %#q, do unistr()-style backslash escapes for
|
|
+ ** all control characters, and for backslash itself.
|
|
+ ** For %#Q, do the same but only if there is at least
|
|
+ ** one control character. */
|
|
+ u32 nBack = 0;
|
|
+ u32 nCtrl = 0;
|
|
+ for(k=0; k<i; k++){
|
|
+ if( escarg[k]=='\\' ){
|
|
+ nBack++;
|
|
+ }else if( ((u8*)escarg)[k]<=0x1f ){
|
|
+ nCtrl++;
|
|
+ }
|
|
+ }
|
|
+ if( nCtrl || xtype==etESCAPE_q ){
|
|
+ n += nBack + 5*nCtrl;
|
|
+ if( xtype==etESCAPE_Q ){
|
|
+ n += 10;
|
|
+ needQuote = 2;
|
|
+ }
|
|
+ }else{
|
|
+ flag_alternateform = 0;
|
|
+ }
|
|
+ }
|
|
n += i + 3;
|
|
if( n>etBUFSIZE ){
|
|
bufpt = zExtra = printfTempBuf(pAccum, n);
|
|
@@ -32299,13 +32472,41 @@
|
|
bufpt = buf;
|
|
}
|
|
j = 0;
|
|
- if( needQuote ) bufpt[j++] = q;
|
|
+ if( needQuote ){
|
|
+ if( needQuote==2 ){
|
|
+ memcpy(&bufpt[j], "unistr('", 8);
|
|
+ j += 8;
|
|
+ }else{
|
|
+ bufpt[j++] = '\'';
|
|
+ }
|
|
+ }
|
|
k = i;
|
|
- for(i=0; i<k; i++){
|
|
- bufpt[j++] = ch = escarg[i];
|
|
- if( ch==q ) bufpt[j++] = ch;
|
|
+ if( flag_alternateform ){
|
|
+ for(i=0; i<k; i++){
|
|
+ bufpt[j++] = ch = escarg[i];
|
|
+ if( ch==q ){
|
|
+ bufpt[j++] = ch;
|
|
+ }else if( ch=='\\' ){
|
|
+ bufpt[j++] = '\\';
|
|
+ }else if( ((unsigned char)ch)<=0x1f ){
|
|
+ bufpt[j-1] = '\\';
|
|
+ bufpt[j++] = 'u';
|
|
+ bufpt[j++] = '0';
|
|
+ bufpt[j++] = '0';
|
|
+ bufpt[j++] = ch>=0x10 ? '1' : '0';
|
|
+ bufpt[j++] = "0123456789abcdef"[ch&0xf];
|
|
+ }
|
|
+ }
|
|
+ }else{
|
|
+ for(i=0; i<k; i++){
|
|
+ bufpt[j++] = ch = escarg[i];
|
|
+ if( ch==q ) bufpt[j++] = ch;
|
|
+ }
|
|
+ }
|
|
+ if( needQuote ){
|
|
+ bufpt[j++] = '\'';
|
|
+ if( needQuote==2 ) bufpt[j++] = ')';
|
|
}
|
|
- if( needQuote ) bufpt[j++] = q;
|
|
bufpt[j] = 0;
|
|
length = j;
|
|
goto adjust_width_for_utf8;
|
|
@@ -32548,7 +32749,7 @@
|
|
static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){
|
|
char *zText;
|
|
assert( p->mxAlloc>0 && !isMalloced(p) );
|
|
- zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
|
|
+ zText = sqlite3DbMallocRaw(p->db, 1+(u64)p->nChar );
|
|
if( zText ){
|
|
memcpy(zText, p->zText, p->nChar+1);
|
|
p->printfFlags |= SQLITE_PRINTF_MALLOCED;
|
|
@@ -32793,6 +32994,15 @@
|
|
return zBuf;
|
|
}
|
|
|
|
+/* Maximum size of an sqlite3_log() message. */
|
|
+#if defined(SQLITE_MAX_LOG_MESSAGE)
|
|
+ /* Leave the definition as supplied */
|
|
+#elif SQLITE_PRINT_BUF_SIZE*10>10000
|
|
+# define SQLITE_MAX_LOG_MESSAGE 10000
|
|
+#else
|
|
+# define SQLITE_MAX_LOG_MESSAGE (SQLITE_PRINT_BUF_SIZE*10)
|
|
+#endif
|
|
+
|
|
/*
|
|
** This is the routine that actually formats the sqlite3_log() message.
|
|
** We house it in a separate routine from sqlite3_log() to avoid using
|
|
@@ -32809,7 +33019,7 @@
|
|
*/
|
|
static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
|
|
StrAccum acc; /* String accumulator */
|
|
- char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */
|
|
+ char zMsg[SQLITE_MAX_LOG_MESSAGE]; /* Complete log message */
|
|
|
|
sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0);
|
|
sqlite3_str_vappendf(&acc, zFormat, ap);
|
|
@@ -34805,6 +35015,35 @@
|
|
}
|
|
|
|
/*
|
|
+** Write a single UTF8 character whose value is v into the
|
|
+** buffer starting at zOut. zOut must be sized to hold at
|
|
+** least four bytes. Return the number of bytes needed
|
|
+** to encode the new character.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3AppendOneUtf8Character(char *zOut, u32 v){
|
|
+ if( v<0x00080 ){
|
|
+ zOut[0] = (u8)(v & 0xff);
|
|
+ return 1;
|
|
+ }
|
|
+ if( v<0x00800 ){
|
|
+ zOut[0] = 0xc0 + (u8)((v>>6) & 0x1f);
|
|
+ zOut[1] = 0x80 + (u8)(v & 0x3f);
|
|
+ return 2;
|
|
+ }
|
|
+ if( v<0x10000 ){
|
|
+ zOut[0] = 0xe0 + (u8)((v>>12) & 0x0f);
|
|
+ zOut[1] = 0x80 + (u8)((v>>6) & 0x3f);
|
|
+ zOut[2] = 0x80 + (u8)(v & 0x3f);
|
|
+ return 3;
|
|
+ }
|
|
+ zOut[0] = 0xf0 + (u8)((v>>18) & 0x07);
|
|
+ zOut[1] = 0x80 + (u8)((v>>12) & 0x3f);
|
|
+ zOut[2] = 0x80 + (u8)((v>>6) & 0x3f);
|
|
+ zOut[3] = 0x80 + (u8)(v & 0x3f);
|
|
+ return 4;
|
|
+}
|
|
+
|
|
+/*
|
|
** Translate a single UTF-8 character. Return the unicode value.
|
|
**
|
|
** During translation, assume that the byte that zTerm points
|
|
@@ -35225,7 +35464,7 @@
|
|
int n = 0;
|
|
|
|
if( SQLITE_UTF16NATIVE==SQLITE_UTF16LE ) z++;
|
|
- while( n<nChar && ALWAYS(z<=zEnd) ){
|
|
+ while( n<nChar && z<=zEnd ){
|
|
c = z[0];
|
|
z += 2;
|
|
if( c>=0xd8 && c<0xdc && z<=zEnd && z[0]>=0xdc && z[0]<0xe0 ) z += 2;
|
|
@@ -36400,7 +36639,11 @@
|
|
}
|
|
p->z = &p->zBuf[i+1];
|
|
assert( i+p->n < sizeof(p->zBuf) );
|
|
- while( ALWAYS(p->n>0) && p->z[p->n-1]=='0' ){ p->n--; }
|
|
+ assert( p->n>0 );
|
|
+ while( p->z[p->n-1]=='0' ){
|
|
+ p->n--;
|
|
+ assert( p->n>0 );
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -36905,7 +37148,7 @@
|
|
}
|
|
|
|
/*
|
|
-** Compute the absolute value of a 32-bit signed integer, of possible. Or
|
|
+** Compute the absolute value of a 32-bit signed integer, if possible. Or
|
|
** if the integer has a value of -2147483648, return +2147483647
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3AbsInt32(int x){
|
|
@@ -37186,12 +37429,19 @@
|
|
*/
|
|
static unsigned int strHash(const char *z){
|
|
unsigned int h = 0;
|
|
- unsigned char c;
|
|
- while( (c = (unsigned char)*z++)!=0 ){ /*OPTIMIZATION-IF-TRUE*/
|
|
+ while( z[0] ){ /*OPTIMIZATION-IF-TRUE*/
|
|
/* Knuth multiplicative hashing. (Sorting & Searching, p. 510).
|
|
** 0x9e3779b1 is 2654435761 which is the closest prime number to
|
|
- ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2. */
|
|
- h += sqlite3UpperToLower[c];
|
|
+ ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2.
|
|
+ **
|
|
+ ** Only bits 0xdf for ASCII and bits 0xbf for EBCDIC each octet are
|
|
+ ** hashed since the omitted bits determine the upper/lower case difference.
|
|
+ */
|
|
+#ifdef SQLITE_EBCDIC
|
|
+ h += 0xbf & (unsigned char)*(z++);
|
|
+#else
|
|
+ h += 0xdf & (unsigned char)*(z++);
|
|
+#endif
|
|
h *= 0x9e3779b1;
|
|
}
|
|
return h;
|
|
@@ -37264,9 +37514,8 @@
|
|
pH->htsize = new_size = sqlite3MallocSize(new_ht)/sizeof(struct _ht);
|
|
memset(new_ht, 0, new_size*sizeof(struct _ht));
|
|
for(elem=pH->first, pH->first=0; elem; elem = next_elem){
|
|
- unsigned int h = strHash(elem->pKey) % new_size;
|
|
next_elem = elem->next;
|
|
- insertElement(pH, &new_ht[h], elem);
|
|
+ insertElement(pH, &new_ht[elem->h % new_size], elem);
|
|
}
|
|
return 1;
|
|
}
|
|
@@ -37284,23 +37533,22 @@
|
|
HashElem *elem; /* Used to loop thru the element list */
|
|
unsigned int count; /* Number of elements left to test */
|
|
unsigned int h; /* The computed hash */
|
|
- static HashElem nullElement = { 0, 0, 0, 0 };
|
|
+ static HashElem nullElement = { 0, 0, 0, 0, 0 };
|
|
|
|
+ h = strHash(pKey);
|
|
if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/
|
|
struct _ht *pEntry;
|
|
- h = strHash(pKey) % pH->htsize;
|
|
- pEntry = &pH->ht[h];
|
|
+ pEntry = &pH->ht[h % pH->htsize];
|
|
elem = pEntry->chain;
|
|
count = pEntry->count;
|
|
}else{
|
|
- h = 0;
|
|
elem = pH->first;
|
|
count = pH->count;
|
|
}
|
|
if( pHash ) *pHash = h;
|
|
while( count ){
|
|
assert( elem!=0 );
|
|
- if( sqlite3StrICmp(elem->pKey,pKey)==0 ){
|
|
+ if( h==elem->h && sqlite3StrICmp(elem->pKey,pKey)==0 ){
|
|
return elem;
|
|
}
|
|
elem = elem->next;
|
|
@@ -37312,10 +37560,9 @@
|
|
/* Remove a single entry from the hash table given a pointer to that
|
|
** element and a hash on the element's key.
|
|
*/
|
|
-static void removeElementGivenHash(
|
|
+static void removeElement(
|
|
Hash *pH, /* The pH containing "elem" */
|
|
- HashElem* elem, /* The element to be removed from the pH */
|
|
- unsigned int h /* Hash value for the element */
|
|
+ HashElem *elem /* The element to be removed from the pH */
|
|
){
|
|
struct _ht *pEntry;
|
|
if( elem->prev ){
|
|
@@ -37327,7 +37574,7 @@
|
|
elem->next->prev = elem->prev;
|
|
}
|
|
if( pH->ht ){
|
|
- pEntry = &pH->ht[h];
|
|
+ pEntry = &pH->ht[elem->h % pH->htsize];
|
|
if( pEntry->chain==elem ){
|
|
pEntry->chain = elem->next;
|
|
}
|
|
@@ -37378,7 +37625,7 @@
|
|
if( elem->data ){
|
|
void *old_data = elem->data;
|
|
if( data==0 ){
|
|
- removeElementGivenHash(pH,elem,h);
|
|
+ removeElement(pH,elem);
|
|
}else{
|
|
elem->data = data;
|
|
elem->pKey = pKey;
|
|
@@ -37389,15 +37636,13 @@
|
|
new_elem = (HashElem*)sqlite3Malloc( sizeof(HashElem) );
|
|
if( new_elem==0 ) return data;
|
|
new_elem->pKey = pKey;
|
|
+ new_elem->h = h;
|
|
new_elem->data = data;
|
|
pH->count++;
|
|
- if( pH->count>=10 && pH->count > 2*pH->htsize ){
|
|
- if( rehash(pH, pH->count*2) ){
|
|
- assert( pH->htsize>0 );
|
|
- h = strHash(pKey) % pH->htsize;
|
|
- }
|
|
+ if( pH->count>=5 && pH->count > 2*pH->htsize ){
|
|
+ rehash(pH, pH->count*3);
|
|
}
|
|
- insertElement(pH, pH->ht ? &pH->ht[h] : 0, new_elem);
|
|
+ insertElement(pH, pH->ht ? &pH->ht[new_elem->h % pH->htsize] : 0, new_elem);
|
|
return 0;
|
|
}
|
|
|
|
@@ -38880,6 +39125,7 @@
|
|
#endif
|
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
unsigned iBusyTimeout; /* Wait this many millisec on locks */
|
|
+ int bBlockOnConnect; /* True to block for SHARED locks */
|
|
#endif
|
|
#if OS_VXWORKS
|
|
struct vxworksFileId *pId; /* Unique file ID */
|
|
@@ -40273,6 +40519,13 @@
|
|
rc = 0;
|
|
}
|
|
}else{
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ if( pFile->bBlockOnConnect && pLock->l_type==F_RDLCK
|
|
+ && pLock->l_start==SHARED_FIRST && pLock->l_len==SHARED_SIZE
|
|
+ ){
|
|
+ rc = osFcntl(pFile->h, F_SETLKW, pLock);
|
|
+ }else
|
|
+#endif
|
|
rc = osSetPosixAdvisoryLock(pFile->h, pLock, pFile);
|
|
}
|
|
return rc;
|
|
@@ -42634,8 +42887,9 @@
|
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
case SQLITE_FCNTL_LOCK_TIMEOUT: {
|
|
int iOld = pFile->iBusyTimeout;
|
|
+ int iNew = *(int*)pArg;
|
|
#if SQLITE_ENABLE_SETLK_TIMEOUT==1
|
|
- pFile->iBusyTimeout = *(int*)pArg;
|
|
+ pFile->iBusyTimeout = iNew<0 ? 0x7FFFFFFF : (unsigned)iNew;
|
|
#elif SQLITE_ENABLE_SETLK_TIMEOUT==2
|
|
pFile->iBusyTimeout = !!(*(int*)pArg);
|
|
#else
|
|
@@ -42644,7 +42898,12 @@
|
|
*(int*)pArg = iOld;
|
|
return SQLITE_OK;
|
|
}
|
|
-#endif
|
|
+ case SQLITE_FCNTL_BLOCK_ON_CONNECT: {
|
|
+ int iNew = *(int*)pArg;
|
|
+ pFile->bBlockOnConnect = iNew;
|
|
+ return SQLITE_OK;
|
|
+ }
|
|
+#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */
|
|
#if SQLITE_MAX_MMAP_SIZE>0
|
|
case SQLITE_FCNTL_MMAP_SIZE: {
|
|
i64 newLimit = *(i64*)pArg;
|
|
@@ -43617,21 +43876,20 @@
|
|
/* Check that, if this to be a blocking lock, no locks that occur later
|
|
** in the following list than the lock being obtained are already held:
|
|
**
|
|
- ** 1. Checkpointer lock (ofst==1).
|
|
- ** 2. Write lock (ofst==0).
|
|
- ** 3. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
|
|
+ ** 1. Recovery lock (ofst==2).
|
|
+ ** 2. Checkpointer lock (ofst==1).
|
|
+ ** 3. Write lock (ofst==0).
|
|
+ ** 4. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
|
|
**
|
|
** In other words, if this is a blocking lock, none of the locks that
|
|
** occur later in the above list than the lock being obtained may be
|
|
** held.
|
|
- **
|
|
- ** It is not permitted to block on the RECOVER lock.
|
|
*/
|
|
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && defined(SQLITE_DEBUG)
|
|
{
|
|
u16 lockMask = (p->exclMask|p->sharedMask);
|
|
assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
|
|
- (ofst!=2) /* not RECOVER */
|
|
+ (ofst!=2 || lockMask==0)
|
|
&& (ofst!=1 || lockMask==0 || lockMask==2)
|
|
&& (ofst!=0 || lockMask<3)
|
|
&& (ofst<3 || lockMask<(1<<ofst))
|
|
@@ -45436,7 +45694,7 @@
|
|
|
|
/* Almost all modern unix systems support nanosleep(). But if you are
|
|
** compiling for one of the rare exceptions, you can use
|
|
- ** -DHAVE_NANOSLEEP=0 (perhaps in conjuction with -DHAVE_USLEEP if
|
|
+ ** -DHAVE_NANOSLEEP=0 (perhaps in conjunction with -DHAVE_USLEEP if
|
|
** usleep() is available) in order to bypass the use of nanosleep() */
|
|
nanosleep(&sp, NULL);
|
|
|
|
@@ -47157,8 +47415,18 @@
|
|
sqlite3_int64 mmapSize; /* Size of mapped region */
|
|
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
|
|
#endif
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ DWORD iBusyTimeout; /* Wait this many millisec on locks */
|
|
+ int bBlockOnConnect;
|
|
+#endif
|
|
};
|
|
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+# define winFileBusyTimeout(pDbFd) pDbFd->iBusyTimeout
|
|
+#else
|
|
+# define winFileBusyTimeout(pDbFd) 0
|
|
+#endif
|
|
+
|
|
/*
|
|
** The winVfsAppData structure is used for the pAppData member for all of the
|
|
** Win32 VFS variants.
|
|
@@ -47477,7 +47745,7 @@
|
|
{ "FileTimeToLocalFileTime", (SYSCALL)0, 0 },
|
|
#endif
|
|
|
|
-#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \
|
|
+#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(const FILETIME*, \
|
|
LPFILETIME))aSyscall[11].pCurrent)
|
|
|
|
#if SQLITE_OS_WINCE
|
|
@@ -47486,7 +47754,7 @@
|
|
{ "FileTimeToSystemTime", (SYSCALL)0, 0 },
|
|
#endif
|
|
|
|
-#define osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \
|
|
+#define osFileTimeToSystemTime ((BOOL(WINAPI*)(const FILETIME*, \
|
|
LPSYSTEMTIME))aSyscall[12].pCurrent)
|
|
|
|
{ "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 },
|
|
@@ -47592,6 +47860,12 @@
|
|
#define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \
|
|
LPWSTR*))aSyscall[25].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[26].pCurrent)
|
|
@@ -47760,7 +48034,7 @@
|
|
{ "LockFile", (SYSCALL)0, 0 },
|
|
#endif
|
|
|
|
-#ifndef osLockFile
|
|
+#if !defined(osLockFile) && defined(SQLITE_WIN32_HAS_ANSI)
|
|
#define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
|
|
DWORD))aSyscall[47].pCurrent)
|
|
#endif
|
|
@@ -47824,7 +48098,7 @@
|
|
|
|
{ "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 },
|
|
|
|
-#define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \
|
|
+#define osSystemTimeToFileTime ((BOOL(WINAPI*)(const SYSTEMTIME*, \
|
|
LPFILETIME))aSyscall[56].pCurrent)
|
|
|
|
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
|
|
@@ -47833,7 +48107,7 @@
|
|
{ "UnlockFile", (SYSCALL)0, 0 },
|
|
#endif
|
|
|
|
-#ifndef osUnlockFile
|
|
+#if !defined(osUnlockFile) && defined(SQLITE_WIN32_HAS_ANSI)
|
|
#define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
|
|
DWORD))aSyscall[57].pCurrent)
|
|
#endif
|
|
@@ -47874,11 +48148,13 @@
|
|
#define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \
|
|
DWORD,DWORD))aSyscall[62].pCurrent)
|
|
|
|
-#if !SQLITE_OS_WINRT
|
|
+/*
|
|
+** 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 },
|
|
-#else
|
|
- { "WaitForSingleObject", (SYSCALL)0, 0 },
|
|
-#endif
|
|
|
|
#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \
|
|
DWORD))aSyscall[63].pCurrent)
|
|
@@ -48025,6 +48301,97 @@
|
|
#define osFlushViewOfFile \
|
|
((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].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[80].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[81].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[82].pCurrent)
|
|
+
|
|
+#ifndef _WIN32
|
|
+ { "getenv", (SYSCALL)getenv, 0 },
|
|
+#else
|
|
+ { "getenv", (SYSCALL)0, 0 },
|
|
+#endif
|
|
+
|
|
+#define osGetenv ((const char *(*)(const char *))aSyscall[83].pCurrent)
|
|
+
|
|
+#ifndef _WIN32
|
|
+ { "getcwd", (SYSCALL)getcwd, 0 },
|
|
+#else
|
|
+ { "getcwd", (SYSCALL)0, 0 },
|
|
+#endif
|
|
+
|
|
+#define osGetcwd ((char*(*)(char*,size_t))aSyscall[84].pCurrent)
|
|
+
|
|
+#ifndef _WIN32
|
|
+ { "readlink", (SYSCALL)readlink, 0 },
|
|
+#else
|
|
+ { "readlink", (SYSCALL)0, 0 },
|
|
+#endif
|
|
+
|
|
+#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[85].pCurrent)
|
|
+
|
|
+#ifndef _WIN32
|
|
+ { "lstat", (SYSCALL)lstat, 0 },
|
|
+#else
|
|
+ { "lstat", (SYSCALL)0, 0 },
|
|
+#endif
|
|
+
|
|
+#define osLstat ((int(*)(const char*,struct stat*))aSyscall[86].pCurrent)
|
|
+
|
|
+#ifndef _WIN32
|
|
+ { "__errno", (SYSCALL)__errno, 0 },
|
|
+#else
|
|
+ { "__errno", (SYSCALL)0, 0 },
|
|
+#endif
|
|
+
|
|
+#define osErrno (*((int*(*)(void))aSyscall[87].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[88].pCurrent)
|
|
+
|
|
}; /* End of the overrideable system calls */
|
|
|
|
/*
|
|
@@ -48198,6 +48565,7 @@
|
|
}
|
|
#endif /* SQLITE_WIN32_MALLOC */
|
|
|
|
+#ifdef _WIN32
|
|
/*
|
|
** This function outputs the specified (ANSI) string to the Win32 debugger
|
|
** (if available).
|
|
@@ -48240,6 +48608,7 @@
|
|
}
|
|
#endif
|
|
}
|
|
+#endif /* _WIN32 */
|
|
|
|
/*
|
|
** The following routine suspends the current thread for at least ms
|
|
@@ -48323,7 +48692,9 @@
|
|
}
|
|
return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
|
|
#elif SQLITE_TEST
|
|
- return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
|
|
+ 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
|
|
@@ -48538,6 +48909,7 @@
|
|
}
|
|
#endif /* SQLITE_WIN32_MALLOC */
|
|
|
|
+#ifdef _WIN32
|
|
/*
|
|
** Convert a UTF-8 string to Microsoft Unicode.
|
|
**
|
|
@@ -48563,6 +48935,7 @@
|
|
}
|
|
return zWideText;
|
|
}
|
|
+#endif /* _WIN32 */
|
|
|
|
/*
|
|
** Convert a Microsoft Unicode string to UTF-8.
|
|
@@ -48597,28 +48970,29 @@
|
|
** Space to hold the returned string is obtained from sqlite3_malloc().
|
|
*/
|
|
static LPWSTR winMbcsToUnicode(const char *zText, int useAnsi){
|
|
- int nByte;
|
|
+ int nWideChar;
|
|
LPWSTR zMbcsText;
|
|
int codepage = useAnsi ? CP_ACP : CP_OEMCP;
|
|
|
|
- nByte = osMultiByteToWideChar(codepage, 0, zText, -1, NULL,
|
|
- 0)*sizeof(WCHAR);
|
|
- if( nByte==0 ){
|
|
+ nWideChar = osMultiByteToWideChar(codepage, 0, zText, -1, NULL,
|
|
+ 0);
|
|
+ if( nWideChar==0 ){
|
|
return 0;
|
|
}
|
|
- zMbcsText = sqlite3MallocZero( nByte*sizeof(WCHAR) );
|
|
+ zMbcsText = sqlite3MallocZero( nWideChar*sizeof(WCHAR) );
|
|
if( zMbcsText==0 ){
|
|
return 0;
|
|
}
|
|
- nByte = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText,
|
|
- nByte);
|
|
- if( nByte==0 ){
|
|
+ nWideChar = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText,
|
|
+ nWideChar);
|
|
+ if( nWideChar==0 ){
|
|
sqlite3_free(zMbcsText);
|
|
zMbcsText = 0;
|
|
}
|
|
return zMbcsText;
|
|
}
|
|
|
|
+#ifdef _WIN32
|
|
/*
|
|
** Convert a Microsoft Unicode string to a multi-byte character string,
|
|
** using the ANSI or OEM code page.
|
|
@@ -48646,6 +49020,7 @@
|
|
}
|
|
return zText;
|
|
}
|
|
+#endif /* _WIN32 */
|
|
|
|
/*
|
|
** Convert a multi-byte character string to UTF-8.
|
|
@@ -48665,6 +49040,7 @@
|
|
return zTextUtf8;
|
|
}
|
|
|
|
+#ifdef _WIN32
|
|
/*
|
|
** Convert a UTF-8 string to a multi-byte character string.
|
|
**
|
|
@@ -48714,6 +49090,7 @@
|
|
#endif
|
|
return winUnicodeToUtf8(zWideText);
|
|
}
|
|
+#endif /* _WIN32 */
|
|
|
|
/*
|
|
** This is a public wrapper for the winMbcsToUtf8() function.
|
|
@@ -48731,6 +49108,7 @@
|
|
return winMbcsToUtf8(zText, osAreFileApisANSI());
|
|
}
|
|
|
|
+#ifdef _WIN32
|
|
/*
|
|
** This is a public wrapper for the winMbcsToUtf8() function.
|
|
*/
|
|
@@ -48855,6 +49233,7 @@
|
|
){
|
|
return sqlite3_win32_set_directory16(type, zValue);
|
|
}
|
|
+#endif /* _WIN32 */
|
|
|
|
/*
|
|
** The return value of winGetLastErrorMsg
|
|
@@ -49403,14 +49782,99 @@
|
|
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
|
|
}
|
|
|
|
/*
|
|
+** Lock a region of nByte bytes starting at offset offset of file hFile.
|
|
+** Take an EXCLUSIVE lock if parameter bExclusive is true, or a SHARED lock
|
|
+** otherwise. If nMs is greater than zero and the lock cannot be obtained
|
|
+** immediately, block for that many ms before giving up.
|
|
+**
|
|
+** This function returns SQLITE_OK if the lock is obtained successfully. If
|
|
+** some other process holds the lock, SQLITE_BUSY is returned if nMs==0, or
|
|
+** SQLITE_BUSY_TIMEOUT otherwise. Or, if an error occurs, SQLITE_IOERR.
|
|
+*/
|
|
+static int winHandleLockTimeout(
|
|
+ HANDLE hFile,
|
|
+ DWORD offset,
|
|
+ DWORD nByte,
|
|
+ int bExcl,
|
|
+ DWORD nMs
|
|
+){
|
|
+ DWORD flags = LOCKFILE_FAIL_IMMEDIATELY | (bExcl?LOCKFILE_EXCLUSIVE_LOCK:0);
|
|
+ int rc = SQLITE_OK;
|
|
+ BOOL ret;
|
|
+
|
|
+ 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;
|
|
+ }
|
|
+#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 ){
|
|
+#if SQLITE_ENABLE_SETLK_TIMEOUT==1
|
|
+ rc = SQLITE_BUSY_TIMEOUT;
|
|
+#else
|
|
+ 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);
|
|
+ }
|
|
+
|
|
+ osCloseHandle(ovlp.hEvent);
|
|
+#endif
|
|
+ }
|
|
+
|
|
+ if( rc==SQLITE_OK && !ret ){
|
|
+ rc = SQLITE_BUSY;
|
|
+ }
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
** Unlock a file region.
|
|
*/
|
|
static BOOL winUnlockFile(
|
|
@@ -49434,13 +49898,23 @@
|
|
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
|
|
}
|
|
|
|
+/*
|
|
+** Remove an nByte lock starting at offset iOff from HANDLE h.
|
|
+*/
|
|
+static int winHandleUnlock(HANDLE h, int iOff, int nByte){
|
|
+ BOOL ret = winUnlockFile(&h, iOff, 0, nByte, 0);
|
|
+ return (ret ? SQLITE_OK : SQLITE_IOERR_UNLOCK);
|
|
+}
|
|
+
|
|
/*****************************************************************************
|
|
** The next group of routines implement the I/O methods specified
|
|
** by the sqlite3_io_methods object.
|
|
@@ -49454,66 +49928,70 @@
|
|
#endif
|
|
|
|
/*
|
|
-** Move the current position of the file handle passed as the first
|
|
-** argument to offset iOffset within the file. If successful, return 0.
|
|
-** Otherwise, set pFile->lastErrno and return non-zero.
|
|
+** Seek the file handle h to offset nByte of the file.
|
|
+**
|
|
+** If successful, return SQLITE_OK. Or, if an error occurs, return an SQLite
|
|
+** error code.
|
|
*/
|
|
-static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){
|
|
+static int winHandleSeek(HANDLE h, sqlite3_int64 iOffset){
|
|
+ int rc = SQLITE_OK; /* Return value */
|
|
+
|
|
#if !SQLITE_OS_WINRT
|
|
LONG upperBits; /* Most sig. 32 bits of new offset */
|
|
LONG lowerBits; /* Least sig. 32 bits of new offset */
|
|
DWORD dwRet; /* Value returned by SetFilePointer() */
|
|
- DWORD lastErrno; /* Value returned by GetLastError() */
|
|
-
|
|
- OSTRACE(("SEEK file=%p, offset=%lld\n", pFile->h, iOffset));
|
|
|
|
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().
|
|
- */
|
|
- dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
|
|
-
|
|
- if( (dwRet==INVALID_SET_FILE_POINTER
|
|
- && ((lastErrno = osGetLastError())!=NO_ERROR)) ){
|
|
- pFile->lastErrno = lastErrno;
|
|
- winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
|
|
- "winSeekFile", pFile->zPath);
|
|
- OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h));
|
|
- return 1;
|
|
+ ** GetLastError(). */
|
|
+ if( dwRet==INVALID_SET_FILE_POINTER ){
|
|
+ DWORD lastErrno = osGetLastError();
|
|
+ if( lastErrno!=NO_ERROR ){
|
|
+ rc = SQLITE_IOERR_SEEK;
|
|
+ }
|
|
}
|
|
-
|
|
- OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h));
|
|
- return 0;
|
|
#else
|
|
- /*
|
|
- ** Same as above, except that this implementation works for WinRT.
|
|
- */
|
|
-
|
|
+ /* This implementation works for WinRT. */
|
|
LARGE_INTEGER x; /* The new offset */
|
|
BOOL bRet; /* Value returned by SetFilePointerEx() */
|
|
|
|
x.QuadPart = iOffset;
|
|
- bRet = osSetFilePointerEx(pFile->h, x, 0, FILE_BEGIN);
|
|
+ bRet = osSetFilePointerEx(h, x, 0, FILE_BEGIN);
|
|
|
|
if(!bRet){
|
|
- pFile->lastErrno = osGetLastError();
|
|
- winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
|
|
- "winSeekFile", pFile->zPath);
|
|
- OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h));
|
|
- return 1;
|
|
+ rc = SQLITE_IOERR_SEEK;
|
|
}
|
|
-
|
|
- OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h));
|
|
- return 0;
|
|
#endif
|
|
+
|
|
+ OSTRACE(("SEEK file=%p, offset=%lld rc=%s\n", h, iOffset, sqlite3ErrName(rc)));
|
|
+ return rc;
|
|
}
|
|
|
|
+/*
|
|
+** Move the current position of the file handle passed as the first
|
|
+** argument to offset iOffset within the file. If successful, return 0.
|
|
+** Otherwise, set pFile->lastErrno and return non-zero.
|
|
+*/
|
|
+static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){
|
|
+ int rc;
|
|
+
|
|
+ rc = winHandleSeek(pFile->h, iOffset);
|
|
+ if( rc!=SQLITE_OK ){
|
|
+ pFile->lastErrno = osGetLastError();
|
|
+ winLogError(rc, pFile->lastErrno, "winSeekFile", pFile->zPath);
|
|
+ }
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+
|
|
#if SQLITE_MAX_MMAP_SIZE>0
|
|
/* Forward references to VFS helper methods used for memory mapped files */
|
|
static int winMapfile(winFile*, sqlite3_int64);
|
|
@@ -49774,6 +50252,60 @@
|
|
}
|
|
|
|
/*
|
|
+** Truncate the file opened by handle h to nByte bytes in size.
|
|
+*/
|
|
+static int winHandleTruncate(HANDLE h, sqlite3_int64 nByte){
|
|
+ int rc = SQLITE_OK; /* Return code */
|
|
+ rc = winHandleSeek(h, nByte);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ if( 0==osSetEndOfFile(h) ){
|
|
+ rc = SQLITE_IOERR_TRUNCATE;
|
|
+ }
|
|
+ }
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Determine the size in bytes of the file opened by the handle passed as
|
|
+** the first argument.
|
|
+*/
|
|
+static int winHandleSize(HANDLE h, sqlite3_int64 *pnByte){
|
|
+ int rc = SQLITE_OK;
|
|
+
|
|
+#if SQLITE_OS_WINRT
|
|
+ FILE_STANDARD_INFO info;
|
|
+ BOOL b;
|
|
+ b = osGetFileInformationByHandleEx(h, FileStandardInfo, &info, sizeof(info));
|
|
+ if( b ){
|
|
+ *pnByte = info.EndOfFile.QuadPart;
|
|
+ }else{
|
|
+ rc = SQLITE_IOERR_FSTAT;
|
|
+ }
|
|
+#else
|
|
+ DWORD upperBits = 0;
|
|
+ DWORD lowerBits = 0;
|
|
+
|
|
+ assert( pnByte );
|
|
+ lowerBits = osGetFileSize(h, &upperBits);
|
|
+ *pnByte = (((sqlite3_int64)upperBits)<<32) + lowerBits;
|
|
+ if( lowerBits==INVALID_FILE_SIZE && osGetLastError()!=NO_ERROR ){
|
|
+ rc = SQLITE_IOERR_FSTAT;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Close the handle passed as the only argument.
|
|
+*/
|
|
+static void winHandleClose(HANDLE h){
|
|
+ if( h!=INVALID_HANDLE_VALUE ){
|
|
+ osCloseHandle(h);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
** Truncate an open file to a specified size
|
|
*/
|
|
static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
|
|
@@ -50028,8 +50560,9 @@
|
|
** Different API routines are called depending on whether or not this
|
|
** is Win9x or WinNT.
|
|
*/
|
|
-static int winGetReadLock(winFile *pFile){
|
|
+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
|
|
@@ -50039,7 +50572,7 @@
|
|
*/
|
|
res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0);
|
|
#else
|
|
- res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS, SHARED_FIRST, 0,
|
|
+ res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS&mask, SHARED_FIRST, 0,
|
|
SHARED_SIZE, 0);
|
|
#endif
|
|
}
|
|
@@ -50048,7 +50581,7 @@
|
|
int lk;
|
|
sqlite3_randomness(sizeof(lk), &lk);
|
|
pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1));
|
|
- res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS,
|
|
+ res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS&mask,
|
|
SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
|
|
}
|
|
#endif
|
|
@@ -50143,46 +50676,62 @@
|
|
assert( locktype!=PENDING_LOCK );
|
|
assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
|
|
|
|
- /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
|
|
+ /* Lock the PENDING_LOCK byte if we need to acquire an EXCLUSIVE lock or
|
|
** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of
|
|
** the PENDING_LOCK byte is temporary.
|
|
*/
|
|
newLocktype = pFile->locktype;
|
|
- if( pFile->locktype==NO_LOCK
|
|
- || (locktype==EXCLUSIVE_LOCK && pFile->locktype<=RESERVED_LOCK)
|
|
+ if( locktype==SHARED_LOCK
|
|
+ || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK)
|
|
){
|
|
int cnt = 3;
|
|
- while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS,
|
|
- PENDING_BYTE, 0, 1, 0))==0 ){
|
|
+
|
|
+ /* Flags for the LockFileEx() call. This should be an exclusive lock if
|
|
+ ** this call is to obtain EXCLUSIVE, or a shared lock if this call is to
|
|
+ ** obtain SHARED. */
|
|
+ int flags = LOCKFILE_FAIL_IMMEDIATELY;
|
|
+ if( locktype==EXCLUSIVE_LOCK ){
|
|
+ flags |= LOCKFILE_EXCLUSIVE_LOCK;
|
|
+ }
|
|
+ while( cnt>0 ){
|
|
/* Try 3 times to get the pending lock. This is needed to work
|
|
** around problems caused by indexing and/or anti-virus software on
|
|
** Windows systems.
|
|
+ **
|
|
** If you are using this code as a model for alternative VFSes, do not
|
|
- ** copy this retry logic. It is a hack intended for Windows only.
|
|
- */
|
|
+ ** copy this retry logic. It is a hack intended for Windows only. */
|
|
+ res = winLockFile(&pFile->h, flags, PENDING_BYTE, 0, 1, 0);
|
|
+ if( res ) break;
|
|
+
|
|
lastErrno = osGetLastError();
|
|
OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, result=%d\n",
|
|
- pFile->h, cnt, res));
|
|
+ pFile->h, cnt, res
|
|
+ ));
|
|
+
|
|
if( lastErrno==ERROR_INVALID_HANDLE ){
|
|
pFile->lastErrno = lastErrno;
|
|
rc = SQLITE_IOERR_LOCK;
|
|
OSTRACE(("LOCK-FAIL file=%p, count=%d, rc=%s\n",
|
|
- pFile->h, cnt, sqlite3ErrName(rc)));
|
|
+ pFile->h, cnt, sqlite3ErrName(rc)
|
|
+ ));
|
|
return rc;
|
|
}
|
|
- if( cnt ) sqlite3_win32_sleep(1);
|
|
+
|
|
+ cnt--;
|
|
+ if( cnt>0 ) sqlite3_win32_sleep(1);
|
|
}
|
|
gotPendingLock = res;
|
|
- if( !res ){
|
|
- lastErrno = osGetLastError();
|
|
- }
|
|
}
|
|
|
|
/* Acquire a shared lock
|
|
*/
|
|
if( locktype==SHARED_LOCK && res ){
|
|
assert( pFile->locktype==NO_LOCK );
|
|
- res = winGetReadLock(pFile);
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ res = winGetReadLock(pFile, pFile->bBlockOnConnect);
|
|
+#else
|
|
+ res = winGetReadLock(pFile, 0);
|
|
+#endif
|
|
if( res ){
|
|
newLocktype = SHARED_LOCK;
|
|
}else{
|
|
@@ -50220,7 +50769,7 @@
|
|
newLocktype = EXCLUSIVE_LOCK;
|
|
}else{
|
|
lastErrno = osGetLastError();
|
|
- winGetReadLock(pFile);
|
|
+ winGetReadLock(pFile, 0);
|
|
}
|
|
}
|
|
|
|
@@ -50300,7 +50849,7 @@
|
|
type = pFile->locktype;
|
|
if( type>=EXCLUSIVE_LOCK ){
|
|
winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
|
|
- if( locktype==SHARED_LOCK && !winGetReadLock(pFile) ){
|
|
+ if( locktype==SHARED_LOCK && !winGetReadLock(pFile, 0) ){
|
|
/* This should never happen. We should always be able to
|
|
** reacquire the read lock */
|
|
rc = winLogError(SQLITE_IOERR_UNLOCK, osGetLastError(),
|
|
@@ -50510,6 +51059,28 @@
|
|
return rc;
|
|
}
|
|
#endif
|
|
+
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ case SQLITE_FCNTL_LOCK_TIMEOUT: {
|
|
+ int iOld = pFile->iBusyTimeout;
|
|
+ int iNew = *(int*)pArg;
|
|
+#if SQLITE_ENABLE_SETLK_TIMEOUT==1
|
|
+ pFile->iBusyTimeout = (iNew < 0) ? INFINITE : (DWORD)iNew;
|
|
+#elif SQLITE_ENABLE_SETLK_TIMEOUT==2
|
|
+ pFile->iBusyTimeout = (DWORD)(!!iNew);
|
|
+#else
|
|
+# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2"
|
|
+#endif
|
|
+ *(int*)pArg = iOld;
|
|
+ return SQLITE_OK;
|
|
+ }
|
|
+ case SQLITE_FCNTL_BLOCK_ON_CONNECT: {
|
|
+ int iNew = *(int*)pArg;
|
|
+ pFile->bBlockOnConnect = iNew;
|
|
+ return SQLITE_OK;
|
|
+ }
|
|
+#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */
|
|
+
|
|
}
|
|
OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h));
|
|
return SQLITE_NOTFOUND;
|
|
@@ -50590,23 +51161,27 @@
|
|
**
|
|
** The following fields are read-only after the object is created:
|
|
**
|
|
-** fid
|
|
** zFilename
|
|
**
|
|
** Either winShmNode.mutex must be held or winShmNode.nRef==0 and
|
|
** winShmMutexHeld() is true when reading or writing any other field
|
|
** in this structure.
|
|
**
|
|
+** File-handle hSharedShm is used to (a) take the DMS lock, (b) truncate
|
|
+** the *-shm file if the DMS-locking protocol demands it, and (c) map
|
|
+** regions of the *-shm file into memory using MapViewOfFile() or
|
|
+** similar. Other locks are taken by individual clients using the
|
|
+** winShm.hShm handles.
|
|
*/
|
|
struct winShmNode {
|
|
sqlite3_mutex *mutex; /* Mutex to access this object */
|
|
char *zFilename; /* Name of the file */
|
|
- winFile hFile; /* File handle from winOpen */
|
|
+ HANDLE hSharedShm; /* File handle open on zFilename */
|
|
|
|
+ int isUnlocked; /* DMS lock has not yet been obtained */
|
|
+ int isReadonly; /* True if read-only */
|
|
int szRegion; /* Size of shared-memory regions */
|
|
int nRegion; /* Size of array apRegion */
|
|
- u8 isReadonly; /* True if read-only */
|
|
- u8 isUnlocked; /* True if no DMS lock held */
|
|
|
|
struct ShmRegion {
|
|
HANDLE hMap; /* File handle from CreateFileMapping */
|
|
@@ -50615,7 +51190,6 @@
|
|
DWORD lastErrno; /* The Windows errno from the last I/O error */
|
|
|
|
int nRef; /* Number of winShm objects pointing to this */
|
|
- winShm *pFirst; /* All winShm objects pointing to this */
|
|
winShmNode *pNext; /* Next in list of all winShmNode objects */
|
|
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
|
|
u8 nextShmId; /* Next available winShm.id value */
|
|
@@ -50631,23 +51205,15 @@
|
|
|
|
/*
|
|
** Structure used internally by this VFS to record the state of an
|
|
-** open shared memory connection.
|
|
-**
|
|
-** The following fields are initialized when this object is created and
|
|
-** are read-only thereafter:
|
|
-**
|
|
-** winShm.pShmNode
|
|
-** winShm.id
|
|
-**
|
|
-** All other fields are read/write. The winShm.pShmNode->mutex must be held
|
|
-** while accessing any read/write fields.
|
|
+** open shared memory connection. There is one such structure for each
|
|
+** winFile open on a wal mode database.
|
|
*/
|
|
struct winShm {
|
|
winShmNode *pShmNode; /* The underlying winShmNode object */
|
|
- winShm *pNext; /* Next winShm with the same winShmNode */
|
|
- u8 hasMutex; /* True if holding the winShmNode mutex */
|
|
u16 sharedMask; /* Mask of shared locks held */
|
|
u16 exclMask; /* Mask of exclusive locks held */
|
|
+ HANDLE hShm; /* File-handle on *-shm file. For locking. */
|
|
+ int bReadonly; /* True if hShm is opened read-only */
|
|
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
|
|
u8 id; /* Id of this connection with its winShmNode */
|
|
#endif
|
|
@@ -50659,50 +51225,6 @@
|
|
#define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
|
|
#define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
|
|
|
|
-/*
|
|
-** Apply advisory locks for all n bytes beginning at ofst.
|
|
-*/
|
|
-#define WINSHM_UNLCK 1
|
|
-#define WINSHM_RDLCK 2
|
|
-#define WINSHM_WRLCK 3
|
|
-static int winShmSystemLock(
|
|
- winShmNode *pFile, /* Apply locks to this open shared-memory segment */
|
|
- int lockType, /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */
|
|
- int ofst, /* Offset to first byte to be locked/unlocked */
|
|
- int nByte /* Number of bytes to lock or unlock */
|
|
-){
|
|
- int rc = 0; /* Result code form Lock/UnlockFileEx() */
|
|
-
|
|
- /* Access to the winShmNode object is serialized by the caller */
|
|
- assert( pFile->nRef==0 || sqlite3_mutex_held(pFile->mutex) );
|
|
-
|
|
- OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n",
|
|
- pFile->hFile.h, lockType, ofst, nByte));
|
|
-
|
|
- /* Release/Acquire the system-level lock */
|
|
- if( lockType==WINSHM_UNLCK ){
|
|
- rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0);
|
|
- }else{
|
|
- /* Initialize the locking parameters */
|
|
- DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
|
|
- if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
|
|
- rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0);
|
|
- }
|
|
-
|
|
- if( rc!= 0 ){
|
|
- rc = SQLITE_OK;
|
|
- }else{
|
|
- pFile->lastErrno = osGetLastError();
|
|
- rc = SQLITE_BUSY;
|
|
- }
|
|
-
|
|
- OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n",
|
|
- pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" :
|
|
- "winLockFile", pFile->lastErrno, sqlite3ErrName(rc)));
|
|
-
|
|
- return rc;
|
|
-}
|
|
-
|
|
/* Forward references to VFS methods */
|
|
static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*);
|
|
static int winDelete(sqlite3_vfs *,const char*,int);
|
|
@@ -50734,11 +51256,7 @@
|
|
osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
|
|
UNUSED_VARIABLE_VALUE(bRc);
|
|
}
|
|
- if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){
|
|
- SimulateIOErrorBenign(1);
|
|
- winClose((sqlite3_file *)&p->hFile);
|
|
- SimulateIOErrorBenign(0);
|
|
- }
|
|
+ winHandleClose(p->hSharedShm);
|
|
if( deleteFlag ){
|
|
SimulateIOErrorBenign(1);
|
|
sqlite3BeginBenignMalloc();
|
|
@@ -50756,42 +51274,239 @@
|
|
}
|
|
|
|
/*
|
|
-** The DMS lock has not yet been taken on shm file pShmNode. Attempt to
|
|
-** take it now. Return SQLITE_OK if successful, or an SQLite error
|
|
-** code otherwise.
|
|
-**
|
|
-** If the DMS cannot be locked because this is a readonly_shm=1
|
|
-** connection and no other process already holds a lock, return
|
|
-** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1.
|
|
+** The DMS lock has not yet been taken on the shm file associated with
|
|
+** pShmNode. Take the lock. Truncate the *-shm file if required.
|
|
+** Return SQLITE_OK if successful, or an SQLite error code otherwise.
|
|
*/
|
|
-static int winLockSharedMemory(winShmNode *pShmNode){
|
|
- int rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1);
|
|
+static int winLockSharedMemory(winShmNode *pShmNode, DWORD nMs){
|
|
+ HANDLE h = pShmNode->hSharedShm;
|
|
+ int rc = SQLITE_OK;
|
|
|
|
+ assert( sqlite3_mutex_held(pShmNode->mutex) );
|
|
+ rc = winHandleLockTimeout(h, WIN_SHM_DMS, 1, 1, 0);
|
|
if( rc==SQLITE_OK ){
|
|
+ /* We have an EXCLUSIVE lock on the DMS byte. This means that this
|
|
+ ** is the first process to open the file. Truncate it to zero bytes
|
|
+ ** in this case. */
|
|
if( pShmNode->isReadonly ){
|
|
- pShmNode->isUnlocked = 1;
|
|
- winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
|
|
- return SQLITE_READONLY_CANTINIT;
|
|
- }else if( winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){
|
|
- winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
|
|
- return winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
|
|
- "winLockSharedMemory", pShmNode->zFilename);
|
|
+ rc = SQLITE_READONLY_CANTINIT;
|
|
+ }else{
|
|
+ rc = winHandleTruncate(h, 0);
|
|
}
|
|
+
|
|
+ /* Release the EXCLUSIVE lock acquired above. */
|
|
+ winUnlockFile(&h, WIN_SHM_DMS, 0, 1, 0);
|
|
+ }else if( (rc & 0xFF)==SQLITE_BUSY ){
|
|
+ rc = SQLITE_OK;
|
|
}
|
|
|
|
if( rc==SQLITE_OK ){
|
|
- winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
|
|
+ /* Take a SHARED lock on the DMS byte. */
|
|
+ rc = winHandleLockTimeout(h, WIN_SHM_DMS, 1, 0, nMs);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ pShmNode->isUnlocked = 0;
|
|
+ }
|
|
}
|
|
|
|
- return winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
|
|
+ return rc;
|
|
}
|
|
|
|
+
|
|
/*
|
|
-** Open the shared-memory area associated with database file pDbFd.
|
|
+** Convert a UTF-8 filename into whatever form the underlying
|
|
+** operating system wants filenames in. Space to hold the result
|
|
+** is obtained from malloc and must be freed by the calling
|
|
+** function
|
|
**
|
|
-** When opening a new shared-memory file, if no other instances of that
|
|
-** file are currently open, in this process or in other processes, then
|
|
-** the file must be truncated to zero length or have its header cleared.
|
|
+** On Cygwin, 3 possible input forms are accepted:
|
|
+** - If the filename starts with "<drive>:/" or "<drive>:\",
|
|
+** it is converted to UTF-16 as-is.
|
|
+** - If the filename contains '/', it is assumed to be a
|
|
+** Cygwin absolute path, it is converted to a win32
|
|
+** absolute path in UTF-16.
|
|
+** - Otherwise it must be a filename only, the win32 filename
|
|
+** is returned in UTF-16.
|
|
+** Note: If the function cygwin_conv_path() fails, only
|
|
+** UTF-8 -> UTF-16 conversion will be done. This can only
|
|
+** happen when the file path >32k, in which case winUtf8ToUnicode()
|
|
+** will fail too.
|
|
+*/
|
|
+static void *winConvertFromUtf8Filename(const char *zFilename){
|
|
+ void *zConverted = 0;
|
|
+ if( osIsNT() ){
|
|
+#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;
|
|
+ }
|
|
+ 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());
|
|
+ }
|
|
+#endif
|
|
+ /* caller will handle out of memory */
|
|
+ return zConverted;
|
|
+}
|
|
+
|
|
+/*
|
|
+** This function is used to open a handle on a *-shm file.
|
|
+**
|
|
+** If SQLITE_ENABLE_SETLK_TIMEOUT is defined at build time, then the file
|
|
+** is opened with FILE_FLAG_OVERLAPPED specified. If not, it is not.
|
|
+*/
|
|
+static int winHandleOpen(
|
|
+ const char *zUtf8, /* File to open */
|
|
+ int *pbReadonly, /* IN/OUT: True for readonly handle */
|
|
+ HANDLE *ph /* OUT: New HANDLE for file */
|
|
+){
|
|
+ int rc = SQLITE_OK;
|
|
+ void *zConverted = 0;
|
|
+ int bReadonly = *pbReadonly;
|
|
+ HANDLE h = INVALID_HANDLE_VALUE;
|
|
+
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ const DWORD flag_overlapped = FILE_FLAG_OVERLAPPED;
|
|
+#else
|
|
+ const DWORD flag_overlapped = 0;
|
|
+#endif
|
|
+
|
|
+ /* Convert the filename to the system encoding. */
|
|
+ zConverted = winConvertFromUtf8Filename(zUtf8);
|
|
+ if( zConverted==0 ){
|
|
+ OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8));
|
|
+ rc = SQLITE_IOERR_NOMEM_BKPT;
|
|
+ goto winopenfile_out;
|
|
+ }
|
|
+
|
|
+ /* Ensure the file we are trying to open is not actually a directory. */
|
|
+ if( winIsDir(zConverted) ){
|
|
+ OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8));
|
|
+ rc = SQLITE_CANTOPEN_ISDIR;
|
|
+ goto winopenfile_out;
|
|
+ }
|
|
+
|
|
+ /* TODO: platforms.
|
|
+ ** TODO: retry-on-ioerr.
|
|
+ */
|
|
+ if( osIsNT() ){
|
|
+#if SQLITE_OS_WINRT
|
|
+ CREATEFILE2_EXTENDED_PARAMETERS extendedParameters;
|
|
+ memset(&extendedParameters, 0, sizeof(extendedParameters));
|
|
+ extendedParameters.dwSize = sizeof(extendedParameters);
|
|
+ extendedParameters.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
+ extendedParameters.dwFileFlags = flag_overlapped;
|
|
+ extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS;
|
|
+ h = osCreateFile2((LPCWSTR)zConverted,
|
|
+ (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)),/* dwDesiredAccess */
|
|
+ FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */
|
|
+ OPEN_ALWAYS, /* dwCreationDisposition */
|
|
+ &extendedParameters
|
|
+ );
|
|
+#else
|
|
+ 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
|
|
+ );
|
|
+#endif
|
|
+ }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
|
|
+ }
|
|
+
|
|
+ if( h==INVALID_HANDLE_VALUE ){
|
|
+ if( bReadonly==0 ){
|
|
+ bReadonly = 1;
|
|
+ rc = winHandleOpen(zUtf8, &bReadonly, &h);
|
|
+ }else{
|
|
+ rc = SQLITE_CANTOPEN_BKPT;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ winopenfile_out:
|
|
+ sqlite3_free(zConverted);
|
|
+ *pbReadonly = bReadonly;
|
|
+ *ph = h;
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+
|
|
+/*
|
|
+** Open the shared-memory area associated with database file pDbFd.
|
|
*/
|
|
static int winOpenSharedMemory(winFile *pDbFd){
|
|
struct winShm *p; /* The connection to be opened */
|
|
@@ -50803,98 +51518,83 @@
|
|
assert( pDbFd->pShm==0 ); /* Not previously opened */
|
|
|
|
/* Allocate space for the new sqlite3_shm object. Also speculatively
|
|
- ** allocate space for a new winShmNode and filename.
|
|
- */
|
|
+ ** allocate space for a new winShmNode and filename. */
|
|
p = sqlite3MallocZero( sizeof(*p) );
|
|
if( p==0 ) return SQLITE_IOERR_NOMEM_BKPT;
|
|
nName = sqlite3Strlen30(pDbFd->zPath);
|
|
- pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 );
|
|
+ pNew = sqlite3MallocZero( sizeof(*pShmNode) + (i64)nName + 17 );
|
|
if( pNew==0 ){
|
|
sqlite3_free(p);
|
|
return SQLITE_IOERR_NOMEM_BKPT;
|
|
}
|
|
pNew->zFilename = (char*)&pNew[1];
|
|
+ pNew->hSharedShm = INVALID_HANDLE_VALUE;
|
|
+ pNew->isUnlocked = 1;
|
|
sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
|
|
sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename);
|
|
|
|
+ /* Open a file-handle on the *-shm file for this connection. This file-handle
|
|
+ ** is only used for locking. The mapping of the *-shm file is created using
|
|
+ ** the shared file handle in winShmNode.hSharedShm. */
|
|
+ p->bReadonly = sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0);
|
|
+ rc = winHandleOpen(pNew->zFilename, &p->bReadonly, &p->hShm);
|
|
+
|
|
/* Look to see if there is an existing winShmNode that can be used.
|
|
- ** If no matching winShmNode currently exists, create a new one.
|
|
- */
|
|
+ ** If no matching winShmNode currently exists, then create a new one. */
|
|
winShmEnterMutex();
|
|
for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){
|
|
/* TBD need to come up with better match here. Perhaps
|
|
- ** use FILE_ID_BOTH_DIR_INFO Structure.
|
|
- */
|
|
+ ** use FILE_ID_BOTH_DIR_INFO Structure. */
|
|
if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break;
|
|
}
|
|
- if( pShmNode ){
|
|
- sqlite3_free(pNew);
|
|
- }else{
|
|
- int inFlags = SQLITE_OPEN_WAL;
|
|
- int outFlags = 0;
|
|
-
|
|
+ if( pShmNode==0 ){
|
|
pShmNode = pNew;
|
|
- pNew = 0;
|
|
- ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE;
|
|
- pShmNode->pNext = winShmNodeList;
|
|
- winShmNodeList = pShmNode;
|
|
|
|
+ /* Allocate a mutex for this winShmNode object, if one is required. */
|
|
if( sqlite3GlobalConfig.bCoreMutex ){
|
|
pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
|
- if( pShmNode->mutex==0 ){
|
|
- rc = SQLITE_IOERR_NOMEM_BKPT;
|
|
- goto shm_open_err;
|
|
- }
|
|
+ if( pShmNode->mutex==0 ) rc = SQLITE_IOERR_NOMEM_BKPT;
|
|
}
|
|
|
|
- if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
|
|
- inFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
|
|
- }else{
|
|
- inFlags |= SQLITE_OPEN_READONLY;
|
|
- }
|
|
- rc = winOpen(pDbFd->pVfs, pShmNode->zFilename,
|
|
- (sqlite3_file*)&pShmNode->hFile,
|
|
- inFlags, &outFlags);
|
|
- if( rc!=SQLITE_OK ){
|
|
- rc = winLogError(rc, osGetLastError(), "winOpenShm",
|
|
- pShmNode->zFilename);
|
|
- goto shm_open_err;
|
|
+ /* Open a file-handle to use for mappings, and for the DMS lock. */
|
|
+ if( rc==SQLITE_OK ){
|
|
+ HANDLE h = INVALID_HANDLE_VALUE;
|
|
+ pShmNode->isReadonly = p->bReadonly;
|
|
+ rc = winHandleOpen(pNew->zFilename, &pShmNode->isReadonly, &h);
|
|
+ pShmNode->hSharedShm = h;
|
|
}
|
|
- if( outFlags==SQLITE_OPEN_READONLY ) pShmNode->isReadonly = 1;
|
|
|
|
- rc = winLockSharedMemory(pShmNode);
|
|
- if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err;
|
|
+ /* If successful, link the new winShmNode into the global list. If an
|
|
+ ** error occurred, free the object. */
|
|
+ if( rc==SQLITE_OK ){
|
|
+ pShmNode->pNext = winShmNodeList;
|
|
+ winShmNodeList = pShmNode;
|
|
+ pNew = 0;
|
|
+ }else{
|
|
+ sqlite3_mutex_free(pShmNode->mutex);
|
|
+ if( pShmNode->hSharedShm!=INVALID_HANDLE_VALUE ){
|
|
+ osCloseHandle(pShmNode->hSharedShm);
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
- /* Make the new connection a child of the winShmNode */
|
|
- p->pShmNode = pShmNode;
|
|
+ /* If no error has occurred, link the winShm object to the winShmNode and
|
|
+ ** the winShm to pDbFd. */
|
|
+ if( rc==SQLITE_OK ){
|
|
+ p->pShmNode = pShmNode;
|
|
+ pShmNode->nRef++;
|
|
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
|
|
- p->id = pShmNode->nextShmId++;
|
|
+ p->id = pShmNode->nextShmId++;
|
|
#endif
|
|
- pShmNode->nRef++;
|
|
- pDbFd->pShm = p;
|
|
- winShmLeaveMutex();
|
|
-
|
|
- /* The reference count on pShmNode has already been incremented under
|
|
- ** the cover of the winShmEnterMutex() mutex and the pointer from the
|
|
- ** new (struct winShm) object to the pShmNode has been set. All that is
|
|
- ** left to do is to link the new object into the linked list starting
|
|
- ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex
|
|
- ** mutex.
|
|
- */
|
|
- sqlite3_mutex_enter(pShmNode->mutex);
|
|
- p->pNext = pShmNode->pFirst;
|
|
- pShmNode->pFirst = p;
|
|
- sqlite3_mutex_leave(pShmNode->mutex);
|
|
- return rc;
|
|
+ pDbFd->pShm = p;
|
|
+ }else if( p ){
|
|
+ winHandleClose(p->hShm);
|
|
+ sqlite3_free(p);
|
|
+ }
|
|
|
|
- /* Jump here on any error */
|
|
-shm_open_err:
|
|
- winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
|
|
- winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */
|
|
- sqlite3_free(p);
|
|
- sqlite3_free(pNew);
|
|
+ assert( rc!=SQLITE_OK || pShmNode->isUnlocked==0 || pShmNode->nRegion==0 );
|
|
winShmLeaveMutex();
|
|
+ sqlite3_free(pNew);
|
|
return rc;
|
|
}
|
|
|
|
@@ -50909,27 +51609,19 @@
|
|
winFile *pDbFd; /* Database holding shared-memory */
|
|
winShm *p; /* The connection to be closed */
|
|
winShmNode *pShmNode; /* The underlying shared-memory file */
|
|
- winShm **pp; /* For looping over sibling connections */
|
|
|
|
pDbFd = (winFile*)fd;
|
|
p = pDbFd->pShm;
|
|
if( p==0 ) return SQLITE_OK;
|
|
- pShmNode = p->pShmNode;
|
|
-
|
|
- /* Remove connection p from the set of connections associated
|
|
- ** with pShmNode */
|
|
- sqlite3_mutex_enter(pShmNode->mutex);
|
|
- for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
|
|
- *pp = p->pNext;
|
|
+ if( p->hShm!=INVALID_HANDLE_VALUE ){
|
|
+ osCloseHandle(p->hShm);
|
|
+ }
|
|
|
|
- /* Free the connection p */
|
|
- sqlite3_free(p);
|
|
- pDbFd->pShm = 0;
|
|
- sqlite3_mutex_leave(pShmNode->mutex);
|
|
+ pShmNode = p->pShmNode;
|
|
+ winShmEnterMutex();
|
|
|
|
/* If pShmNode->nRef has reached 0, then close the underlying
|
|
- ** shared-memory file, too */
|
|
- winShmEnterMutex();
|
|
+ ** shared-memory file, too. */
|
|
assert( pShmNode->nRef>0 );
|
|
pShmNode->nRef--;
|
|
if( pShmNode->nRef==0 ){
|
|
@@ -50937,6 +51629,9 @@
|
|
}
|
|
winShmLeaveMutex();
|
|
|
|
+ /* Free the connection p */
|
|
+ sqlite3_free(p);
|
|
+ pDbFd->pShm = 0;
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
@@ -50951,10 +51646,9 @@
|
|
){
|
|
winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */
|
|
winShm *p = pDbFd->pShm; /* The shared memory being locked */
|
|
- winShm *pX; /* For looping over all siblings */
|
|
winShmNode *pShmNode;
|
|
int rc = SQLITE_OK; /* Result code */
|
|
- u16 mask; /* Mask of locks to take or release */
|
|
+ u16 mask = (u16)((1U<<(ofst+n)) - (1U<<ofst)); /* Mask of locks to [un]take */
|
|
|
|
if( p==0 ) return SQLITE_IOERR_SHMLOCK;
|
|
pShmNode = p->pShmNode;
|
|
@@ -50968,85 +51662,81 @@
|
|
|| flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
|
|
assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
|
|
|
|
- mask = (u16)((1U<<(ofst+n)) - (1U<<ofst));
|
|
- assert( n>1 || mask==(1<<ofst) );
|
|
- sqlite3_mutex_enter(pShmNode->mutex);
|
|
- if( flags & SQLITE_SHM_UNLOCK ){
|
|
- u16 allMask = 0; /* Mask of locks held by siblings */
|
|
-
|
|
- /* See if any siblings hold this same lock */
|
|
- for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
|
|
- if( pX==p ) continue;
|
|
- assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
|
|
- allMask |= pX->sharedMask;
|
|
- }
|
|
+ /* Check that, if this to be a blocking lock, no locks that occur later
|
|
+ ** in the following list than the lock being obtained are already held:
|
|
+ **
|
|
+ ** 1. Recovery lock (ofst==2).
|
|
+ ** 2. Checkpointer lock (ofst==1).
|
|
+ ** 3. Write lock (ofst==0).
|
|
+ ** 4. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
|
|
+ **
|
|
+ ** In other words, if this is a blocking lock, none of the locks that
|
|
+ ** occur later in the above list than the lock being obtained may be
|
|
+ ** held.
|
|
+ */
|
|
+#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && defined(SQLITE_DEBUG)
|
|
+ {
|
|
+ u16 lockMask = (p->exclMask|p->sharedMask);
|
|
+ assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
|
|
+ (ofst!=2 || lockMask==0)
|
|
+ && (ofst!=1 || lockMask==0 || lockMask==2)
|
|
+ && (ofst!=0 || lockMask<3)
|
|
+ && (ofst<3 || lockMask<(1<<ofst))
|
|
+ ));
|
|
+ }
|
|
+#endif
|
|
|
|
- /* Unlock the system-level locks */
|
|
- if( (mask & allMask)==0 ){
|
|
- rc = winShmSystemLock(pShmNode, WINSHM_UNLCK, ofst+WIN_SHM_BASE, n);
|
|
- }else{
|
|
- rc = SQLITE_OK;
|
|
- }
|
|
+ /* Check if there is any work to do. There are three cases:
|
|
+ **
|
|
+ ** a) An unlock operation where there are locks to unlock,
|
|
+ ** b) An shared lock where the requested lock is not already held
|
|
+ ** c) An exclusive lock where the requested lock is not already held
|
|
+ **
|
|
+ ** The SQLite core never requests an exclusive lock that it already holds.
|
|
+ ** This is assert()ed immediately below. */
|
|
+ assert( flags!=(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK)
|
|
+ || 0==(p->exclMask & mask)
|
|
+ );
|
|
+ if( ((flags & SQLITE_SHM_UNLOCK) && ((p->exclMask|p->sharedMask) & mask))
|
|
+ || (flags==(SQLITE_SHM_SHARED|SQLITE_SHM_LOCK) && 0==(p->sharedMask & mask))
|
|
+ || (flags==(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK))
|
|
+ ){
|
|
|
|
- /* Undo the local locks */
|
|
- if( rc==SQLITE_OK ){
|
|
- p->exclMask &= ~mask;
|
|
- p->sharedMask &= ~mask;
|
|
- }
|
|
- }else if( flags & SQLITE_SHM_SHARED ){
|
|
- u16 allShared = 0; /* Union of locks held by connections other than "p" */
|
|
+ if( flags & SQLITE_SHM_UNLOCK ){
|
|
+ /* Case (a) - unlock. */
|
|
|
|
- /* Find out which shared locks are already held by sibling connections.
|
|
- ** If any sibling already holds an exclusive lock, go ahead and return
|
|
- ** SQLITE_BUSY.
|
|
- */
|
|
- for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
|
|
- if( (pX->exclMask & mask)!=0 ){
|
|
- rc = SQLITE_BUSY;
|
|
- break;
|
|
- }
|
|
- allShared |= pX->sharedMask;
|
|
- }
|
|
+ assert( (p->exclMask & p->sharedMask)==0 );
|
|
+ assert( !(flags & SQLITE_SHM_EXCLUSIVE) || (p->exclMask & mask)==mask );
|
|
+ assert( !(flags & SQLITE_SHM_SHARED) || (p->sharedMask & mask)==mask );
|
|
|
|
- /* Get shared locks at the system level, if necessary */
|
|
- if( rc==SQLITE_OK ){
|
|
- if( (allShared & mask)==0 ){
|
|
- rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, ofst+WIN_SHM_BASE, n);
|
|
- }else{
|
|
- rc = SQLITE_OK;
|
|
- }
|
|
- }
|
|
+ rc = winHandleUnlock(p->hShm, ofst+WIN_SHM_BASE, n);
|
|
|
|
- /* Get the local shared locks */
|
|
- if( rc==SQLITE_OK ){
|
|
- p->sharedMask |= mask;
|
|
- }
|
|
- }else{
|
|
- /* Make sure no sibling connections hold locks that will block this
|
|
- ** lock. If any do, return SQLITE_BUSY right away.
|
|
- */
|
|
- for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
|
|
- if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
|
|
- rc = SQLITE_BUSY;
|
|
- break;
|
|
+ /* If successful, also clear the bits in sharedMask/exclMask */
|
|
+ if( rc==SQLITE_OK ){
|
|
+ p->exclMask = (p->exclMask & ~mask);
|
|
+ p->sharedMask = (p->sharedMask & ~mask);
|
|
}
|
|
- }
|
|
-
|
|
- /* Get the exclusive locks at the system level. Then if successful
|
|
- ** also mark the local connection as being locked.
|
|
- */
|
|
- if( rc==SQLITE_OK ){
|
|
- rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, ofst+WIN_SHM_BASE, n);
|
|
+ }else{
|
|
+ int bExcl = ((flags & SQLITE_SHM_EXCLUSIVE) ? 1 : 0);
|
|
+ DWORD nMs = winFileBusyTimeout(pDbFd);
|
|
+ rc = winHandleLockTimeout(p->hShm, ofst+WIN_SHM_BASE, n, bExcl, nMs);
|
|
if( rc==SQLITE_OK ){
|
|
- assert( (p->sharedMask & mask)==0 );
|
|
- p->exclMask |= mask;
|
|
+ if( bExcl ){
|
|
+ p->exclMask = (p->exclMask | mask);
|
|
+ }else{
|
|
+ p->sharedMask = (p->sharedMask | mask);
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
- sqlite3_mutex_leave(pShmNode->mutex);
|
|
- OSTRACE(("SHM-LOCK pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x, rc=%s\n",
|
|
- osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask,
|
|
- sqlite3ErrName(rc)));
|
|
+
|
|
+ OSTRACE((
|
|
+ "SHM-LOCK(%d,%d,%d) pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x,"
|
|
+ " rc=%s\n",
|
|
+ ofst, n, flags,
|
|
+ osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask,
|
|
+ sqlite3ErrName(rc))
|
|
+ );
|
|
return rc;
|
|
}
|
|
|
|
@@ -51108,13 +51798,15 @@
|
|
|
|
sqlite3_mutex_enter(pShmNode->mutex);
|
|
if( pShmNode->isUnlocked ){
|
|
- rc = winLockSharedMemory(pShmNode);
|
|
+ /* Take the DMS lock. */
|
|
+ assert( pShmNode->nRegion==0 );
|
|
+ rc = winLockSharedMemory(pShmNode, winFileBusyTimeout(pDbFd));
|
|
if( rc!=SQLITE_OK ) goto shmpage_out;
|
|
- pShmNode->isUnlocked = 0;
|
|
}
|
|
- assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
|
|
|
|
+ assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
|
|
if( pShmNode->nRegion<=iRegion ){
|
|
+ HANDLE hShared = pShmNode->hSharedShm;
|
|
struct ShmRegion *apNew; /* New aRegion[] array */
|
|
int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
|
|
sqlite3_int64 sz; /* Current size of wal-index file */
|
|
@@ -51125,10 +51817,9 @@
|
|
** Check to see if it has been allocated (i.e. if the wal-index file is
|
|
** large enough to contain the requested region).
|
|
*/
|
|
- rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz);
|
|
+ rc = winHandleSize(hShared, &sz);
|
|
if( rc!=SQLITE_OK ){
|
|
- rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(),
|
|
- "winShmMap1", pDbFd->zPath);
|
|
+ rc = winLogError(rc, osGetLastError(), "winShmMap1", pDbFd->zPath);
|
|
goto shmpage_out;
|
|
}
|
|
|
|
@@ -51137,19 +51828,17 @@
|
|
** zero, exit early. *pp will be set to NULL and SQLITE_OK returned.
|
|
**
|
|
** Alternatively, if isWrite is non-zero, use ftruncate() to allocate
|
|
- ** the requested memory region.
|
|
- */
|
|
+ ** the requested memory region. */
|
|
if( !isWrite ) goto shmpage_out;
|
|
- rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte);
|
|
+ rc = winHandleTruncate(hShared, nByte);
|
|
if( rc!=SQLITE_OK ){
|
|
- rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(),
|
|
- "winShmMap2", pDbFd->zPath);
|
|
+ rc = winLogError(rc, osGetLastError(), "winShmMap2", pDbFd->zPath);
|
|
goto shmpage_out;
|
|
}
|
|
}
|
|
|
|
/* Map the requested memory region into this processes address space. */
|
|
- apNew = (struct ShmRegion *)sqlite3_realloc64(
|
|
+ apNew = (struct ShmRegion*)sqlite3_realloc64(
|
|
pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
|
|
);
|
|
if( !apNew ){
|
|
@@ -51168,18 +51857,13 @@
|
|
void *pMap = 0; /* Mapped memory region */
|
|
|
|
#if SQLITE_OS_WINRT
|
|
- hMap = osCreateFileMappingFromApp(pShmNode->hFile.h,
|
|
- NULL, protect, nByte, NULL
|
|
- );
|
|
+ hMap = osCreateFileMappingFromApp(hShared, NULL, protect, nByte, NULL);
|
|
#elif defined(SQLITE_WIN32_HAS_WIDE)
|
|
- hMap = osCreateFileMappingW(pShmNode->hFile.h,
|
|
- NULL, protect, 0, nByte, NULL
|
|
- );
|
|
+ hMap = osCreateFileMappingW(hShared, NULL, protect, 0, nByte, NULL);
|
|
#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA
|
|
- hMap = osCreateFileMappingA(pShmNode->hFile.h,
|
|
- NULL, protect, 0, nByte, NULL
|
|
- );
|
|
+ hMap = osCreateFileMappingA(hShared, NULL, protect, 0, nByte, NULL);
|
|
#endif
|
|
+
|
|
OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n",
|
|
osGetCurrentProcessId(), pShmNode->nRegion, nByte,
|
|
hMap ? "ok" : "failed"));
|
|
@@ -51222,7 +51906,9 @@
|
|
}else{
|
|
*pp = 0;
|
|
}
|
|
- if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY;
|
|
+ if( pShmNode->isReadonly && rc==SQLITE_OK ){
|
|
+ rc = SQLITE_READONLY;
|
|
+ }
|
|
sqlite3_mutex_leave(pShmNode->mutex);
|
|
return rc;
|
|
}
|
|
@@ -51542,47 +52228,6 @@
|
|
** sqlite3_vfs object.
|
|
*/
|
|
|
|
-#if defined(__CYGWIN__)
|
|
-/*
|
|
-** Convert a filename from whatever the underlying operating system
|
|
-** supports for filenames into UTF-8. Space to hold the result is
|
|
-** obtained from malloc and must be freed by the calling function.
|
|
-*/
|
|
-static char *winConvertToUtf8Filename(const void *zFilename){
|
|
- char *zConverted = 0;
|
|
- if( osIsNT() ){
|
|
- zConverted = winUnicodeToUtf8(zFilename);
|
|
- }
|
|
-#ifdef SQLITE_WIN32_HAS_ANSI
|
|
- else{
|
|
- zConverted = winMbcsToUtf8(zFilename, osAreFileApisANSI());
|
|
- }
|
|
-#endif
|
|
- /* caller will handle out of memory */
|
|
- return zConverted;
|
|
-}
|
|
-#endif
|
|
-
|
|
-/*
|
|
-** Convert a UTF-8 filename into whatever form the underlying
|
|
-** operating system wants filenames in. Space to hold the result
|
|
-** is obtained from malloc and must be freed by the calling
|
|
-** function.
|
|
-*/
|
|
-static void *winConvertFromUtf8Filename(const char *zFilename){
|
|
- void *zConverted = 0;
|
|
- if( osIsNT() ){
|
|
- zConverted = winUtf8ToUnicode(zFilename);
|
|
- }
|
|
-#ifdef SQLITE_WIN32_HAS_ANSI
|
|
- else{
|
|
- zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI());
|
|
- }
|
|
-#endif
|
|
- /* caller will handle out of memory */
|
|
- return zConverted;
|
|
-}
|
|
-
|
|
/*
|
|
** This function returns non-zero if the specified UTF-8 string buffer
|
|
** ends with a directory separator character or one was successfully
|
|
@@ -51595,7 +52240,14 @@
|
|
if( winIsDirSep(zBuf[nLen-1]) ){
|
|
return 1;
|
|
}else if( nLen+1<nBuf ){
|
|
- zBuf[nLen] = winGetDirSep();
|
|
+ if( !osGetenv ){
|
|
+ zBuf[nLen] = winGetDirSep();
|
|
+ }else if( winIsDriveLetterAndColon(zBuf) && winIsDirSep(zBuf[2]) ){
|
|
+ zBuf[nLen] = '\\';
|
|
+ zBuf[2]='\\';
|
|
+ }else{
|
|
+ zBuf[nLen] = '/';
|
|
+ }
|
|
zBuf[nLen+1] = '\0';
|
|
return 1;
|
|
}
|
|
@@ -51622,14 +52274,14 @@
|
|
** The pointer returned in pzBuf must be freed via sqlite3_free().
|
|
*/
|
|
static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
|
|
- static char zChars[] =
|
|
+ static const char zChars[] =
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
"0123456789";
|
|
size_t i, j;
|
|
DWORD pid;
|
|
int nPre = sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX);
|
|
- int nMax, nBuf, nDir, nLen;
|
|
+ i64 nMax, nBuf, nDir, nLen;
|
|
char *zBuf;
|
|
|
|
/* It's odd to simulate an io-error here, but really this is just
|
|
@@ -51641,7 +52293,8 @@
|
|
/* Allocate a temporary buffer to store the fully qualified file
|
|
** name for the temporary file. If this fails, we cannot continue.
|
|
*/
|
|
- nMax = pVfs->mxPathname; nBuf = nMax + 2;
|
|
+ nMax = pVfs->mxPathname;
|
|
+ nBuf = 2 + (i64)nMax;
|
|
zBuf = sqlite3MallocZero( nBuf );
|
|
if( !zBuf ){
|
|
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
|
|
@@ -51672,7 +52325,7 @@
|
|
}
|
|
|
|
#if defined(__CYGWIN__)
|
|
- else{
|
|
+ else if( osGetenv!=NULL ){
|
|
static const char *azDirs[] = {
|
|
0, /* getenv("SQLITE_TMPDIR") */
|
|
0, /* getenv("TMPDIR") */
|
|
@@ -51688,11 +52341,11 @@
|
|
unsigned int i;
|
|
const char *zDir = 0;
|
|
|
|
- if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR");
|
|
- if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
|
|
- if( !azDirs[2] ) azDirs[2] = getenv("TMP");
|
|
- if( !azDirs[3] ) azDirs[3] = getenv("TEMP");
|
|
- if( !azDirs[4] ) azDirs[4] = getenv("USERPROFILE");
|
|
+ if( !azDirs[0] ) azDirs[0] = osGetenv("SQLITE_TMPDIR");
|
|
+ if( !azDirs[1] ) azDirs[1] = osGetenv("TMPDIR");
|
|
+ if( !azDirs[2] ) azDirs[2] = osGetenv("TMP");
|
|
+ if( !azDirs[3] ) azDirs[3] = osGetenv("TEMP");
|
|
+ if( !azDirs[4] ) azDirs[4] = osGetenv("USERPROFILE");
|
|
for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
|
|
void *zConverted;
|
|
if( zDir==0 ) continue;
|
|
@@ -51701,7 +52354,7 @@
|
|
** it must be converted to a native Win32 path via the Cygwin API
|
|
** prior to using it.
|
|
*/
|
|
- if( winIsDriveLetterAndColon(zDir) ){
|
|
+ {
|
|
zConverted = winConvertFromUtf8Filename(zDir);
|
|
if( !zConverted ){
|
|
sqlite3_free(zBuf);
|
|
@@ -51714,44 +52367,12 @@
|
|
break;
|
|
}
|
|
sqlite3_free(zConverted);
|
|
- }else{
|
|
- zConverted = sqlite3MallocZero( nMax+1 );
|
|
- if( !zConverted ){
|
|
- sqlite3_free(zBuf);
|
|
- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
|
|
- return SQLITE_IOERR_NOMEM_BKPT;
|
|
- }
|
|
- if( cygwin_conv_path(
|
|
- osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A, zDir,
|
|
- zConverted, nMax+1)<0 ){
|
|
- sqlite3_free(zConverted);
|
|
- sqlite3_free(zBuf);
|
|
- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_CONVPATH\n"));
|
|
- return winLogError(SQLITE_IOERR_CONVPATH, (DWORD)errno,
|
|
- "winGetTempname2", zDir);
|
|
- }
|
|
- if( winIsDir(zConverted) ){
|
|
- /* At this point, we know the candidate directory exists and should
|
|
- ** be used. However, we may need to convert the string containing
|
|
- ** its name into UTF-8 (i.e. if it is UTF-16 right now).
|
|
- */
|
|
- char *zUtf8 = winConvertToUtf8Filename(zConverted);
|
|
- if( !zUtf8 ){
|
|
- sqlite3_free(zConverted);
|
|
- sqlite3_free(zBuf);
|
|
- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
|
|
- return SQLITE_IOERR_NOMEM_BKPT;
|
|
- }
|
|
- sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
|
|
- sqlite3_free(zUtf8);
|
|
- sqlite3_free(zConverted);
|
|
- break;
|
|
- }
|
|
- sqlite3_free(zConverted);
|
|
}
|
|
}
|
|
}
|
|
-#elif !SQLITE_OS_WINRT && !defined(__CYGWIN__)
|
|
+#endif
|
|
+
|
|
+#if !SQLITE_OS_WINRT && defined(_WIN32)
|
|
else if( osIsNT() ){
|
|
char *zMulti;
|
|
LPWSTR zWidePath = sqlite3MallocZero( nMax*sizeof(WCHAR) );
|
|
@@ -51875,7 +52496,7 @@
|
|
return 0; /* Invalid name? */
|
|
}
|
|
attr = sAttrData.dwFileAttributes;
|
|
-#if SQLITE_OS_WINCE==0
|
|
+#if SQLITE_OS_WINCE==0 && defined(SQLITE_WIN32_HAS_ANSI)
|
|
}else{
|
|
attr = osGetFileAttributesA((char*)zConverted);
|
|
#endif
|
|
@@ -51892,6 +52513,12 @@
|
|
);
|
|
|
|
/*
|
|
+** The Windows version of xAccess() accepts an extra bit in the flags
|
|
+** parameter that prevents an anti-virus retry loop.
|
|
+*/
|
|
+#define NORETRY 0x4000
|
|
+
|
|
+/*
|
|
** Open a file.
|
|
*/
|
|
static int winOpen(
|
|
@@ -51915,6 +52542,7 @@
|
|
void *zConverted; /* Filename in OS encoding */
|
|
const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */
|
|
int cnt = 0;
|
|
+ int isRO = 0; /* file is known to be accessible readonly */
|
|
|
|
/* If argument zPath is a NULL pointer, this function is required to open
|
|
** a temporary file. Use this buffer to store the file name in.
|
|
@@ -52079,9 +52707,9 @@
|
|
&extendedParameters);
|
|
if( h!=INVALID_HANDLE_VALUE ) break;
|
|
if( isReadWrite ){
|
|
- int rc2, isRO = 0;
|
|
+ int rc2;
|
|
sqlite3BeginBenignMalloc();
|
|
- rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
|
|
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ|NORETRY, &isRO);
|
|
sqlite3EndBenignMalloc();
|
|
if( rc2==SQLITE_OK && isRO ) break;
|
|
}
|
|
@@ -52096,9 +52724,9 @@
|
|
NULL);
|
|
if( h!=INVALID_HANDLE_VALUE ) break;
|
|
if( isReadWrite ){
|
|
- int rc2, isRO = 0;
|
|
+ int rc2;
|
|
sqlite3BeginBenignMalloc();
|
|
- rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
|
|
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ|NORETRY, &isRO);
|
|
sqlite3EndBenignMalloc();
|
|
if( rc2==SQLITE_OK && isRO ) break;
|
|
}
|
|
@@ -52116,9 +52744,9 @@
|
|
NULL);
|
|
if( h!=INVALID_HANDLE_VALUE ) break;
|
|
if( isReadWrite ){
|
|
- int rc2, isRO = 0;
|
|
+ int rc2;
|
|
sqlite3BeginBenignMalloc();
|
|
- rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
|
|
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ|NORETRY, &isRO);
|
|
sqlite3EndBenignMalloc();
|
|
if( rc2==SQLITE_OK && isRO ) break;
|
|
}
|
|
@@ -52133,7 +52761,7 @@
|
|
if( h==INVALID_HANDLE_VALUE ){
|
|
sqlite3_free(zConverted);
|
|
sqlite3_free(zTmpname);
|
|
- if( isReadWrite && !isExclusive ){
|
|
+ if( isReadWrite && isRO && !isExclusive ){
|
|
return winOpen(pVfs, zName, id,
|
|
((flags|SQLITE_OPEN_READONLY) &
|
|
~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
|
|
@@ -52335,8 +52963,14 @@
|
|
int rc = 0;
|
|
DWORD lastErrno = 0;
|
|
void *zConverted;
|
|
+ int noRetry = 0; /* Do not use winRetryIoerr() */
|
|
UNUSED_PARAMETER(pVfs);
|
|
|
|
+ if( (flags & NORETRY)!=0 ){
|
|
+ noRetry = 1;
|
|
+ flags &= ~NORETRY;
|
|
+ }
|
|
+
|
|
SimulateIOError( return SQLITE_IOERR_ACCESS; );
|
|
OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n",
|
|
zFilename, flags, pResOut));
|
|
@@ -52359,7 +52993,10 @@
|
|
memset(&sAttrData, 0, sizeof(sAttrData));
|
|
while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
|
|
GetFileExInfoStandard,
|
|
- &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){}
|
|
+ &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.
|
|
@@ -52427,6 +53064,7 @@
|
|
return ( sqlite3Isalpha(zPathname[0]) && zPathname[1]==':' );
|
|
}
|
|
|
|
+#ifdef _WIN32
|
|
/*
|
|
** Returns non-zero if the specified path name should be used verbatim. If
|
|
** non-zero is returned from this function, the calling function must simply
|
|
@@ -52463,6 +53101,70 @@
|
|
*/
|
|
return FALSE;
|
|
}
|
|
+#endif /* _WIN32 */
|
|
+
|
|
+#ifdef __CYGWIN__
|
|
+/*
|
|
+** Simplify a filename into its canonical form
|
|
+** by making the following changes:
|
|
+**
|
|
+** * convert any '/' to '\' (win32) or reverse (Cygwin)
|
|
+** * removing any trailing and duplicate / (except for UNC paths)
|
|
+** * convert /./ into just /
|
|
+**
|
|
+** Changes are made in-place. Return the new name length.
|
|
+**
|
|
+** The original filename is in z[0..]. If the path is shortened,
|
|
+** no-longer used bytes will be written by '\0'.
|
|
+*/
|
|
+static void winSimplifyName(char *z){
|
|
+ int i, j;
|
|
+ for(i=j=0; z[i]; ++i){
|
|
+ if( winIsDirSep(z[i]) ){
|
|
+#if !defined(SQLITE_TEST)
|
|
+ /* Some test-cases assume that "./foo" and "foo" are different */
|
|
+ if( z[i+1]=='.' && winIsDirSep(z[i+2]) ){
|
|
+ ++i;
|
|
+ continue;
|
|
+ }
|
|
+#endif
|
|
+ if( !z[i+1] || (winIsDirSep(z[i+1]) && (i!=0)) ){
|
|
+ continue;
|
|
+ }
|
|
+ z[j++] = osGetenv?'/':'\\';
|
|
+ }else{
|
|
+ z[j++] = z[i];
|
|
+ }
|
|
+ }
|
|
+ while(j<i) z[j++] = '\0';
|
|
+}
|
|
+
|
|
+#define SQLITE_MAX_SYMLINKS 100
|
|
+
|
|
+static int mkFullPathname(
|
|
+ const char *zPath, /* Input path */
|
|
+ char *zOut, /* Output buffer */
|
|
+ int nOut /* Allocated size of buffer zOut */
|
|
+){
|
|
+ int nPath = sqlite3Strlen30(zPath);
|
|
+ int iOff = 0;
|
|
+ if( zPath[0]!='/' ){
|
|
+ if( osGetcwd(zOut, nOut-2)==0 ){
|
|
+ return winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)osErrno, "getcwd", zPath);
|
|
+ }
|
|
+ iOff = sqlite3Strlen30(zOut);
|
|
+ zOut[iOff++] = '/';
|
|
+ }
|
|
+ if( (iOff+nPath+1)>nOut ){
|
|
+ /* SQLite assumes that xFullPathname() nul-terminates the output buffer
|
|
+ ** even if it returns an error. */
|
|
+ zOut[iOff] = '\0';
|
|
+ return SQLITE_CANTOPEN_BKPT;
|
|
+ }
|
|
+ sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath);
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+#endif /* __CYGWIN__ */
|
|
|
|
/*
|
|
** Turn a relative pathname into a full pathname. Write the full
|
|
@@ -52475,8 +53177,8 @@
|
|
int nFull, /* Size of output buffer in bytes */
|
|
char *zFull /* Output buffer */
|
|
){
|
|
-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
|
|
- DWORD nByte;
|
|
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
|
|
+ int nByte;
|
|
void *zConverted;
|
|
char *zOut;
|
|
#endif
|
|
@@ -52489,64 +53191,82 @@
|
|
zRelative++;
|
|
}
|
|
|
|
-#if defined(__CYGWIN__)
|
|
SimulateIOError( return SQLITE_ERROR );
|
|
- UNUSED_PARAMETER(nFull);
|
|
- assert( nFull>=pVfs->mxPathname );
|
|
- 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 slash.
|
|
- */
|
|
- char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
|
|
- if( !zOut ){
|
|
- return SQLITE_IOERR_NOMEM_BKPT;
|
|
- }
|
|
- if( cygwin_conv_path(
|
|
- (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A) |
|
|
- CCP_RELATIVE, zRelative, zOut, pVfs->mxPathname+1)<0 ){
|
|
- sqlite3_free(zOut);
|
|
- return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno,
|
|
- "winFullPathname1", zRelative);
|
|
- }else{
|
|
- char *zUtf8 = winConvertToUtf8Filename(zOut);
|
|
- if( !zUtf8 ){
|
|
- sqlite3_free(zOut);
|
|
- return SQLITE_IOERR_NOMEM_BKPT;
|
|
- }
|
|
- sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
|
|
- sqlite3_data_directory, winGetDirSep(), zUtf8);
|
|
- sqlite3_free(zUtf8);
|
|
- sqlite3_free(zOut);
|
|
- }
|
|
- }else{
|
|
- char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
|
|
- if( !zOut ){
|
|
- return SQLITE_IOERR_NOMEM_BKPT;
|
|
- }
|
|
- if( cygwin_conv_path(
|
|
- (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A),
|
|
- zRelative, zOut, pVfs->mxPathname+1)<0 ){
|
|
- sqlite3_free(zOut);
|
|
- return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno,
|
|
- "winFullPathname2", zRelative);
|
|
- }else{
|
|
- char *zUtf8 = winConvertToUtf8Filename(zOut);
|
|
- if( !zUtf8 ){
|
|
- sqlite3_free(zOut);
|
|
- return SQLITE_IOERR_NOMEM_BKPT;
|
|
- }
|
|
- sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8);
|
|
- sqlite3_free(zUtf8);
|
|
- sqlite3_free(zOut);
|
|
+
|
|
+#ifdef __CYGWIN__
|
|
+ if( osGetcwd ){
|
|
+ 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 */
|
|
+ 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. */
|
|
+ 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);
|
|
+ }
|
|
+ }else{
|
|
+ bLink = ((buf.st_mode & 0170000) == 0120000);
|
|
+ }
|
|
+
|
|
+ if( bLink ){
|
|
+ if( zDel==0 ){
|
|
+ zDel = sqlite3MallocZero(nFull);
|
|
+ if( zDel==0 ) rc = SQLITE_NOMEM;
|
|
+ }else if( ++nLink>SQLITE_MAX_SYMLINKS ){
|
|
+ rc = SQLITE_CANTOPEN_BKPT;
|
|
+ }
|
|
+
|
|
+ if( rc==SQLITE_OK ){
|
|
+ nByte = osReadlink(zIn, zDel, nFull-1);
|
|
+ if( nByte ==(DWORD)-1 ){
|
|
+ rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)osErrno, "readlink", zIn);
|
|
+ }else{
|
|
+ if( zDel[0]!='/' ){
|
|
+ int n;
|
|
+ for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--);
|
|
+ if( nByte+n+1>nFull ){
|
|
+ rc = SQLITE_CANTOPEN_BKPT;
|
|
+ }else{
|
|
+ memmove(&zDel[n], zDel, nByte+1);
|
|
+ memcpy(zDel, zIn, n);
|
|
+ nByte += n;
|
|
+ }
|
|
+ }
|
|
+ zDel[nByte] = '\0';
|
|
+ }
|
|
+ }
|
|
+
|
|
+ zIn = zDel;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ assert( rc!=SQLITE_OK || zIn!=zFull || zIn[0]=='/' );
|
|
+ if( rc==SQLITE_OK && zIn!=zFull ){
|
|
+ rc = mkFullPathname(zIn, zFull, nFull);
|
|
+ }
|
|
+ if( bLink==0 ) break;
|
|
+ zIn = zFull;
|
|
+ }while( rc==SQLITE_OK );
|
|
+
|
|
+ sqlite3_free(zDel);
|
|
+ winSimplifyName(zFull);
|
|
+ return rc;
|
|
}
|
|
}
|
|
- return SQLITE_OK;
|
|
-#endif
|
|
+#endif /* __CYGWIN__ */
|
|
|
|
-#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__)
|
|
+#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && 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. */
|
|
@@ -52565,7 +53285,8 @@
|
|
return SQLITE_OK;
|
|
#endif
|
|
|
|
-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
|
|
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
|
|
+#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
|
|
** function failing. This function could fail if, for example, the
|
|
@@ -52583,6 +53304,7 @@
|
|
sqlite3_data_directory, winGetDirSep(), zRelative);
|
|
return SQLITE_OK;
|
|
}
|
|
+#endif
|
|
zConverted = winConvertFromUtf8Filename(zRelative);
|
|
if( zConverted==0 ){
|
|
return SQLITE_IOERR_NOMEM_BKPT;
|
|
@@ -52621,13 +53343,12 @@
|
|
return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(),
|
|
"winFullPathname3", zRelative);
|
|
}
|
|
- nByte += 3;
|
|
- zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
|
|
+ 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, zTemp, 0);
|
|
+ nByte = osGetFullPathNameA((char*)zConverted, nByte+3, zTemp, 0);
|
|
if( nByte==0 ){
|
|
sqlite3_free(zConverted);
|
|
sqlite3_free(zTemp);
|
|
@@ -52640,7 +53361,26 @@
|
|
}
|
|
#endif
|
|
if( zOut ){
|
|
+#ifdef __CYGWIN__
|
|
+ if( memcmp(zOut, "\\\\?\\", 4) ){
|
|
+ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut);
|
|
+ }else if( memcmp(zOut+4, "UNC\\", 4) ){
|
|
+ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut+4);
|
|
+ }else{
|
|
+ char *p = zOut+6;
|
|
+ *p = '\\';
|
|
+ if( osGetcwd ){
|
|
+ /* On Cygwin, UNC paths use forward slashes */
|
|
+ while( *p ){
|
|
+ if( *p=='\\' ) *p = '/';
|
|
+ ++p;
|
|
+ }
|
|
+ }
|
|
+ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut+6);
|
|
+ }
|
|
+#else
|
|
sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut);
|
|
+#endif /* __CYGWIN__ */
|
|
sqlite3_free(zOut);
|
|
return SQLITE_OK;
|
|
}else{
|
|
@@ -52670,25 +53410,8 @@
|
|
*/
|
|
static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
|
|
HANDLE h;
|
|
-#if defined(__CYGWIN__)
|
|
- int nFull = pVfs->mxPathname+1;
|
|
- char *zFull = sqlite3MallocZero( nFull );
|
|
- void *zConverted = 0;
|
|
- if( zFull==0 ){
|
|
- OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
|
|
- return 0;
|
|
- }
|
|
- if( winFullPathname(pVfs, zFilename, nFull, zFull)!=SQLITE_OK ){
|
|
- sqlite3_free(zFull);
|
|
- OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
|
|
- return 0;
|
|
- }
|
|
- zConverted = winConvertFromUtf8Filename(zFull);
|
|
- sqlite3_free(zFull);
|
|
-#else
|
|
void *zConverted = winConvertFromUtf8Filename(zFilename);
|
|
UNUSED_PARAMETER(pVfs);
|
|
-#endif
|
|
if( zConverted==0 ){
|
|
OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
|
|
return 0;
|
|
@@ -53037,7 +53760,7 @@
|
|
|
|
/* Double-check that the aSyscall[] array has been constructed
|
|
** correctly. See ticket [bb3a86e890c8e96ab] */
|
|
- assert( ArraySize(aSyscall)==80 );
|
|
+ assert( ArraySize(aSyscall)==89 );
|
|
|
|
/* get memory map allocation granularity */
|
|
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
|
|
@@ -53656,13 +54379,13 @@
|
|
}
|
|
if( p==0 ){
|
|
MemStore **apNew;
|
|
- p = sqlite3Malloc( sizeof(*p) + szName + 3 );
|
|
+ p = sqlite3Malloc( sizeof(*p) + (i64)szName + 3 );
|
|
if( p==0 ){
|
|
sqlite3_mutex_leave(pVfsMutex);
|
|
return SQLITE_NOMEM;
|
|
}
|
|
apNew = sqlite3Realloc(memdb_g.apMemStore,
|
|
- sizeof(apNew[0])*(memdb_g.nMemStore+1) );
|
|
+ sizeof(apNew[0])*(1+(i64)memdb_g.nMemStore) );
|
|
if( apNew==0 ){
|
|
sqlite3_free(p);
|
|
sqlite3_mutex_leave(pVfsMutex);
|
|
@@ -54095,7 +54818,7 @@
|
|
** no fewer collisions than the no-op *1. */
|
|
#define BITVEC_HASH(X) (((X)*1)%BITVEC_NINT)
|
|
|
|
-#define BITVEC_NPTR (BITVEC_USIZE/sizeof(Bitvec *))
|
|
+#define BITVEC_NPTR ((u32)(BITVEC_USIZE/sizeof(Bitvec *)))
|
|
|
|
|
|
/*
|
|
@@ -54244,7 +54967,9 @@
|
|
}else{
|
|
memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));
|
|
memset(p->u.apSub, 0, sizeof(p->u.apSub));
|
|
- p->iDivisor = (p->iSize + BITVEC_NPTR - 1)/BITVEC_NPTR;
|
|
+ p->iDivisor = p->iSize/BITVEC_NPTR;
|
|
+ if( (p->iSize%BITVEC_NPTR)!=0 ) p->iDivisor++;
|
|
+ if( p->iDivisor<BITVEC_NBIT ) p->iDivisor = BITVEC_NBIT;
|
|
rc = sqlite3BitvecSet(p, i);
|
|
for(j=0; j<BITVEC_NINT; j++){
|
|
if( aiValues[j] ) rc |= sqlite3BitvecSet(p, aiValues[j]);
|
|
@@ -54278,7 +55003,7 @@
|
|
}
|
|
}
|
|
if( p->iSize<=BITVEC_NBIT ){
|
|
- p->u.aBitmap[i/BITVEC_SZELEM] &= ~(1 << (i&(BITVEC_SZELEM-1)));
|
|
+ p->u.aBitmap[i/BITVEC_SZELEM] &= ~(BITVEC_TELEM)(1<<(i&(BITVEC_SZELEM-1)));
|
|
}else{
|
|
unsigned int j;
|
|
u32 *aiValues = pBuf;
|
|
@@ -54329,7 +55054,7 @@
|
|
** individual bits within V.
|
|
*/
|
|
#define SETBIT(V,I) V[I>>3] |= (1<<(I&7))
|
|
-#define CLEARBIT(V,I) V[I>>3] &= ~(1<<(I&7))
|
|
+#define CLEARBIT(V,I) V[I>>3] &= ~(BITVEC_TELEM)(1<<(I&7))
|
|
#define TESTBIT(V,I) (V[I>>3]&(1<<(I&7)))!=0
|
|
|
|
/*
|
|
@@ -54372,7 +55097,7 @@
|
|
/* Allocate the Bitvec to be tested and a linear array of
|
|
** bits to act as the reference */
|
|
pBitvec = sqlite3BitvecCreate( sz );
|
|
- pV = sqlite3MallocZero( (sz+7)/8 + 1 );
|
|
+ pV = sqlite3MallocZero( (7+(i64)sz)/8 + 1 );
|
|
pTmpSpace = sqlite3_malloc64(BITVEC_SZ);
|
|
if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end;
|
|
|
|
@@ -55613,10 +56338,6 @@
|
|
sqlite3_mutex *mutex; /* Mutex for accessing the following: */
|
|
PgFreeslot *pFree; /* Free page blocks */
|
|
int nFreeSlot; /* Number of unused pcache slots */
|
|
- /* The following value requires a mutex to change. We skip the mutex on
|
|
- ** reading because (1) most platforms read a 32-bit integer atomically and
|
|
- ** (2) even if an incorrect value is read, no great harm is done since this
|
|
- ** is really just an optimization. */
|
|
int bUnderPressure; /* True if low on PAGECACHE memory */
|
|
} pcache1_g;
|
|
|
|
@@ -55664,7 +56385,7 @@
|
|
pcache1.nReserve = n>90 ? 10 : (n/10 + 1);
|
|
pcache1.pStart = pBuf;
|
|
pcache1.pFree = 0;
|
|
- pcache1.bUnderPressure = 0;
|
|
+ AtomicStore(&pcache1.bUnderPressure,0);
|
|
while( n-- ){
|
|
p = (PgFreeslot*)pBuf;
|
|
p->pNext = pcache1.pFree;
|
|
@@ -55732,7 +56453,7 @@
|
|
if( p ){
|
|
pcache1.pFree = pcache1.pFree->pNext;
|
|
pcache1.nFreeSlot--;
|
|
- pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
|
|
+ AtomicStore(&pcache1.bUnderPressure,pcache1.nFreeSlot<pcache1.nReserve);
|
|
assert( pcache1.nFreeSlot>=0 );
|
|
sqlite3StatusHighwater(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
|
|
sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_USED, 1);
|
|
@@ -55771,7 +56492,7 @@
|
|
pSlot->pNext = pcache1.pFree;
|
|
pcache1.pFree = pSlot;
|
|
pcache1.nFreeSlot++;
|
|
- pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
|
|
+ AtomicStore(&pcache1.bUnderPressure,pcache1.nFreeSlot<pcache1.nReserve);
|
|
assert( pcache1.nFreeSlot<=pcache1.nSlot );
|
|
sqlite3_mutex_leave(pcache1.mutex);
|
|
}else{
|
|
@@ -55902,7 +56623,7 @@
|
|
*/
|
|
static int pcache1UnderMemoryPressure(PCache1 *pCache){
|
|
if( pcache1.nSlot && (pCache->szPage+pCache->szExtra)<=pcache1.szSlot ){
|
|
- return pcache1.bUnderPressure;
|
|
+ return AtomicLoad(&pcache1.bUnderPressure);
|
|
}else{
|
|
return sqlite3HeapNearlyFull();
|
|
}
|
|
@@ -55919,12 +56640,12 @@
|
|
*/
|
|
static void pcache1ResizeHash(PCache1 *p){
|
|
PgHdr1 **apNew;
|
|
- unsigned int nNew;
|
|
- unsigned int i;
|
|
+ u64 nNew;
|
|
+ u32 i;
|
|
|
|
assert( sqlite3_mutex_held(p->pGroup->mutex) );
|
|
|
|
- nNew = p->nHash*2;
|
|
+ nNew = 2*(u64)p->nHash;
|
|
if( nNew<256 ){
|
|
nNew = 256;
|
|
}
|
|
@@ -56147,7 +56868,7 @@
|
|
static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
|
|
PCache1 *pCache; /* The newly created page cache */
|
|
PGroup *pGroup; /* The group the new page cache will belong to */
|
|
- int sz; /* Bytes of memory required to allocate the new cache */
|
|
+ i64 sz; /* Bytes of memory required to allocate the new cache */
|
|
|
|
assert( (szPage & (szPage-1))==0 && szPage>=512 && szPage<=65536 );
|
|
assert( szExtra < 300 );
|
|
@@ -58035,6 +58756,9 @@
|
|
Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */
|
|
char *zWal; /* File name for write-ahead log */
|
|
#endif
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ sqlite3 *dbWal;
|
|
+#endif
|
|
};
|
|
|
|
/*
|
|
@@ -58626,7 +59350,7 @@
|
|
** If an error occurs while reading from the journal file, an SQLite
|
|
** error code is returned.
|
|
*/
|
|
-static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u32 nSuper){
|
|
+static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u64 nSuper){
|
|
int rc; /* Return code */
|
|
u32 len; /* Length in bytes of super-journal name */
|
|
i64 szJ; /* Total size in bytes of journal file pJrnl */
|
|
@@ -59181,6 +59905,15 @@
|
|
|
|
if( pagerUseWal(pPager) ){
|
|
assert( !isOpen(pPager->jfd) );
|
|
+ if( pPager->eState==PAGER_ERROR ){
|
|
+ /* If an IO error occurs in wal.c while attempting to wrap the wal file,
|
|
+ ** then the Wal object may be holding a write-lock but no read-lock.
|
|
+ ** This call ensures that the write-lock is dropped as well. We cannot
|
|
+ ** have sqlite3WalEndReadTransaction() drop the write-lock, as it once
|
|
+ ** did, because this would break "BEGIN EXCLUSIVE" handling for
|
|
+ ** SQLITE_ENABLE_SETLK_TIMEOUT builds. */
|
|
+ sqlite3WalEndWriteTransaction(pPager->pWal);
|
|
+ }
|
|
sqlite3WalEndReadTransaction(pPager->pWal);
|
|
pPager->eState = PAGER_OPEN;
|
|
}else if( !pPager->exclusiveMode ){
|
|
@@ -59862,12 +60595,12 @@
|
|
char *zJournal; /* Pointer to one journal within MJ file */
|
|
char *zSuperPtr; /* Space to hold super-journal filename */
|
|
char *zFree = 0; /* Free this buffer */
|
|
- int nSuperPtr; /* Amount of space allocated to zSuperPtr[] */
|
|
+ i64 nSuperPtr; /* Amount of space allocated to zSuperPtr[] */
|
|
|
|
/* Allocate space for both the pJournal and pSuper file descriptors.
|
|
** If successful, open the super-journal file for reading.
|
|
*/
|
|
- pSuper = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
|
|
+ pSuper = (sqlite3_file *)sqlite3MallocZero(2 * (i64)pVfs->szOsFile);
|
|
if( !pSuper ){
|
|
rc = SQLITE_NOMEM_BKPT;
|
|
pJournal = 0;
|
|
@@ -59885,11 +60618,14 @@
|
|
*/
|
|
rc = sqlite3OsFileSize(pSuper, &nSuperJournal);
|
|
if( rc!=SQLITE_OK ) goto delsuper_out;
|
|
- nSuperPtr = pVfs->mxPathname+1;
|
|
+ nSuperPtr = 1 + (i64)pVfs->mxPathname;
|
|
+ assert( nSuperJournal>=0 && nSuperPtr>0 );
|
|
zFree = sqlite3Malloc(4 + nSuperJournal + nSuperPtr + 2);
|
|
if( !zFree ){
|
|
rc = SQLITE_NOMEM_BKPT;
|
|
goto delsuper_out;
|
|
+ }else{
|
|
+ assert( nSuperJournal<=0x7fffffff );
|
|
}
|
|
zFree[0] = zFree[1] = zFree[2] = zFree[3] = 0;
|
|
zSuperJournal = &zFree[4];
|
|
@@ -60150,7 +60886,7 @@
|
|
** for pageSize.
|
|
*/
|
|
zSuper = pPager->pTmpSpace;
|
|
- rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1);
|
|
+ rc = readSuperJournal(pPager->jfd, zSuper, 1+(i64)pPager->pVfs->mxPathname);
|
|
if( rc==SQLITE_OK && zSuper[0] ){
|
|
rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res);
|
|
}
|
|
@@ -60289,7 +61025,7 @@
|
|
** which case it requires 4 0x00 bytes in memory immediately before
|
|
** the filename. */
|
|
zSuper = &pPager->pTmpSpace[4];
|
|
- rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1);
|
|
+ rc = readSuperJournal(pPager->jfd, zSuper, 1+(i64)pPager->pVfs->mxPathname);
|
|
testcase( rc!=SQLITE_OK );
|
|
}
|
|
if( rc==SQLITE_OK
|
|
@@ -62060,6 +62796,7 @@
|
|
const char *zUri = 0; /* URI args to copy */
|
|
int nUriByte = 1; /* Number of bytes of URI args at *zUri */
|
|
|
|
+
|
|
/* Figure out how much space is required for each journal file-handle
|
|
** (there are two of them, the main journal and the sub-journal). */
|
|
journalFileSize = ROUND8(sqlite3JournalSize(pVfs));
|
|
@@ -62085,8 +62822,8 @@
|
|
*/
|
|
if( zFilename && zFilename[0] ){
|
|
const char *z;
|
|
- nPathname = pVfs->mxPathname+1;
|
|
- zPathname = sqlite3DbMallocRaw(0, nPathname*2);
|
|
+ nPathname = pVfs->mxPathname + 1;
|
|
+ zPathname = sqlite3DbMallocRaw(0, 2*(i64)nPathname);
|
|
if( zPathname==0 ){
|
|
return SQLITE_NOMEM_BKPT;
|
|
}
|
|
@@ -62173,14 +62910,14 @@
|
|
ROUND8(sizeof(*pPager)) + /* Pager structure */
|
|
ROUND8(pcacheSize) + /* PCache object */
|
|
ROUND8(pVfs->szOsFile) + /* The main db file */
|
|
- journalFileSize * 2 + /* The two journal files */
|
|
+ (u64)journalFileSize * 2 + /* The two journal files */
|
|
SQLITE_PTRSIZE + /* Space to hold a pointer */
|
|
4 + /* Database prefix */
|
|
- nPathname + 1 + /* database filename */
|
|
- nUriByte + /* query parameters */
|
|
- nPathname + 8 + 1 + /* Journal filename */
|
|
+ (u64)nPathname + 1 + /* database filename */
|
|
+ (u64)nUriByte + /* query parameters */
|
|
+ (u64)nPathname + 8 + 1 + /* Journal filename */
|
|
#ifndef SQLITE_OMIT_WAL
|
|
- nPathname + 4 + 1 + /* WAL filename */
|
|
+ (u64)nPathname + 4 + 1 + /* WAL filename */
|
|
#endif
|
|
3 /* Terminator */
|
|
);
|
|
@@ -64903,6 +65640,11 @@
|
|
pPager->fd, pPager->zWal, pPager->exclusiveMode,
|
|
pPager->journalSizeLimit, &pPager->pWal
|
|
);
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ if( rc==SQLITE_OK ){
|
|
+ sqlite3WalDb(pPager->pWal, pPager->dbWal);
|
|
+ }
|
|
+#endif
|
|
}
|
|
pagerFixMaplimit(pPager);
|
|
|
|
@@ -65022,6 +65764,7 @@
|
|
** blocking locks are required.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3PagerWalDb(Pager *pPager, sqlite3 *db){
|
|
+ pPager->dbWal = db;
|
|
if( pagerUseWal(pPager) ){
|
|
sqlite3WalDb(pPager->pWal, db);
|
|
}
|
|
@@ -65635,6 +66378,11 @@
|
|
/*
|
|
** An open write-ahead log file is represented by an instance of the
|
|
** following object.
|
|
+**
|
|
+** writeLock:
|
|
+** This is usually set to 1 whenever the WRITER lock is held. However,
|
|
+** if it is set to 2, then the WRITER lock is held but must be released
|
|
+** by walHandleException() if a SEH exception is thrown.
|
|
*/
|
|
struct Wal {
|
|
sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */
|
|
@@ -65725,9 +66473,13 @@
|
|
u32 *aPgno; /* Array of page numbers. */
|
|
int nEntry; /* Nr. of entries in aPgno[] and aIndex[] */
|
|
int iZero; /* Frame number associated with aPgno[0] */
|
|
- } aSegment[1]; /* One for every 32KB page in the wal-index */
|
|
+ } aSegment[FLEXARRAY]; /* One for every 32KB page in the wal-index */
|
|
};
|
|
|
|
+/* Size (in bytes) of a WalIterator object suitable for N or fewer segments */
|
|
+#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
|
|
@@ -65886,7 +66638,7 @@
|
|
|
|
/* Enlarge the pWal->apWiData[] array if required */
|
|
if( pWal->nWiData<=iPage ){
|
|
- sqlite3_int64 nByte = sizeof(u32*)*(iPage+1);
|
|
+ sqlite3_int64 nByte = sizeof(u32*)*(1+(i64)iPage);
|
|
volatile u32 **apNew;
|
|
apNew = (volatile u32 **)sqlite3Realloc((void *)pWal->apWiData, nByte);
|
|
if( !apNew ){
|
|
@@ -65995,10 +66747,8 @@
|
|
s1 = s2 = 0;
|
|
}
|
|
|
|
- assert( nByte>=8 );
|
|
- assert( (nByte&0x00000007)==0 );
|
|
- assert( nByte<=65536 );
|
|
- assert( nByte%4==0 );
|
|
+ /* nByte is a multiple of 8 between 8 and 65536 */
|
|
+ assert( nByte>=8 && (nByte&7)==0 && nByte<=65536 );
|
|
|
|
if( !nativeCksum ){
|
|
do {
|
|
@@ -67088,8 +67838,7 @@
|
|
|
|
/* Allocate space for the WalIterator object. */
|
|
nSegment = walFramePage(iLast) + 1;
|
|
- nByte = sizeof(WalIterator)
|
|
- + (nSegment-1)*sizeof(struct WalSegment)
|
|
+ nByte = SZ_WALITERATOR(nSegment)
|
|
+ iLast*sizeof(ht_slot);
|
|
p = (WalIterator *)sqlite3_malloc64(nByte
|
|
+ sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
|
|
@@ -67160,7 +67909,7 @@
|
|
static int walEnableBlocking(Wal *pWal){
|
|
int res = 0;
|
|
if( pWal->db ){
|
|
- int tmout = pWal->db->busyTimeout;
|
|
+ int tmout = pWal->db->setlkTimeout;
|
|
if( tmout ){
|
|
res = walEnableBlockingMs(pWal, tmout);
|
|
}
|
|
@@ -67546,7 +68295,9 @@
|
|
static const int S = 1;
|
|
static const int E = (1<<SQLITE_SHM_NLOCK);
|
|
int ii;
|
|
- u32 mUnlock = pWal->lockMask & ~(
|
|
+ u32 mUnlock;
|
|
+ if( pWal->writeLock==2 ) pWal->writeLock = 0;
|
|
+ mUnlock = pWal->lockMask & ~(
|
|
(pWal->readLock<0 ? 0 : (S << WAL_READ_LOCK(pWal->readLock)))
|
|
| (pWal->writeLock ? (E << WAL_WRITE_LOCK) : 0)
|
|
| (pWal->ckptLock ? (E << WAL_CKPT_LOCK) : 0)
|
|
@@ -67818,7 +68569,12 @@
|
|
if( bWriteLock
|
|
|| SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1))
|
|
){
|
|
- pWal->writeLock = 1;
|
|
+ /* If the write-lock was just obtained, set writeLock to 2 instead of
|
|
+ ** the usual 1. This causes walIndexPage() to behave as if the
|
|
+ ** write-lock were held (so that it allocates new pages as required),
|
|
+ ** and walHandleException() to unlock the write-lock if a SEH exception
|
|
+ ** is thrown. */
|
|
+ if( !bWriteLock ) pWal->writeLock = 2;
|
|
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
|
|
badHdr = walIndexTryHdr(pWal, pChanged);
|
|
if( badHdr ){
|
|
@@ -68182,7 +68938,6 @@
|
|
rc = walIndexReadHdr(pWal, pChanged);
|
|
}
|
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
- walDisableBlocking(pWal);
|
|
if( rc==SQLITE_BUSY_TIMEOUT ){
|
|
rc = SQLITE_BUSY;
|
|
*pCnt |= WAL_RETRY_BLOCKED_MASK;
|
|
@@ -68197,6 +68952,7 @@
|
|
** WAL_RETRY this routine will be called again and will probably be
|
|
** right on the second iteration.
|
|
*/
|
|
+ (void)walEnableBlocking(pWal);
|
|
if( pWal->apWiData[0]==0 ){
|
|
/* This branch is taken when the xShmMap() method returns SQLITE_BUSY.
|
|
** We assume this is a transient condition, so return WAL_RETRY. The
|
|
@@ -68213,6 +68969,7 @@
|
|
rc = SQLITE_BUSY_RECOVERY;
|
|
}
|
|
}
|
|
+ walDisableBlocking(pWal);
|
|
if( rc!=SQLITE_OK ){
|
|
return rc;
|
|
}
|
|
@@ -68603,8 +69360,11 @@
|
|
** read-lock.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){
|
|
- sqlite3WalEndWriteTransaction(pWal);
|
|
+#ifndef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ assert( pWal->writeLock==0 || pWal->readLock<0 );
|
|
+#endif
|
|
if( pWal->readLock>=0 ){
|
|
+ sqlite3WalEndWriteTransaction(pWal);
|
|
walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
|
|
pWal->readLock = -1;
|
|
}
|
|
@@ -68797,7 +69557,7 @@
|
|
** read-transaction was even opened, making this call a no-op.
|
|
** Return early. */
|
|
if( pWal->writeLock ){
|
|
- assert( !memcmp(&pWal->hdr,(void *)walIndexHdr(pWal),sizeof(WalIndexHdr)) );
|
|
+ assert( !memcmp(&pWal->hdr,(void*)pWal->apWiData[0],sizeof(WalIndexHdr)) );
|
|
return SQLITE_OK;
|
|
}
|
|
#endif
|
|
@@ -68897,6 +69657,7 @@
|
|
if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
|
|
}
|
|
SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
|
|
+ pWal->iReCksum = 0;
|
|
}
|
|
return rc;
|
|
}
|
|
@@ -68944,6 +69705,9 @@
|
|
walCleanupHash(pWal);
|
|
}
|
|
SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
|
|
+ if( pWal->iReCksum>pWal->hdr.mxFrame ){
|
|
+ pWal->iReCksum = 0;
|
|
+ }
|
|
}
|
|
|
|
return rc;
|
|
@@ -70247,6 +71011,12 @@
|
|
#define BTCURSOR_MAX_DEPTH 20
|
|
|
|
/*
|
|
+** Maximum amount of storage local to a database page, regardless of
|
|
+** page size.
|
|
+*/
|
|
+#define BT_MAX_LOCAL 65501 /* 65536 - 35 */
|
|
+
|
|
+/*
|
|
** A cursor is a pointer to a particular entry within a particular
|
|
** b-tree within a database file.
|
|
**
|
|
@@ -70654,7 +71424,7 @@
|
|
*/
|
|
static void SQLITE_NOINLINE btreeEnterAll(sqlite3 *db){
|
|
int i;
|
|
- int skipOk = 1;
|
|
+ u8 skipOk = 1;
|
|
Btree *p;
|
|
assert( sqlite3_mutex_held(db->mutex) );
|
|
for(i=0; i<db->nDb; i++){
|
|
@@ -71510,7 +72280,7 @@
|
|
** below. */
|
|
void *pKey;
|
|
pCur->nKey = sqlite3BtreePayloadSize(pCur);
|
|
- pKey = sqlite3Malloc( pCur->nKey + 9 + 8 );
|
|
+ pKey = sqlite3Malloc( ((i64)pCur->nKey) + 9 + 8 );
|
|
if( pKey ){
|
|
rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey);
|
|
if( rc==SQLITE_OK ){
|
|
@@ -71800,7 +72570,7 @@
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor *pCur, unsigned x){
|
|
assert( x==BTREE_SEEK_EQ || x==BTREE_BULKLOAD || x==0 );
|
|
- pCur->hints = x;
|
|
+ pCur->hints = (u8)x;
|
|
}
|
|
|
|
|
|
@@ -71994,14 +72764,15 @@
|
|
static int btreePayloadToLocal(MemPage *pPage, i64 nPayload){
|
|
int maxLocal; /* Maximum amount of payload held locally */
|
|
maxLocal = pPage->maxLocal;
|
|
+ assert( nPayload>=0 );
|
|
if( nPayload<=maxLocal ){
|
|
- return nPayload;
|
|
+ return (int)nPayload;
|
|
}else{
|
|
int minLocal; /* Minimum amount of payload held locally */
|
|
int surplus; /* Overflow payload available for local storage */
|
|
minLocal = pPage->minLocal;
|
|
- surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize-4);
|
|
- return ( surplus <= maxLocal ) ? surplus : minLocal;
|
|
+ surplus = (int)(minLocal +(nPayload - minLocal)%(pPage->pBt->usableSize-4));
|
|
+ return (surplus <= maxLocal) ? surplus : minLocal;
|
|
}
|
|
}
|
|
|
|
@@ -72111,11 +72882,13 @@
|
|
pInfo->pPayload = pIter;
|
|
testcase( nPayload==pPage->maxLocal );
|
|
testcase( nPayload==(u32)pPage->maxLocal+1 );
|
|
+ assert( nPayload>=0 );
|
|
+ assert( pPage->maxLocal <= BT_MAX_LOCAL );
|
|
if( nPayload<=pPage->maxLocal ){
|
|
/* This is the (easy) common case where the entire payload fits
|
|
** on the local page. No overflow is required.
|
|
*/
|
|
- pInfo->nSize = nPayload + (u16)(pIter - pCell);
|
|
+ pInfo->nSize = (u16)nPayload + (u16)(pIter - pCell);
|
|
if( pInfo->nSize<4 ) pInfo->nSize = 4;
|
|
pInfo->nLocal = (u16)nPayload;
|
|
}else{
|
|
@@ -72148,11 +72921,13 @@
|
|
pInfo->pPayload = pIter;
|
|
testcase( nPayload==pPage->maxLocal );
|
|
testcase( nPayload==(u32)pPage->maxLocal+1 );
|
|
+ assert( nPayload>=0 );
|
|
+ assert( pPage->maxLocal <= BT_MAX_LOCAL );
|
|
if( nPayload<=pPage->maxLocal ){
|
|
/* This is the (easy) common case where the entire payload fits
|
|
** on the local page. No overflow is required.
|
|
*/
|
|
- pInfo->nSize = nPayload + (u16)(pIter - pCell);
|
|
+ pInfo->nSize = (u16)nPayload + (u16)(pIter - pCell);
|
|
if( pInfo->nSize<4 ) pInfo->nSize = 4;
|
|
pInfo->nLocal = (u16)nPayload;
|
|
}else{
|
|
@@ -72691,14 +73466,14 @@
|
|
** at the end of the page. So do additional corruption checks inside this
|
|
** routine and return SQLITE_CORRUPT if any problems are found.
|
|
*/
|
|
-static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
|
- u16 iPtr; /* Address of ptr to next freeblock */
|
|
- u16 iFreeBlk; /* Address of the next freeblock */
|
|
+static int freeSpace(MemPage *pPage, int iStart, int iSize){
|
|
+ int iPtr; /* Address of ptr to next freeblock */
|
|
+ int iFreeBlk; /* Address of the next freeblock */
|
|
u8 hdr; /* Page header size. 0 or 100 */
|
|
- u8 nFrag = 0; /* Reduction in fragmentation */
|
|
- u16 iOrigSize = iSize; /* Original value of iSize */
|
|
- u16 x; /* Offset to cell content area */
|
|
- u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */
|
|
+ int nFrag = 0; /* Reduction in fragmentation */
|
|
+ int iOrigSize = iSize; /* Original value of iSize */
|
|
+ int x; /* Offset to cell content area */
|
|
+ int iEnd = iStart + iSize; /* First byte past the iStart buffer */
|
|
unsigned char *data = pPage->aData; /* Page content */
|
|
u8 *pTmp; /* Temporary ptr into data[] */
|
|
|
|
@@ -72725,7 +73500,7 @@
|
|
}
|
|
iPtr = iFreeBlk;
|
|
}
|
|
- if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */
|
|
+ if( iFreeBlk>(int)pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */
|
|
return SQLITE_CORRUPT_PAGE(pPage);
|
|
}
|
|
assert( iFreeBlk>iPtr || iFreeBlk==0 || CORRUPT_DB );
|
|
@@ -72740,7 +73515,7 @@
|
|
nFrag = iFreeBlk - iEnd;
|
|
if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage);
|
|
iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
|
|
- if( iEnd > pPage->pBt->usableSize ){
|
|
+ if( iEnd > (int)pPage->pBt->usableSize ){
|
|
return SQLITE_CORRUPT_PAGE(pPage);
|
|
}
|
|
iSize = iEnd - iStart;
|
|
@@ -72761,7 +73536,7 @@
|
|
}
|
|
}
|
|
if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage);
|
|
- data[hdr+7] -= nFrag;
|
|
+ data[hdr+7] -= (u8)nFrag;
|
|
}
|
|
pTmp = &data[hdr+5];
|
|
x = get2byte(pTmp);
|
|
@@ -72782,7 +73557,8 @@
|
|
/* Insert the new freeblock into the freelist */
|
|
put2byte(&data[iPtr], iStart);
|
|
put2byte(&data[iStart], iFreeBlk);
|
|
- put2byte(&data[iStart+2], iSize);
|
|
+ assert( iSize>=0 && iSize<=0xffff );
|
|
+ put2byte(&data[iStart+2], (u16)iSize);
|
|
}
|
|
pPage->nFree += iOrigSize;
|
|
return SQLITE_OK;
|
|
@@ -73008,7 +73784,7 @@
|
|
assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
|
|
pPage->maskPage = (u16)(pBt->pageSize - 1);
|
|
pPage->nOverflow = 0;
|
|
- pPage->cellOffset = pPage->hdrOffset + 8 + pPage->childPtrSize;
|
|
+ pPage->cellOffset = (u16)(pPage->hdrOffset + 8 + pPage->childPtrSize);
|
|
pPage->aCellIdx = data + pPage->childPtrSize + 8;
|
|
pPage->aDataEnd = pPage->aData + pBt->pageSize;
|
|
pPage->aDataOfst = pPage->aData + pPage->childPtrSize;
|
|
@@ -73042,8 +73818,8 @@
|
|
static void zeroPage(MemPage *pPage, int flags){
|
|
unsigned char *data = pPage->aData;
|
|
BtShared *pBt = pPage->pBt;
|
|
- u8 hdr = pPage->hdrOffset;
|
|
- u16 first;
|
|
+ int hdr = pPage->hdrOffset;
|
|
+ int first;
|
|
|
|
assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno || CORRUPT_DB );
|
|
assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage );
|
|
@@ -73060,7 +73836,7 @@
|
|
put2byte(&data[hdr+5], pBt->usableSize);
|
|
pPage->nFree = (u16)(pBt->usableSize - first);
|
|
decodeFlags(pPage, flags);
|
|
- pPage->cellOffset = first;
|
|
+ pPage->cellOffset = (u16)first;
|
|
pPage->aDataEnd = &data[pBt->pageSize];
|
|
pPage->aCellIdx = &data[first];
|
|
pPage->aDataOfst = &data[pPage->childPtrSize];
|
|
@@ -73846,7 +74622,7 @@
|
|
BtShared *pBt = p->pBt;
|
|
assert( nReserve>=0 && nReserve<=255 );
|
|
sqlite3BtreeEnter(p);
|
|
- pBt->nReserveWanted = nReserve;
|
|
+ pBt->nReserveWanted = (u8)nReserve;
|
|
x = pBt->pageSize - pBt->usableSize;
|
|
if( nReserve<x ) nReserve = x;
|
|
if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
|
|
@@ -73952,7 +74728,7 @@
|
|
assert( BTS_FAST_SECURE==(BTS_OVERWRITE|BTS_SECURE_DELETE) );
|
|
if( newFlag>=0 ){
|
|
p->pBt->btsFlags &= ~BTS_FAST_SECURE;
|
|
- p->pBt->btsFlags |= BTS_SECURE_DELETE*newFlag;
|
|
+ p->pBt->btsFlags |= (u16)(BTS_SECURE_DELETE*newFlag);
|
|
}
|
|
b = (p->pBt->btsFlags & BTS_FAST_SECURE)/BTS_SECURE_DELETE;
|
|
sqlite3BtreeLeave(p);
|
|
@@ -74472,6 +75248,13 @@
|
|
(void)sqlite3PagerWalWriteLock(pPager, 0);
|
|
unlockBtreeIfUnused(pBt);
|
|
}
|
|
+#if defined(SQLITE_ENABLE_SETLK_TIMEOUT)
|
|
+ if( rc==SQLITE_BUSY_TIMEOUT ){
|
|
+ /* If a blocking lock timed out, break out of the loop here so that
|
|
+ ** the busy-handler is not invoked. */
|
|
+ break;
|
|
+ }
|
|
+#endif
|
|
}while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
|
|
btreeInvokeBusyHandler(pBt) );
|
|
sqlite3PagerWalDb(pPager, 0);
|
|
@@ -76881,7 +77664,7 @@
|
|
rc = SQLITE_CORRUPT_PAGE(pPage);
|
|
goto moveto_index_finish;
|
|
}
|
|
- pCellKey = sqlite3Malloc( nCell+nOverrun );
|
|
+ pCellKey = sqlite3Malloc( (u64)nCell+(u64)nOverrun );
|
|
if( pCellKey==0 ){
|
|
rc = SQLITE_NOMEM_BKPT;
|
|
goto moveto_index_finish;
|
|
@@ -78400,7 +79183,8 @@
|
|
}
|
|
|
|
/* The pPg->nFree field is now set incorrectly. The caller will fix it. */
|
|
- pPg->nCell = nCell;
|
|
+ assert( nCell < 10922 );
|
|
+ pPg->nCell = (u16)nCell;
|
|
pPg->nOverflow = 0;
|
|
|
|
put2byte(&aData[hdr+1], 0);
|
|
@@ -78647,9 +79431,13 @@
|
|
if( pageInsertArray(
|
|
pPg, pBegin, &pData, pCellptr,
|
|
iNew+nCell, nNew-nCell, pCArray
|
|
- ) ) goto editpage_fail;
|
|
+ )
|
|
+ ){
|
|
+ goto editpage_fail;
|
|
+ }
|
|
|
|
- pPg->nCell = nNew;
|
|
+ assert( nNew < 10922 );
|
|
+ pPg->nCell = (u16)nNew;
|
|
pPg->nOverflow = 0;
|
|
|
|
put2byte(&aData[hdr+3], pPg->nCell);
|
|
@@ -78958,7 +79746,7 @@
|
|
int pageFlags; /* Value of pPage->aData[0] */
|
|
int iSpace1 = 0; /* First unused byte of aSpace1[] */
|
|
int iOvflSpace = 0; /* First unused byte of aOvflSpace[] */
|
|
- int szScratch; /* Size of scratch memory requested */
|
|
+ u64 szScratch; /* Size of scratch memory requested */
|
|
MemPage *apOld[NB]; /* pPage and up to two siblings */
|
|
MemPage *apNew[NB+2]; /* pPage and up to NB siblings after balancing */
|
|
u8 *pRight; /* Location in parent of right-sibling pointer */
|
|
@@ -80243,7 +81031,7 @@
|
|
if( pCur->info.nKey==pX->nKey ){
|
|
BtreePayload x2;
|
|
x2.pData = pX->pKey;
|
|
- x2.nData = pX->nKey;
|
|
+ x2.nData = (int)pX->nKey; assert( pX->nKey<=0x7fffffff );
|
|
x2.nZero = 0;
|
|
return btreeOverwriteCell(pCur, &x2);
|
|
}
|
|
@@ -80424,7 +81212,7 @@
|
|
|
|
getCellInfo(pSrc);
|
|
if( pSrc->info.nPayload<0x80 ){
|
|
- *(aOut++) = pSrc->info.nPayload;
|
|
+ *(aOut++) = (u8)pSrc->info.nPayload;
|
|
}else{
|
|
aOut += sqlite3PutVarint(aOut, pSrc->info.nPayload);
|
|
}
|
|
@@ -80437,7 +81225,7 @@
|
|
nRem = pSrc->info.nPayload;
|
|
if( nIn==nRem && nIn<pDest->pPage->maxLocal ){
|
|
memcpy(aOut, aIn, nIn);
|
|
- pBt->nPreformatSize = nIn + (aOut - pBt->pTmpSpace);
|
|
+ pBt->nPreformatSize = nIn + (int)(aOut - pBt->pTmpSpace);
|
|
return SQLITE_OK;
|
|
}else{
|
|
int rc = SQLITE_OK;
|
|
@@ -80449,7 +81237,7 @@
|
|
u32 nOut; /* Size of output buffer aOut[] */
|
|
|
|
nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload);
|
|
- pBt->nPreformatSize = nOut + (aOut - pBt->pTmpSpace);
|
|
+ pBt->nPreformatSize = (int)nOut + (int)(aOut - pBt->pTmpSpace);
|
|
if( nOut<pSrc->info.nPayload ){
|
|
pPgnoOut = &aOut[nOut];
|
|
pBt->nPreformatSize += 4;
|
|
@@ -82070,6 +82858,7 @@
|
|
*/
|
|
SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){
|
|
BtShared *pBt = p->pBt;
|
|
+ assert( nBytes==0 || nBytes==sizeof(Schema) );
|
|
sqlite3BtreeEnter(p);
|
|
if( !pBt->pSchema && nBytes ){
|
|
pBt->pSchema = sqlite3DbMallocZero(0, nBytes);
|
|
@@ -83186,7 +83975,7 @@
|
|
** corresponding string value, then it is important that the string be
|
|
** derived from the numeric value, not the other way around, to ensure
|
|
** that the index and table are consistent. See ticket
|
|
-** https://www.sqlite.org/src/info/343634942dd54ab (2018-01-31) for
|
|
+** https://sqlite.org/src/info/343634942dd54ab (2018-01-31) for
|
|
** an example.
|
|
**
|
|
** This routine looks at pMem to verify that if it has both a numeric
|
|
@@ -83372,7 +84161,7 @@
|
|
return;
|
|
}
|
|
if( pMem->enc!=SQLITE_UTF8 ) return;
|
|
- if( NEVER(pMem->z==0) ) return;
|
|
+ assert( pMem->z!=0 );
|
|
if( pMem->flags & MEM_Dyn ){
|
|
if( pMem->xDel==sqlite3_free
|
|
&& sqlite3_msize(pMem->z) >= (u64)(pMem->n+1)
|
|
@@ -84485,7 +85274,7 @@
|
|
|
|
if( pRec==0 ){
|
|
Index *pIdx = p->pIdx; /* Index being probed */
|
|
- int nByte; /* Bytes of space to allocate */
|
|
+ i64 nByte; /* Bytes of space to allocate */
|
|
int i; /* Counter variable */
|
|
int nCol = pIdx->nColumn; /* Number of index columns including rowid */
|
|
|
|
@@ -84551,7 +85340,7 @@
|
|
){
|
|
sqlite3_context ctx; /* Context object for function invocation */
|
|
sqlite3_value **apVal = 0; /* Function arguments */
|
|
- int nVal = 0; /* Size of apVal[] array */
|
|
+ int nVal = 0; /* Number of function arguments */
|
|
FuncDef *pFunc = 0; /* Function definition */
|
|
sqlite3_value *pVal = 0; /* New value */
|
|
int rc = SQLITE_OK; /* Return code */
|
|
@@ -85549,12 +86338,10 @@
|
|
int eCallCtx /* Calling context */
|
|
){
|
|
Vdbe *v = pParse->pVdbe;
|
|
- int nByte;
|
|
int addr;
|
|
sqlite3_context *pCtx;
|
|
assert( v );
|
|
- nByte = sizeof(*pCtx) + (nArg-1)*sizeof(sqlite3_value*);
|
|
- pCtx = sqlite3DbMallocRawNN(pParse->db, nByte);
|
|
+ pCtx = sqlite3DbMallocRawNN(pParse->db, SZ_CONTEXT(nArg));
|
|
if( pCtx==0 ){
|
|
assert( pParse->db->mallocFailed );
|
|
freeEphemeralFunction(pParse->db, (FuncDef*)pFunc);
|
|
@@ -85830,7 +86617,7 @@
|
|
}
|
|
|
|
if( pRet->p4type==P4_SUBPROGRAM ){
|
|
- int nByte = (p->nSub+1)*sizeof(SubProgram*);
|
|
+ i64 nByte = (1+(u64)p->nSub)*sizeof(SubProgram*);
|
|
int j;
|
|
for(j=0; j<p->nSub; j++){
|
|
if( p->apSub[j]==pRet->p4.pProgram ) break;
|
|
@@ -85960,8 +86747,8 @@
|
|
** (1) For each jump instruction with a negative P2 value (a label)
|
|
** resolve the P2 value to an actual address.
|
|
**
|
|
-** (2) Compute the maximum number of arguments used by any SQL function
|
|
-** and store that value in *pMaxFuncArgs.
|
|
+** (2) Compute the maximum number of arguments used by the xUpdate/xFilter
|
|
+** methods of any virtual table and store that value in *pMaxVtabArgs.
|
|
**
|
|
** (3) Update the Vdbe.readOnly and Vdbe.bIsReader flags to accurately
|
|
** indicate what the prepared statement actually does.
|
|
@@ -85974,8 +86761,8 @@
|
|
** script numbers the opcodes correctly. Changes to this routine must be
|
|
** coordinated with changes to mkopcodeh.tcl.
|
|
*/
|
|
-static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
|
- int nMaxArgs = *pMaxFuncArgs;
|
|
+static void resolveP2Values(Vdbe *p, int *pMaxVtabArgs){
|
|
+ int nMaxVtabArgs = *pMaxVtabArgs;
|
|
Op *pOp;
|
|
Parse *pParse = p->pParse;
|
|
int *aLabel = pParse->aLabel;
|
|
@@ -86020,15 +86807,19 @@
|
|
}
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
case OP_VUpdate: {
|
|
- if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
|
|
+ if( pOp->p2>nMaxVtabArgs ) nMaxVtabArgs = pOp->p2;
|
|
break;
|
|
}
|
|
case OP_VFilter: {
|
|
int n;
|
|
+ /* The instruction immediately prior to VFilter will be an
|
|
+ ** OP_Integer that sets the "argc" value for the VFilter. See
|
|
+ ** the code where OP_VFilter is generated at tag-20250207a. */
|
|
assert( (pOp - p->aOp) >= 3 );
|
|
assert( pOp[-1].opcode==OP_Integer );
|
|
+ assert( pOp[-1].p2==pOp->p3+1 );
|
|
n = pOp[-1].p1;
|
|
- if( n>nMaxArgs ) nMaxArgs = n;
|
|
+ if( n>nMaxVtabArgs ) nMaxVtabArgs = n;
|
|
/* Fall through into the default case */
|
|
/* no break */ deliberate_fall_through
|
|
}
|
|
@@ -86069,7 +86860,7 @@
|
|
pParse->aLabel = 0;
|
|
}
|
|
pParse->nLabel = 0;
|
|
- *pMaxFuncArgs = nMaxArgs;
|
|
+ *pMaxVtabArgs = nMaxVtabArgs;
|
|
assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) );
|
|
}
|
|
|
|
@@ -86298,7 +87089,7 @@
|
|
const char *zName /* Name of table or index being scanned */
|
|
){
|
|
if( IS_STMT_SCANSTATUS(p->db) ){
|
|
- sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus);
|
|
+ i64 nByte = (1+(i64)p->nScan) * sizeof(ScanStatus);
|
|
ScanStatus *aNew;
|
|
aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte);
|
|
if( aNew ){
|
|
@@ -86408,6 +87199,9 @@
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3VdbeTypeofColumn(Vdbe *p, int iDest){
|
|
VdbeOp *pOp = sqlite3VdbeGetLastOp(p);
|
|
+#ifdef SQLITE_DEBUG
|
|
+ while( pOp->opcode==OP_ReleaseReg ) pOp--;
|
|
+#endif
|
|
if( pOp->p3==iDest && pOp->opcode==OP_Column ){
|
|
pOp->p5 |= OPFLAG_TYPEOFARG;
|
|
}
|
|
@@ -87747,7 +88541,7 @@
|
|
int nVar; /* Number of parameters */
|
|
int nMem; /* Number of VM memory registers */
|
|
int nCursor; /* Number of cursors required */
|
|
- int nArg; /* Number of arguments in subprograms */
|
|
+ int nArg; /* Max number args to xFilter or xUpdate */
|
|
int n; /* Loop counter */
|
|
struct ReusableSpace x; /* Reusable bulk memory */
|
|
|
|
@@ -87819,6 +88613,9 @@
|
|
p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*));
|
|
}
|
|
}
|
|
+#ifdef SQLITE_DEBUG
|
|
+ p->napArg = nArg;
|
|
+#endif
|
|
|
|
if( db->mallocFailed ){
|
|
p->nVar = 0;
|
|
@@ -89316,6 +90113,7 @@
|
|
){
|
|
UnpackedRecord *p; /* Unpacked record to return */
|
|
int nByte; /* Number of bytes required for *p */
|
|
+ assert( sizeof(UnpackedRecord) + sizeof(Mem)*65536 < 0x7fffffff );
|
|
nByte = ROUND8P(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1);
|
|
p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
|
|
if( !p ) return 0;
|
|
@@ -90622,10 +91420,11 @@
|
|
preupdate.pCsr = pCsr;
|
|
preupdate.op = op;
|
|
preupdate.iNewReg = iReg;
|
|
- preupdate.keyinfo.db = db;
|
|
- preupdate.keyinfo.enc = ENC(db);
|
|
- preupdate.keyinfo.nKeyField = pTab->nCol;
|
|
- preupdate.keyinfo.aSortFlags = (u8*)&fakeSortOrder;
|
|
+ preupdate.pKeyinfo = (KeyInfo*)&preupdate.keyinfoSpace;
|
|
+ preupdate.pKeyinfo->db = db;
|
|
+ preupdate.pKeyinfo->enc = ENC(db);
|
|
+ preupdate.pKeyinfo->nKeyField = pTab->nCol;
|
|
+ preupdate.pKeyinfo->aSortFlags = (u8*)&fakeSortOrder;
|
|
preupdate.iKey1 = iKey1;
|
|
preupdate.iKey2 = iKey2;
|
|
preupdate.pTab = pTab;
|
|
@@ -90635,8 +91434,8 @@
|
|
db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
|
|
db->pPreUpdate = 0;
|
|
sqlite3DbFree(db, preupdate.aRecord);
|
|
- vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked);
|
|
- vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked);
|
|
+ vdbeFreeUnpacked(db, preupdate.pKeyinfo->nKeyField+1,preupdate.pUnpacked);
|
|
+ vdbeFreeUnpacked(db, preupdate.pKeyinfo->nKeyField+1,preupdate.pNewUnpacked);
|
|
sqlite3VdbeMemRelease(&preupdate.oldipk);
|
|
if( preupdate.aNew ){
|
|
int i;
|
|
@@ -92467,7 +93266,7 @@
|
|
assert( xDel!=SQLITE_DYNAMIC );
|
|
if( enc!=SQLITE_UTF8 ){
|
|
if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
|
|
- nData &= ~(u16)1;
|
|
+ nData &= ~(u64)1;
|
|
}
|
|
return bindText(pStmt, i, zData, nData, xDel, enc);
|
|
}
|
|
@@ -92875,7 +93674,7 @@
|
|
if( !aRec ) goto preupdate_old_out;
|
|
rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec);
|
|
if( rc==SQLITE_OK ){
|
|
- p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec);
|
|
+ p->pUnpacked = vdbeUnpackRecord(p->pKeyinfo, nRec, aRec);
|
|
if( !p->pUnpacked ) rc = SQLITE_NOMEM;
|
|
}
|
|
if( rc!=SQLITE_OK ){
|
|
@@ -92892,7 +93691,9 @@
|
|
Column *pCol = &p->pTab->aCol[iIdx];
|
|
if( pCol->iDflt>0 ){
|
|
if( p->apDflt==0 ){
|
|
- int nByte = sizeof(sqlite3_value*)*p->pTab->nCol;
|
|
+ int nByte;
|
|
+ assert( sizeof(sqlite3_value*)*UMXV(p->pTab->nCol) < 0x7fffffff );
|
|
+ nByte = sizeof(sqlite3_value*)*p->pTab->nCol;
|
|
p->apDflt = (sqlite3_value**)sqlite3DbMallocZero(db, nByte);
|
|
if( p->apDflt==0 ) goto preupdate_old_out;
|
|
}
|
|
@@ -92938,7 +93739,7 @@
|
|
#else
|
|
p = db->pPreUpdate;
|
|
#endif
|
|
- return (p ? p->keyinfo.nKeyField : 0);
|
|
+ return (p ? p->pKeyinfo->nKeyField : 0);
|
|
}
|
|
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
|
|
|
|
@@ -93021,7 +93822,7 @@
|
|
Mem *pData = &p->v->aMem[p->iNewReg];
|
|
rc = ExpandBlob(pData);
|
|
if( rc!=SQLITE_OK ) goto preupdate_new_out;
|
|
- pUnpack = vdbeUnpackRecord(&p->keyinfo, pData->n, pData->z);
|
|
+ pUnpack = vdbeUnpackRecord(p->pKeyinfo, pData->n, pData->z);
|
|
if( !pUnpack ){
|
|
rc = SQLITE_NOMEM;
|
|
goto preupdate_new_out;
|
|
@@ -93042,7 +93843,8 @@
|
|
*/
|
|
assert( p->op==SQLITE_UPDATE );
|
|
if( !p->aNew ){
|
|
- p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem) * p->pCsr->nField);
|
|
+ assert( sizeof(Mem)*UMXV(p->pCsr->nField) < 0x7fffffff );
|
|
+ p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem)*p->pCsr->nField);
|
|
if( !p->aNew ){
|
|
rc = SQLITE_NOMEM;
|
|
goto preupdate_new_out;
|
|
@@ -93812,11 +94614,11 @@
|
|
*/
|
|
Mem *pMem = iCur>0 ? &p->aMem[p->nMem-iCur] : p->aMem;
|
|
|
|
- int nByte;
|
|
+ i64 nByte;
|
|
VdbeCursor *pCx = 0;
|
|
- nByte =
|
|
- ROUND8P(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
|
|
- (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0);
|
|
+ nByte = SZ_VDBECURSOR(nField);
|
|
+ assert( ROUND8(nByte)==nByte );
|
|
+ if( eCurType==CURTYPE_BTREE ) nByte += sqlite3BtreeCursorSize();
|
|
|
|
assert( iCur>=0 && iCur<p->nCursor );
|
|
if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/
|
|
@@ -93840,7 +94642,7 @@
|
|
pMem->szMalloc = 0;
|
|
return 0;
|
|
}
|
|
- pMem->szMalloc = nByte;
|
|
+ pMem->szMalloc = (int)nByte;
|
|
}
|
|
|
|
p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->zMalloc;
|
|
@@ -93849,8 +94651,8 @@
|
|
pCx->nField = nField;
|
|
pCx->aOffset = &pCx->aType[nField];
|
|
if( eCurType==CURTYPE_BTREE ){
|
|
- pCx->uc.pCursor = (BtCursor*)
|
|
- &pMem->z[ROUND8P(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
|
|
+ assert( ROUND8(SZ_VDBECURSOR(nField))==SZ_VDBECURSOR(nField) );
|
|
+ pCx->uc.pCursor = (BtCursor*)&pMem->z[SZ_VDBECURSOR(nField)];
|
|
sqlite3BtreeCursorZero(pCx->uc.pCursor);
|
|
}
|
|
return pCx;
|
|
@@ -94854,7 +95656,7 @@
|
|
sqlite3VdbeError(p, "%s", pOp->p4.z);
|
|
}
|
|
pcx = (int)(pOp - aOp);
|
|
- sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg);
|
|
+ sqlite3_log(pOp->p1, "abort at %d: %s; [%s]", pcx, p->zErrMsg, p->zSql);
|
|
}
|
|
rc = sqlite3VdbeHalt(p);
|
|
assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR );
|
|
@@ -96180,7 +96982,7 @@
|
|
break;
|
|
}
|
|
|
|
-/* Opcode: Once P1 P2 * * *
|
|
+/* Opcode: Once P1 P2 P3 * *
|
|
**
|
|
** Fall through to the next instruction the first time this opcode is
|
|
** encountered on each invocation of the byte-code program. Jump to P2
|
|
@@ -96196,6 +96998,12 @@
|
|
** whether or not the jump should be taken. The bitmask is necessary
|
|
** because the self-altering code trick does not work for recursive
|
|
** triggers.
|
|
+**
|
|
+** The P3 operand is not used directly by this opcode. However P3 is
|
|
+** used by the code generator as follows: If this opcode is the start
|
|
+** of a subroutine and that subroutine uses a Bloom filter, then P3 will
|
|
+** be the register that holds that Bloom filter. See tag-202407032019
|
|
+** in the source code for implementation details.
|
|
*/
|
|
case OP_Once: { /* jump */
|
|
u32 iAddr; /* Address of this instruction */
|
|
@@ -97241,6 +98049,7 @@
|
|
zHdr += sqlite3PutVarint(zHdr, serial_type);
|
|
if( pRec->n ){
|
|
assert( pRec->z!=0 );
|
|
+ assert( pRec->z!=(const char*)sqlite3CtypeMap );
|
|
memcpy(zPayload, pRec->z, pRec->n);
|
|
zPayload += pRec->n;
|
|
}
|
|
@@ -99592,7 +100401,7 @@
|
|
/* The OP_RowData opcodes always follow OP_NotExists or
|
|
** OP_SeekRowid or OP_Rewind/Op_Next with no intervening instructions
|
|
** that might invalidate the cursor.
|
|
- ** If this where not the case, on of the following assert()s
|
|
+ ** If this were not the case, one of the following assert()s
|
|
** would fail. Should this ever change (because of changes in the code
|
|
** generator) then the fix would be to insert a call to
|
|
** sqlite3VdbeCursorMoveto().
|
|
@@ -100861,7 +101670,7 @@
|
|
*/
|
|
case OP_Program: { /* jump0 */
|
|
int nMem; /* Number of memory registers for sub-program */
|
|
- int nByte; /* Bytes of runtime space required for sub-program */
|
|
+ i64 nByte; /* Bytes of runtime space required for sub-program */
|
|
Mem *pRt; /* Register to allocate runtime space */
|
|
Mem *pMem; /* Used to iterate through memory cells */
|
|
Mem *pEnd; /* Last memory cell in new array */
|
|
@@ -100912,7 +101721,7 @@
|
|
nByte = ROUND8(sizeof(VdbeFrame))
|
|
+ nMem * sizeof(Mem)
|
|
+ pProgram->nCsr * sizeof(VdbeCursor*)
|
|
- + (pProgram->nOp + 7)/8;
|
|
+ + (7 + (i64)pProgram->nOp)/8;
|
|
pFrame = sqlite3DbMallocZero(db, nByte);
|
|
if( !pFrame ){
|
|
goto no_mem;
|
|
@@ -100920,7 +101729,7 @@
|
|
sqlite3VdbeMemRelease(pRt);
|
|
pRt->flags = MEM_Blob|MEM_Dyn;
|
|
pRt->z = (char*)pFrame;
|
|
- pRt->n = nByte;
|
|
+ pRt->n = (int)nByte;
|
|
pRt->xDel = sqlite3VdbeFrameMemDel;
|
|
|
|
pFrame->v = p;
|
|
@@ -101019,12 +101828,14 @@
|
|
** statement counter is incremented (immediate foreign key constraints).
|
|
*/
|
|
case OP_FkCounter: {
|
|
- if( db->flags & SQLITE_DeferFKs ){
|
|
- db->nDeferredImmCons += pOp->p2;
|
|
- }else if( pOp->p1 ){
|
|
+ if( pOp->p1 ){
|
|
db->nDeferredCons += pOp->p2;
|
|
}else{
|
|
- p->nFkConstraint += pOp->p2;
|
|
+ if( db->flags & SQLITE_DeferFKs ){
|
|
+ db->nDeferredImmCons += pOp->p2;
|
|
+ }else{
|
|
+ p->nFkConstraint += pOp->p2;
|
|
+ }
|
|
}
|
|
break;
|
|
}
|
|
@@ -101239,7 +102050,7 @@
|
|
**
|
|
** Note: We could avoid this by using a regular memory cell from aMem[] for
|
|
** the accumulator, instead of allocating one here. */
|
|
- nAlloc = ROUND8P( sizeof(pCtx[0]) + (n-1)*sizeof(sqlite3_value*) );
|
|
+ nAlloc = ROUND8P( SZ_CONTEXT(n) );
|
|
pCtx = sqlite3DbMallocRawNN(db, nAlloc + sizeof(Mem));
|
|
if( pCtx==0 ) goto no_mem;
|
|
pCtx->pOut = (Mem*)((u8*)pCtx + nAlloc);
|
|
@@ -101899,6 +102710,7 @@
|
|
|
|
/* Invoke the xFilter method */
|
|
apArg = p->apArg;
|
|
+ assert( nArg<=p->napArg );
|
|
for(i = 0; i<nArg; i++){
|
|
apArg[i] = &pArgc[i+1];
|
|
}
|
|
@@ -102109,6 +102921,7 @@
|
|
u8 vtabOnConflict = db->vtabOnConflict;
|
|
apArg = p->apArg;
|
|
pX = &aMem[pOp->p3];
|
|
+ assert( nArg<=p->napArg );
|
|
for(i=0; i<nArg; i++){
|
|
assert( memIsValid(pX) );
|
|
memAboutToChange(p, pX);
|
|
@@ -102685,8 +103498,8 @@
|
|
p->rc = rc;
|
|
sqlite3SystemError(db, rc);
|
|
testcase( sqlite3GlobalConfig.xLog!=0 );
|
|
- sqlite3_log(rc, "statement aborts at %d: [%s] %s",
|
|
- (int)(pOp - aOp), p->zSql, p->zErrMsg);
|
|
+ sqlite3_log(rc, "statement aborts at %d: %s; [%s]",
|
|
+ (int)(pOp - aOp), p->zErrMsg, p->zSql);
|
|
if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p);
|
|
if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db);
|
|
if( rc==SQLITE_CORRUPT && db->autoCommit==0 ){
|
|
@@ -102895,6 +103708,7 @@
|
|
char *zErr = 0;
|
|
Table *pTab;
|
|
Incrblob *pBlob = 0;
|
|
+ int iDb;
|
|
Parse sParse;
|
|
|
|
#ifdef SQLITE_ENABLE_API_ARMOR
|
|
@@ -102940,7 +103754,10 @@
|
|
sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable);
|
|
}
|
|
#endif
|
|
- if( !pTab ){
|
|
+ if( pTab==0
|
|
+ || ((iDb = sqlite3SchemaToIndex(db, pTab->pSchema))==1 &&
|
|
+ sqlite3OpenTempDatabase(&sParse))
|
|
+ ){
|
|
if( sParse.zErrMsg ){
|
|
sqlite3DbFree(db, zErr);
|
|
zErr = sParse.zErrMsg;
|
|
@@ -102951,15 +103768,11 @@
|
|
goto blob_open_out;
|
|
}
|
|
pBlob->pTab = pTab;
|
|
- pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName;
|
|
+ pBlob->zDb = db->aDb[iDb].zDbSName;
|
|
|
|
/* Now search pTab for the exact column. */
|
|
- for(iCol=0; iCol<pTab->nCol; iCol++) {
|
|
- if( sqlite3StrICmp(pTab->aCol[iCol].zCnName, zColumn)==0 ){
|
|
- break;
|
|
- }
|
|
- }
|
|
- if( iCol==pTab->nCol ){
|
|
+ iCol = sqlite3ColumnIndex(pTab, zColumn);
|
|
+ if( iCol<0 ){
|
|
sqlite3DbFree(db, zErr);
|
|
zErr = sqlite3MPrintf(db, "no such column: \"%s\"", zColumn);
|
|
rc = SQLITE_ERROR;
|
|
@@ -103039,7 +103852,6 @@
|
|
{OP_Halt, 0, 0, 0}, /* 5 */
|
|
};
|
|
Vdbe *v = (Vdbe *)pBlob->pStmt;
|
|
- int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
VdbeOp *aOp;
|
|
|
|
sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag,
|
|
@@ -103617,9 +104429,12 @@
|
|
u8 iPrev; /* Previous thread used to flush PMA */
|
|
u8 nTask; /* Size of aTask[] array */
|
|
u8 typeMask;
|
|
- SortSubtask aTask[1]; /* One or more subtasks */
|
|
+ SortSubtask aTask[FLEXARRAY]; /* One or more subtasks */
|
|
};
|
|
|
|
+/* Size (in bytes) of a VdbeSorter object that works with N or fewer subtasks */
|
|
+#define SZ_VDBESORTER(N) (offsetof(VdbeSorter,aTask)+(N)*sizeof(SortSubtask))
|
|
+
|
|
#define SORTER_TYPE_INTEGER 0x01
|
|
#define SORTER_TYPE_TEXT 0x02
|
|
|
|
@@ -104221,7 +105036,7 @@
|
|
VdbeSorter *pSorter; /* The new sorter */
|
|
KeyInfo *pKeyInfo; /* Copy of pCsr->pKeyInfo with db==0 */
|
|
int szKeyInfo; /* Size of pCsr->pKeyInfo in bytes */
|
|
- int sz; /* Size of pSorter in bytes */
|
|
+ i64 sz; /* Size of pSorter in bytes */
|
|
int rc = SQLITE_OK;
|
|
#if SQLITE_MAX_WORKER_THREADS==0
|
|
# define nWorker 0
|
|
@@ -104249,8 +105064,10 @@
|
|
assert( pCsr->pKeyInfo );
|
|
assert( !pCsr->isEphemeral );
|
|
assert( pCsr->eCurType==CURTYPE_SORTER );
|
|
- szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*);
|
|
- sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask);
|
|
+ assert( sizeof(KeyInfo) + UMXV(pCsr->pKeyInfo->nKeyField)*sizeof(CollSeq*)
|
|
+ < 0x7fffffff );
|
|
+ szKeyInfo = SZ_KEYINFO(pCsr->pKeyInfo->nKeyField);
|
|
+ sz = SZ_VDBESORTER(nWorker+1);
|
|
|
|
pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo);
|
|
pCsr->uc.pSorter = pSorter;
|
|
@@ -104462,7 +105279,7 @@
|
|
*/
|
|
static MergeEngine *vdbeMergeEngineNew(int nReader){
|
|
int N = 2; /* Smallest power of two >= nReader */
|
|
- int nByte; /* Total bytes of space to allocate */
|
|
+ i64 nByte; /* Total bytes of space to allocate */
|
|
MergeEngine *pNew; /* Pointer to allocated object to return */
|
|
|
|
assert( nReader<=SORTER_MAX_MERGE_COUNT );
|
|
@@ -104714,6 +105531,10 @@
|
|
p->u.pNext = 0;
|
|
for(i=0; aSlot[i]; i++){
|
|
p = vdbeSorterMerge(pTask, p, aSlot[i]);
|
|
+ /* ,--Each aSlot[] holds twice as much as the previous. So we cannot use
|
|
+ ** | up all 64 aSlots[] with only a 64-bit address space.
|
|
+ ** v */
|
|
+ assert( i<ArraySize(aSlot) );
|
|
aSlot[i] = 0;
|
|
}
|
|
aSlot[i] = p;
|
|
@@ -107505,7 +108326,6 @@
|
|
Schema *pSchema = 0; /* Schema of the expression */
|
|
int eNewExprOp = TK_COLUMN; /* New value for pExpr->op on success */
|
|
Table *pTab = 0; /* Table holding the row */
|
|
- Column *pCol; /* A column of pTab */
|
|
ExprList *pFJMatch = 0; /* Matches for FULL JOIN .. USING */
|
|
const char *zCol = pRight->u.zToken;
|
|
|
|
@@ -107556,7 +108376,6 @@
|
|
|
|
if( pSrcList ){
|
|
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
|
|
- u8 hCol;
|
|
pTab = pItem->pSTab;
|
|
assert( pTab!=0 && pTab->zName!=0 );
|
|
assert( pTab->nCol>0 || pParse->nErr );
|
|
@@ -107644,43 +108463,38 @@
|
|
sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab);
|
|
}
|
|
}
|
|
- hCol = sqlite3StrIHash(zCol);
|
|
- for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
|
|
- if( pCol->hName==hCol
|
|
- && sqlite3StrICmp(pCol->zCnName, zCol)==0
|
|
- ){
|
|
- if( cnt>0 ){
|
|
- if( pItem->fg.isUsing==0
|
|
- || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
|
|
- ){
|
|
- /* Two or more tables have the same column name which is
|
|
- ** not joined by USING. This is an error. Signal as much
|
|
- ** by clearing pFJMatch and letting cnt go above 1. */
|
|
- sqlite3ExprListDelete(db, pFJMatch);
|
|
- pFJMatch = 0;
|
|
- }else
|
|
- if( (pItem->fg.jointype & JT_RIGHT)==0 ){
|
|
- /* An INNER or LEFT JOIN. Use the left-most table */
|
|
- continue;
|
|
- }else
|
|
- if( (pItem->fg.jointype & JT_LEFT)==0 ){
|
|
- /* A RIGHT JOIN. Use the right-most table */
|
|
- cnt = 0;
|
|
- sqlite3ExprListDelete(db, pFJMatch);
|
|
- pFJMatch = 0;
|
|
- }else{
|
|
- /* For a FULL JOIN, we must construct a coalesce() func */
|
|
- extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
|
|
- }
|
|
- }
|
|
- cnt++;
|
|
- pMatch = pItem;
|
|
- /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
|
|
- pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
|
|
- if( pItem->fg.isNestedFrom ){
|
|
- sqlite3SrcItemColumnUsed(pItem, j);
|
|
+ j = sqlite3ColumnIndex(pTab, zCol);
|
|
+ if( j>=0 ){
|
|
+ if( cnt>0 ){
|
|
+ if( pItem->fg.isUsing==0
|
|
+ || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
|
|
+ ){
|
|
+ /* Two or more tables have the same column name which is
|
|
+ ** not joined by USING. This is an error. Signal as much
|
|
+ ** by clearing pFJMatch and letting cnt go above 1. */
|
|
+ sqlite3ExprListDelete(db, pFJMatch);
|
|
+ pFJMatch = 0;
|
|
+ }else
|
|
+ if( (pItem->fg.jointype & JT_RIGHT)==0 ){
|
|
+ /* An INNER or LEFT JOIN. Use the left-most table */
|
|
+ continue;
|
|
+ }else
|
|
+ if( (pItem->fg.jointype & JT_LEFT)==0 ){
|
|
+ /* A RIGHT JOIN. Use the right-most table */
|
|
+ cnt = 0;
|
|
+ sqlite3ExprListDelete(db, pFJMatch);
|
|
+ pFJMatch = 0;
|
|
+ }else{
|
|
+ /* For a FULL JOIN, we must construct a coalesce() func */
|
|
+ extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
|
|
}
|
|
- break;
|
|
+ }
|
|
+ cnt++;
|
|
+ pMatch = pItem;
|
|
+ /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
|
|
+ pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
|
|
+ if( pItem->fg.isNestedFrom ){
|
|
+ sqlite3SrcItemColumnUsed(pItem, j);
|
|
}
|
|
}
|
|
if( 0==cnt && VisibleRowid(pTab) ){
|
|
@@ -107770,23 +108584,18 @@
|
|
|
|
if( pTab ){
|
|
int iCol;
|
|
- u8 hCol = sqlite3StrIHash(zCol);
|
|
pSchema = pTab->pSchema;
|
|
cntTab++;
|
|
- for(iCol=0, pCol=pTab->aCol; iCol<pTab->nCol; iCol++, pCol++){
|
|
- if( pCol->hName==hCol
|
|
- && sqlite3StrICmp(pCol->zCnName, zCol)==0
|
|
- ){
|
|
- if( iCol==pTab->iPKey ){
|
|
- iCol = -1;
|
|
- }
|
|
- break;
|
|
+ iCol = sqlite3ColumnIndex(pTab, zCol);
|
|
+ if( iCol>=0 ){
|
|
+ if( pTab->iPKey==iCol ) iCol = -1;
|
|
+ }else{
|
|
+ if( sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){
|
|
+ iCol = -1;
|
|
+ }else{
|
|
+ iCol = pTab->nCol;
|
|
}
|
|
}
|
|
- if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){
|
|
- /* IMP: R-51414-32910 */
|
|
- iCol = -1;
|
|
- }
|
|
if( iCol<pTab->nCol ){
|
|
cnt++;
|
|
pMatch = 0;
|
|
@@ -108425,13 +109234,12 @@
|
|
** sqlite_version() that might change over time cannot be used
|
|
** in an index or generated column. Curiously, they can be used
|
|
** in a CHECK constraint. SQLServer, MySQL, and PostgreSQL all
|
|
- ** all this. */
|
|
+ ** allow this. */
|
|
sqlite3ResolveNotValid(pParse, pNC, "non-deterministic functions",
|
|
NC_IdxExpr|NC_PartIdx|NC_GenCol, 0, pExpr);
|
|
}else{
|
|
assert( (NC_SelfRef & 0xff)==NC_SelfRef ); /* Must fit in 8 bits */
|
|
pExpr->op2 = pNC->ncFlags & NC_SelfRef;
|
|
- if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL);
|
|
}
|
|
if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0
|
|
&& pParse->nested==0
|
|
@@ -108447,6 +109255,7 @@
|
|
if( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0
|
|
&& !IN_RENAME_OBJECT
|
|
){
|
|
+ if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL);
|
|
sqlite3ExprFunctionUsable(pParse, pExpr, pDef);
|
|
}
|
|
}
|
|
@@ -109500,20 +110309,22 @@
|
|
Expr *pExpr, /* Expression to resolve. May be NULL. */
|
|
ExprList *pList /* Expression list to resolve. May be NULL. */
|
|
){
|
|
- SrcList sSrc; /* Fake SrcList for pParse->pNewTable */
|
|
+ SrcList *pSrc; /* Fake SrcList for pParse->pNewTable */
|
|
NameContext sNC; /* Name context for pParse->pNewTable */
|
|
int rc;
|
|
+ u8 srcSpace[SZ_SRCLIST_1]; /* Memory space for the fake SrcList */
|
|
|
|
assert( type==0 || pTab!=0 );
|
|
assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr
|
|
|| type==NC_GenCol || pTab==0 );
|
|
memset(&sNC, 0, sizeof(sNC));
|
|
- memset(&sSrc, 0, sizeof(sSrc));
|
|
+ pSrc = (SrcList*)srcSpace;
|
|
+ memset(pSrc, 0, SZ_SRCLIST_1);
|
|
if( pTab ){
|
|
- sSrc.nSrc = 1;
|
|
- sSrc.a[0].zName = pTab->zName;
|
|
- sSrc.a[0].pSTab = pTab;
|
|
- sSrc.a[0].iCursor = -1;
|
|
+ pSrc->nSrc = 1;
|
|
+ pSrc->a[0].zName = pTab->zName;
|
|
+ pSrc->a[0].pSTab = pTab;
|
|
+ pSrc->a[0].iCursor = -1;
|
|
if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){
|
|
/* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP
|
|
** schema elements */
|
|
@@ -109521,7 +110332,7 @@
|
|
}
|
|
}
|
|
sNC.pParse = pParse;
|
|
- sNC.pSrcList = &sSrc;
|
|
+ sNC.pSrcList = pSrc;
|
|
sNC.ncFlags = type | NC_IsDDL;
|
|
if( (rc = sqlite3ResolveExprNames(&sNC, pExpr))!=SQLITE_OK ) return rc;
|
|
if( pList ) rc = sqlite3ResolveExprListNames(&sNC, pList);
|
|
@@ -109605,7 +110416,9 @@
|
|
pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
|
|
);
|
|
}
|
|
- if( op==TK_VECTOR ){
|
|
+ if( op==TK_VECTOR
|
|
+ || (op==TK_FUNCTION && pExpr->affExpr==SQLITE_AFF_DEFER)
|
|
+ ){
|
|
assert( ExprUseXList(pExpr) );
|
|
return sqlite3ExprAffinity(pExpr->x.pList->a[0].pExpr);
|
|
}
|
|
@@ -109798,7 +110611,9 @@
|
|
p = p->pLeft;
|
|
continue;
|
|
}
|
|
- if( op==TK_VECTOR ){
|
|
+ if( op==TK_VECTOR
|
|
+ || (op==TK_FUNCTION && p->affExpr==SQLITE_AFF_DEFER)
|
|
+ ){
|
|
assert( ExprUseXList(p) );
|
|
p = p->x.pList->a[0].pExpr;
|
|
continue;
|
|
@@ -110672,7 +111487,7 @@
|
|
return pLeft;
|
|
}else{
|
|
u32 f = pLeft->flags | pRight->flags;
|
|
- if( (f&(EP_OuterON|EP_InnerON|EP_IsFalse))==EP_IsFalse
|
|
+ if( (f&(EP_OuterON|EP_InnerON|EP_IsFalse|EP_HasFunc))==EP_IsFalse
|
|
&& !IN_RENAME_OBJECT
|
|
){
|
|
sqlite3ExprDeferredDelete(pParse, pLeft);
|
|
@@ -111270,7 +112085,7 @@
|
|
SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p){
|
|
With *pRet = 0;
|
|
if( p ){
|
|
- sqlite3_int64 nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1);
|
|
+ sqlite3_int64 nByte = SZ_WITH(p->nCte);
|
|
pRet = sqlite3DbMallocZero(db, nByte);
|
|
if( pRet ){
|
|
int i;
|
|
@@ -111381,7 +112196,6 @@
|
|
}
|
|
pItem->zEName = sqlite3DbStrDup(db, pOldItem->zEName);
|
|
pItem->fg = pOldItem->fg;
|
|
- pItem->fg.done = 0;
|
|
pItem->u = pOldItem->u;
|
|
}
|
|
return pNew;
|
|
@@ -111398,11 +112212,9 @@
|
|
SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){
|
|
SrcList *pNew;
|
|
int i;
|
|
- int nByte;
|
|
assert( db!=0 );
|
|
if( p==0 ) return 0;
|
|
- nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0);
|
|
- pNew = sqlite3DbMallocRawNN(db, nByte );
|
|
+ pNew = sqlite3DbMallocRawNN(db, SZ_SRCLIST(p->nSrc) );
|
|
if( pNew==0 ) return 0;
|
|
pNew->nSrc = pNew->nAlloc = p->nSrc;
|
|
for(i=0; i<p->nSrc; i++){
|
|
@@ -111464,7 +112276,7 @@
|
|
int i;
|
|
assert( db!=0 );
|
|
if( p==0 ) return 0;
|
|
- pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew)+(p->nId-1)*sizeof(p->a[0]) );
|
|
+ pNew = sqlite3DbMallocRawNN(db, SZ_IDLIST(p->nId));
|
|
if( pNew==0 ) return 0;
|
|
pNew->nId = p->nId;
|
|
for(i=0; i<p->nId; i++){
|
|
@@ -111496,7 +112308,7 @@
|
|
pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
|
|
pNew->iLimit = 0;
|
|
pNew->iOffset = 0;
|
|
- pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
|
|
+ pNew->selFlags = p->selFlags & ~(u32)SF_UsesEphemeral;
|
|
pNew->addrOpenEphm[0] = -1;
|
|
pNew->addrOpenEphm[1] = -1;
|
|
pNew->nSelectRow = p->nSelectRow;
|
|
@@ -111548,7 +112360,7 @@
|
|
struct ExprList_item *pItem;
|
|
ExprList *pList;
|
|
|
|
- pList = sqlite3DbMallocRawNN(db, sizeof(ExprList)+sizeof(pList->a[0])*4 );
|
|
+ pList = sqlite3DbMallocRawNN(db, SZ_EXPRLIST(4));
|
|
if( pList==0 ){
|
|
sqlite3ExprDelete(db, pExpr);
|
|
return 0;
|
|
@@ -111568,8 +112380,7 @@
|
|
struct ExprList_item *pItem;
|
|
ExprList *pNew;
|
|
pList->nAlloc *= 2;
|
|
- pNew = sqlite3DbRealloc(db, pList,
|
|
- sizeof(*pList)+(pList->nAlloc-1)*sizeof(pList->a[0]));
|
|
+ pNew = sqlite3DbRealloc(db, pList, SZ_EXPRLIST(pList->nAlloc));
|
|
if( pNew==0 ){
|
|
sqlite3ExprListDelete(db, pList);
|
|
sqlite3ExprDelete(db, pExpr);
|
|
@@ -112498,13 +113309,7 @@
|
|
int ii;
|
|
assert( VisibleRowid(pTab) );
|
|
for(ii=0; ii<ArraySize(azOpt); ii++){
|
|
- int iCol;
|
|
- for(iCol=0; iCol<pTab->nCol; iCol++){
|
|
- if( sqlite3_stricmp(azOpt[ii], pTab->aCol[iCol].zCnName)==0 ) break;
|
|
- }
|
|
- if( iCol==pTab->nCol ){
|
|
- return azOpt[ii];
|
|
- }
|
|
+ if( sqlite3ColumnIndex(pTab, azOpt[ii])<0 ) return azOpt[ii];
|
|
}
|
|
return 0;
|
|
}
|
|
@@ -112908,7 +113713,7 @@
|
|
char *zRet;
|
|
|
|
assert( pExpr->op==TK_IN );
|
|
- zRet = sqlite3DbMallocRaw(pParse->db, nVal+1);
|
|
+ zRet = sqlite3DbMallocRaw(pParse->db, 1+(i64)nVal);
|
|
if( zRet ){
|
|
int i;
|
|
for(i=0; i<nVal; i++){
|
|
@@ -113168,11 +113973,12 @@
|
|
sqlite3SelectDelete(pParse->db, pCopy);
|
|
sqlite3DbFree(pParse->db, dest.zAffSdst);
|
|
if( addrBloom ){
|
|
+ /* Remember that location of the Bloom filter in the P3 operand
|
|
+ ** of the OP_Once that began this subroutine. tag-202407032019 */
|
|
sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2;
|
|
if( dest.iSDParm2==0 ){
|
|
- sqlite3VdbeChangeToNoop(v, addrBloom);
|
|
- }else{
|
|
- sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2;
|
|
+ /* If the Bloom filter won't actually be used, keep it small */
|
|
+ sqlite3VdbeGetOp(v, addrBloom)->p1 = 10;
|
|
}
|
|
}
|
|
if( rc ){
|
|
@@ -113619,7 +114425,7 @@
|
|
if( ExprHasProperty(pExpr, EP_Subrtn) ){
|
|
const VdbeOp *pOp = sqlite3VdbeGetOp(v, pExpr->y.sub.iAddr);
|
|
assert( pOp->opcode==OP_Once || pParse->nErr );
|
|
- if( pOp->opcode==OP_Once && pOp->p3>0 ){
|
|
+ if( pOp->opcode==OP_Once && pOp->p3>0 ){ /* tag-202407032019 */
|
|
assert( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) );
|
|
sqlite3VdbeAddOp4Int(v, OP_Filter, pOp->p3, destIfFalse,
|
|
rLhs, nVector); VdbeCoverage(v);
|
|
@@ -114211,7 +115017,7 @@
|
|
|
|
|
|
/*
|
|
-** Expresion pExpr is guaranteed to be a TK_COLUMN or equivalent. This
|
|
+** Expression pExpr is guaranteed to be a TK_COLUMN or equivalent. This
|
|
** function checks the Parse.pIdxPartExpr list to see if this column
|
|
** can be replaced with a constant value. If so, it generates code to
|
|
** put the constant value in a register (ideally, but not necessarily,
|
|
@@ -115468,11 +116274,11 @@
|
|
assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL );
|
|
assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL );
|
|
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
|
- sqlite3VdbeTypeofColumn(v, r1);
|
|
+ assert( regFree1==0 || regFree1==r1 );
|
|
+ if( regFree1 ) sqlite3VdbeTypeofColumn(v, r1);
|
|
sqlite3VdbeAddOp2(v, op, r1, dest);
|
|
VdbeCoverageIf(v, op==TK_ISNULL);
|
|
VdbeCoverageIf(v, op==TK_NOTNULL);
|
|
- testcase( regFree1==0 );
|
|
break;
|
|
}
|
|
case TK_BETWEEN: {
|
|
@@ -115643,11 +116449,11 @@
|
|
case TK_ISNULL:
|
|
case TK_NOTNULL: {
|
|
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
|
- sqlite3VdbeTypeofColumn(v, r1);
|
|
+ assert( regFree1==0 || regFree1==r1 );
|
|
+ if( regFree1 ) sqlite3VdbeTypeofColumn(v, r1);
|
|
sqlite3VdbeAddOp2(v, op, r1, dest);
|
|
testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL);
|
|
testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL);
|
|
- testcase( regFree1==0 );
|
|
break;
|
|
}
|
|
case TK_BETWEEN: {
|
|
@@ -116547,7 +117353,9 @@
|
|
){
|
|
struct AggInfo_col *pCol;
|
|
int k;
|
|
+ int mxTerm = pParse->db->aLimit[SQLITE_LIMIT_COLUMN];
|
|
|
|
+ assert( mxTerm <= SMXV(i16) );
|
|
assert( pAggInfo->iFirstReg==0 );
|
|
pCol = pAggInfo->aCol;
|
|
for(k=0; k<pAggInfo->nColumn; k++, pCol++){
|
|
@@ -116565,6 +117373,10 @@
|
|
assert( pParse->db->mallocFailed );
|
|
return;
|
|
}
|
|
+ if( k>mxTerm ){
|
|
+ sqlite3ErrorMsg(pParse, "more than %d aggregate terms", mxTerm);
|
|
+ k = mxTerm;
|
|
+ }
|
|
pCol = &pAggInfo->aCol[k];
|
|
assert( ExprUseYTab(pExpr) );
|
|
pCol->pTab = pExpr->y.pTab;
|
|
@@ -116598,6 +117410,7 @@
|
|
if( pExpr->op==TK_COLUMN ){
|
|
pExpr->op = TK_AGG_COLUMN;
|
|
}
|
|
+ assert( k <= SMXV(pExpr->iAgg) );
|
|
pExpr->iAgg = (i16)k;
|
|
}
|
|
|
|
@@ -116682,13 +117495,19 @@
|
|
** function that is already in the pAggInfo structure
|
|
*/
|
|
struct AggInfo_func *pItem = pAggInfo->aFunc;
|
|
+ int mxTerm = pParse->db->aLimit[SQLITE_LIMIT_COLUMN];
|
|
+ assert( mxTerm <= SMXV(i16) );
|
|
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
|
|
if( NEVER(pItem->pFExpr==pExpr) ) break;
|
|
if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){
|
|
break;
|
|
}
|
|
}
|
|
- if( i>=pAggInfo->nFunc ){
|
|
+ if( i>mxTerm ){
|
|
+ sqlite3ErrorMsg(pParse, "more than %d aggregate terms", mxTerm);
|
|
+ i = mxTerm;
|
|
+ assert( i<pAggInfo->nFunc );
|
|
+ }else if( i>=pAggInfo->nFunc ){
|
|
/* pExpr is original. Make a new entry in pAggInfo->aFunc[]
|
|
*/
|
|
u8 enc = ENC(pParse->db);
|
|
@@ -116742,6 +117561,7 @@
|
|
*/
|
|
assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
|
|
ExprSetVVAProperty(pExpr, EP_NoReduce);
|
|
+ assert( i <= SMXV(pExpr->iAgg) );
|
|
pExpr->iAgg = (i16)i;
|
|
pExpr->pAggInfo = pAggInfo;
|
|
return WRC_Prune;
|
|
@@ -117452,13 +118272,13 @@
|
|
assert( pNew->nCol>0 );
|
|
nAlloc = (((pNew->nCol-1)/8)*8)+8;
|
|
assert( nAlloc>=pNew->nCol && nAlloc%8==0 && nAlloc-pNew->nCol<8 );
|
|
- pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nAlloc);
|
|
+ pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*(u32)nAlloc);
|
|
pNew->zName = sqlite3MPrintf(db, "sqlite_altertab_%s", pTab->zName);
|
|
if( !pNew->aCol || !pNew->zName ){
|
|
assert( db->mallocFailed );
|
|
goto exit_begin_add_column;
|
|
}
|
|
- memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol);
|
|
+ memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*(size_t)pNew->nCol);
|
|
for(i=0; i<pNew->nCol; i++){
|
|
Column *pCol = &pNew->aCol[i];
|
|
pCol->zCnName = sqlite3DbStrDup(db, pCol->zCnName);
|
|
@@ -117553,10 +118373,8 @@
|
|
** altered. Set iCol to be the index of the column being renamed */
|
|
zOld = sqlite3NameFromToken(db, pOld);
|
|
if( !zOld ) goto exit_rename_column;
|
|
- for(iCol=0; iCol<pTab->nCol; iCol++){
|
|
- if( 0==sqlite3StrICmp(pTab->aCol[iCol].zCnName, zOld) ) break;
|
|
- }
|
|
- if( iCol==pTab->nCol ){
|
|
+ iCol = sqlite3ColumnIndex(pTab, zOld);
|
|
+ if( iCol<0 ){
|
|
sqlite3ErrorMsg(pParse, "no such column: \"%T\"", pOld);
|
|
goto exit_rename_column;
|
|
}
|
|
@@ -118059,6 +118877,7 @@
|
|
int bTemp /* True if SQL is from temp schema */
|
|
){
|
|
int rc;
|
|
+ u64 flags;
|
|
|
|
sqlite3ParseObjectInit(p, db);
|
|
if( zSql==0 ){
|
|
@@ -118067,11 +118886,21 @@
|
|
if( sqlite3StrNICmp(zSql,"CREATE ",7)!=0 ){
|
|
return SQLITE_CORRUPT_BKPT;
|
|
}
|
|
- db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb);
|
|
+ if( bTemp ){
|
|
+ db->init.iDb = 1;
|
|
+ }else{
|
|
+ int iDb = sqlite3FindDbName(db, zDb);
|
|
+ assert( iDb>=0 && iDb<=0xff );
|
|
+ db->init.iDb = (u8)iDb;
|
|
+ }
|
|
p->eParseMode = PARSE_MODE_RENAME;
|
|
p->db = db;
|
|
p->nQueryLoop = 1;
|
|
+ flags = db->flags;
|
|
+ testcase( (db->flags & SQLITE_Comments)==0 && strstr(zSql," /* ")!=0 );
|
|
+ db->flags |= SQLITE_Comments;
|
|
rc = sqlite3RunParser(p, zSql);
|
|
+ db->flags = flags;
|
|
if( db->mallocFailed ) rc = SQLITE_NOMEM;
|
|
if( rc==SQLITE_OK
|
|
&& NEVER(p->pNewTable==0 && p->pNewIndex==0 && p->pNewTrigger==0)
|
|
@@ -118134,10 +118963,11 @@
|
|
nQuot = sqlite3Strlen30(zQuot)-1;
|
|
}
|
|
|
|
- assert( nQuot>=nNew );
|
|
- zOut = sqlite3DbMallocZero(db, nSql + pRename->nList*nQuot + 1);
|
|
+ assert( nQuot>=nNew && nSql>=0 && nNew>=0 );
|
|
+ zOut = sqlite3DbMallocZero(db, (u64)nSql + pRename->nList*(u64)nQuot + 1);
|
|
}else{
|
|
- zOut = (char*)sqlite3DbMallocZero(db, (nSql*2+1) * 3);
|
|
+ assert( nSql>0 );
|
|
+ zOut = (char*)sqlite3DbMallocZero(db, (2*(u64)nSql + 1) * 3);
|
|
if( zOut ){
|
|
zBuf1 = &zOut[nSql*2+1];
|
|
zBuf2 = &zOut[nSql*4+2];
|
|
@@ -118149,16 +118979,17 @@
|
|
** with the new column name, or with single-quoted versions of themselves.
|
|
** All that remains is to construct and return the edited SQL string. */
|
|
if( zOut ){
|
|
- int nOut = nSql;
|
|
- memcpy(zOut, zSql, nSql);
|
|
+ i64 nOut = nSql;
|
|
+ assert( nSql>0 );
|
|
+ memcpy(zOut, zSql, (size_t)nSql);
|
|
while( pRename->pList ){
|
|
int iOff; /* Offset of token to replace in zOut */
|
|
- u32 nReplace;
|
|
+ i64 nReplace;
|
|
const char *zReplace;
|
|
RenameToken *pBest = renameColumnTokenNext(pRename);
|
|
|
|
if( zNew ){
|
|
- if( bQuote==0 && sqlite3IsIdChar(*pBest->t.z) ){
|
|
+ if( bQuote==0 && sqlite3IsIdChar(*(u8*)pBest->t.z) ){
|
|
nReplace = nNew;
|
|
zReplace = zNew;
|
|
}else{
|
|
@@ -118176,14 +119007,15 @@
|
|
memcpy(zBuf1, pBest->t.z, pBest->t.n);
|
|
zBuf1[pBest->t.n] = 0;
|
|
sqlite3Dequote(zBuf1);
|
|
- sqlite3_snprintf(nSql*2, zBuf2, "%Q%s", zBuf1,
|
|
+ assert( nSql < 0x15555554 /* otherwise malloc would have failed */ );
|
|
+ sqlite3_snprintf((int)(nSql*2), zBuf2, "%Q%s", zBuf1,
|
|
pBest->t.z[pBest->t.n]=='\'' ? " " : ""
|
|
);
|
|
zReplace = zBuf2;
|
|
nReplace = sqlite3Strlen30(zReplace);
|
|
}
|
|
|
|
- iOff = pBest->t.z - zSql;
|
|
+ iOff = (int)(pBest->t.z - zSql);
|
|
if( pBest->t.n!=nReplace ){
|
|
memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n],
|
|
nOut - (iOff + pBest->t.n)
|
|
@@ -118209,11 +119041,12 @@
|
|
** Set all pEList->a[].fg.eEName fields in the expression-list to val.
|
|
*/
|
|
static void renameSetENames(ExprList *pEList, int val){
|
|
+ assert( val==ENAME_NAME || val==ENAME_TAB || val==ENAME_SPAN );
|
|
if( pEList ){
|
|
int i;
|
|
for(i=0; i<pEList->nExpr; i++){
|
|
assert( val==ENAME_NAME || pEList->a[i].fg.eEName==ENAME_NAME );
|
|
- pEList->a[i].fg.eEName = val;
|
|
+ pEList->a[i].fg.eEName = val&0x3;
|
|
}
|
|
}
|
|
}
|
|
@@ -118470,7 +119303,7 @@
|
|
if( sParse.pNewTable ){
|
|
if( IsView(sParse.pNewTable) ){
|
|
Select *pSelect = sParse.pNewTable->u.view.pSelect;
|
|
- pSelect->selFlags &= ~SF_View;
|
|
+ pSelect->selFlags &= ~(u32)SF_View;
|
|
sParse.rc = SQLITE_OK;
|
|
sqlite3SelectPrep(&sParse, pSelect, 0);
|
|
rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc);
|
|
@@ -118688,7 +119521,7 @@
|
|
sNC.pParse = &sParse;
|
|
|
|
assert( pSelect->selFlags & SF_View );
|
|
- pSelect->selFlags &= ~SF_View;
|
|
+ pSelect->selFlags &= ~(u32)SF_View;
|
|
sqlite3SelectPrep(&sParse, pTab->u.view.pSelect, &sNC);
|
|
if( sParse.nErr ){
|
|
rc = sParse.rc;
|
|
@@ -118861,7 +119694,7 @@
|
|
if( sParse.pNewTable ){
|
|
if( IsView(sParse.pNewTable) ){
|
|
Select *pSelect = sParse.pNewTable->u.view.pSelect;
|
|
- pSelect->selFlags &= ~SF_View;
|
|
+ pSelect->selFlags &= ~(u32)SF_View;
|
|
sParse.rc = SQLITE_OK;
|
|
sqlite3SelectPrep(&sParse, pSelect, 0);
|
|
rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc);
|
|
@@ -118960,10 +119793,10 @@
|
|
if( zDb && zInput ){
|
|
int rc;
|
|
Parse sParse;
|
|
- int flags = db->flags;
|
|
+ u64 flags = db->flags;
|
|
if( bNoDQS ) db->flags &= ~(SQLITE_DqsDML|SQLITE_DqsDDL);
|
|
rc = renameParseSql(&sParse, zDb, db, zInput, bTemp);
|
|
- db->flags |= (flags & (SQLITE_DqsDML|SQLITE_DqsDDL));
|
|
+ db->flags = flags;
|
|
if( rc==SQLITE_OK ){
|
|
if( isLegacy==0 && sParse.pNewTable && IsView(sParse.pNewTable) ){
|
|
NameContext sNC;
|
|
@@ -119455,7 +120288,8 @@
|
|
sqlite3NestedParse(pParse,
|
|
"CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols
|
|
);
|
|
- aRoot[i] = (u32)pParse->regRoot;
|
|
+ assert( pParse->isCreate || pParse->nErr );
|
|
+ aRoot[i] = (u32)pParse->u1.cr.regRoot;
|
|
aCreateTbl[i] = OPFLAG_P2ISREG;
|
|
}
|
|
}else{
|
|
@@ -119646,7 +120480,7 @@
|
|
int nCol; /* Number of columns in index being sampled */
|
|
int nKeyCol; /* Number of key columns */
|
|
int nColUp; /* nCol rounded up for alignment */
|
|
- int n; /* Bytes of space to allocate */
|
|
+ i64 n; /* Bytes of space to allocate */
|
|
sqlite3 *db = sqlite3_context_db_handle(context); /* Database connection */
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
/* Maximum number of samples. 0 if STAT4 data is not collected */
|
|
@@ -119682,7 +120516,7 @@
|
|
p->db = db;
|
|
p->nEst = sqlite3_value_int64(argv[2]);
|
|
p->nRow = 0;
|
|
- p->nLimit = sqlite3_value_int64(argv[3]);
|
|
+ p->nLimit = sqlite3_value_int(argv[3]);
|
|
p->nCol = nCol;
|
|
p->nKeyCol = nKeyCol;
|
|
p->nSkipAhead = 0;
|
|
@@ -120815,16 +121649,6 @@
|
|
while( z[0]!=0 && z[0]!=' ' ) z++;
|
|
while( z[0]==' ' ) z++;
|
|
}
|
|
-
|
|
- /* Set the bLowQual flag if the peak number of rows obtained
|
|
- ** from a full equality match is so large that a full table scan
|
|
- ** seems likely to be faster than using the index.
|
|
- */
|
|
- if( aLog[0] > 66 /* Index has more than 100 rows */
|
|
- && aLog[0] <= aLog[nOut-1] /* And only a single value seen */
|
|
- ){
|
|
- pIndex->bLowQual = 1;
|
|
- }
|
|
}
|
|
}
|
|
|
|
@@ -121420,7 +122244,7 @@
|
|
if( aNew==0 ) return;
|
|
memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
|
|
}else{
|
|
- aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
|
|
+ aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(1+(i64)db->nDb));
|
|
if( aNew==0 ) return;
|
|
}
|
|
db->aDb = aNew;
|
|
@@ -121491,6 +122315,13 @@
|
|
sqlite3BtreeEnterAll(db);
|
|
db->init.iDb = 0;
|
|
db->mDbFlags &= ~(DBFLAG_SchemaKnownOk);
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ if( db->setlkFlags & SQLITE_SETLK_BLOCK_ON_CONNECT ){
|
|
+ int val = 1;
|
|
+ sqlite3_file *fd = sqlite3PagerFile(sqlite3BtreePager(pNew->pBt));
|
|
+ sqlite3OsFileControlHint(fd, SQLITE_FCNTL_BLOCK_ON_CONNECT, &val);
|
|
+ }
|
|
+#endif
|
|
if( !REOPEN_AS_MEMDB(db) ){
|
|
rc = sqlite3Init(db, &zErrDyn);
|
|
}
|
|
@@ -122213,6 +123044,7 @@
|
|
}
|
|
}
|
|
|
|
+ assert( pToplevel->nTableLock < 0x7fff0000 );
|
|
nBytes = sizeof(TableLock) * (pToplevel->nTableLock+1);
|
|
pToplevel->aTableLock =
|
|
sqlite3DbReallocOrFree(pToplevel->db, pToplevel->aTableLock, nBytes);
|
|
@@ -122313,10 +123145,12 @@
|
|
|| sqlite3VdbeAssertMayAbort(v, pParse->mayAbort));
|
|
if( v ){
|
|
if( pParse->bReturning ){
|
|
- Returning *pReturning = pParse->u1.pReturning;
|
|
+ Returning *pReturning;
|
|
int addrRewind;
|
|
int reg;
|
|
|
|
+ assert( !pParse->isCreate );
|
|
+ pReturning = pParse->u1.d.pReturning;
|
|
if( pReturning->nRetCol ){
|
|
sqlite3VdbeAddOp0(v, OP_FkCheck);
|
|
addrRewind =
|
|
@@ -122392,7 +123226,9 @@
|
|
}
|
|
|
|
if( pParse->bReturning ){
|
|
- Returning *pRet = pParse->u1.pReturning;
|
|
+ Returning *pRet;
|
|
+ assert( !pParse->isCreate );
|
|
+ pRet = pParse->u1.d.pReturning;
|
|
if( pRet->nRetCol ){
|
|
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol);
|
|
}
|
|
@@ -123207,10 +124043,16 @@
|
|
** find the (first) offset of that column in index pIdx. Or return -1
|
|
** if column iCol is not used in index pIdx.
|
|
*/
|
|
-SQLITE_PRIVATE i16 sqlite3TableColumnToIndex(Index *pIdx, i16 iCol){
|
|
+SQLITE_PRIVATE int sqlite3TableColumnToIndex(Index *pIdx, int iCol){
|
|
int i;
|
|
+ i16 iCol16;
|
|
+ assert( iCol>=(-1) && iCol<=SQLITE_MAX_COLUMN );
|
|
+ assert( pIdx->nColumn<=SQLITE_MAX_COLUMN+1 );
|
|
+ iCol16 = iCol;
|
|
for(i=0; i<pIdx->nColumn; i++){
|
|
- if( iCol==pIdx->aiColumn[i] ) return i;
|
|
+ if( iCol16==pIdx->aiColumn[i] ){
|
|
+ return i;
|
|
+ }
|
|
}
|
|
return -1;
|
|
}
|
|
@@ -123464,8 +124306,9 @@
|
|
/* If the file format and encoding in the database have not been set,
|
|
** set them now.
|
|
*/
|
|
- reg1 = pParse->regRowid = ++pParse->nMem;
|
|
- reg2 = pParse->regRoot = ++pParse->nMem;
|
|
+ assert( pParse->isCreate );
|
|
+ reg1 = pParse->u1.cr.regRowid = ++pParse->nMem;
|
|
+ reg2 = pParse->u1.cr.regRoot = ++pParse->nMem;
|
|
reg3 = ++pParse->nMem;
|
|
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, BTREE_FILE_FORMAT);
|
|
sqlite3VdbeUsesBtree(v, iDb);
|
|
@@ -123480,8 +124323,8 @@
|
|
** The record created does not contain anything yet. It will be replaced
|
|
** by the real entry in code generated at sqlite3EndTable().
|
|
**
|
|
- ** The rowid for the new entry is left in register pParse->regRowid.
|
|
- ** The root page number of the new table is left in reg pParse->regRoot.
|
|
+ ** The rowid for the new entry is left in register pParse->u1.cr.regRowid.
|
|
+ ** The root page of the new table is left in reg pParse->u1.cr.regRoot.
|
|
** The rowid and root page number values are needed by the code that
|
|
** sqlite3EndTable will generate.
|
|
*/
|
|
@@ -123492,7 +124335,7 @@
|
|
#endif
|
|
{
|
|
assert( !pParse->bReturning );
|
|
- pParse->u1.addrCrTab =
|
|
+ pParse->u1.cr.addrCrTab =
|
|
sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY);
|
|
}
|
|
sqlite3OpenSchemaTable(pParse, iDb);
|
|
@@ -123570,7 +124413,8 @@
|
|
sqlite3ExprListDelete(db, pList);
|
|
return;
|
|
}
|
|
- pParse->u1.pReturning = pRet;
|
|
+ assert( !pParse->isCreate );
|
|
+ pParse->u1.d.pReturning = pRet;
|
|
pRet->pParse = pParse;
|
|
pRet->pReturnEL = pList;
|
|
sqlite3ParserAddCleanup(pParse, sqlite3DeleteReturning, pRet);
|
|
@@ -123612,7 +124456,6 @@
|
|
char *zType;
|
|
Column *pCol;
|
|
sqlite3 *db = pParse->db;
|
|
- u8 hName;
|
|
Column *aNew;
|
|
u8 eType = COLTYPE_CUSTOM;
|
|
u8 szEst = 1;
|
|
@@ -123666,13 +124509,10 @@
|
|
memcpy(z, sName.z, sName.n);
|
|
z[sName.n] = 0;
|
|
sqlite3Dequote(z);
|
|
- hName = sqlite3StrIHash(z);
|
|
- for(i=0; i<p->nCol; i++){
|
|
- if( p->aCol[i].hName==hName && sqlite3StrICmp(z, p->aCol[i].zCnName)==0 ){
|
|
- sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
|
|
- sqlite3DbFree(db, z);
|
|
- return;
|
|
- }
|
|
+ if( p->nCol && sqlite3ColumnIndex(p, z)>=0 ){
|
|
+ sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
|
|
+ sqlite3DbFree(db, z);
|
|
+ return;
|
|
}
|
|
aNew = sqlite3DbRealloc(db,p->aCol,((i64)p->nCol+1)*sizeof(p->aCol[0]));
|
|
if( aNew==0 ){
|
|
@@ -123683,7 +124523,7 @@
|
|
pCol = &p->aCol[p->nCol];
|
|
memset(pCol, 0, sizeof(p->aCol[0]));
|
|
pCol->zCnName = z;
|
|
- pCol->hName = hName;
|
|
+ pCol->hName = sqlite3StrIHash(z);
|
|
sqlite3ColumnPropertiesFromName(p, pCol);
|
|
|
|
if( sType.n==0 ){
|
|
@@ -123707,9 +124547,14 @@
|
|
pCol->affinity = sqlite3AffinityType(zType, pCol);
|
|
pCol->colFlags |= COLFLAG_HASTYPE;
|
|
}
|
|
+ if( p->nCol<=0xff ){
|
|
+ u8 h = pCol->hName % sizeof(p->aHx);
|
|
+ p->aHx[h] = p->nCol;
|
|
+ }
|
|
p->nCol++;
|
|
p->nNVCol++;
|
|
- pParse->constraintName.n = 0;
|
|
+ assert( pParse->isCreate );
|
|
+ pParse->u1.cr.constraintName.n = 0;
|
|
}
|
|
|
|
/*
|
|
@@ -123973,15 +124818,11 @@
|
|
assert( pCExpr!=0 );
|
|
sqlite3StringToId(pCExpr);
|
|
if( pCExpr->op==TK_ID ){
|
|
- const char *zCName;
|
|
assert( !ExprHasProperty(pCExpr, EP_IntValue) );
|
|
- zCName = pCExpr->u.zToken;
|
|
- for(iCol=0; iCol<pTab->nCol; iCol++){
|
|
- if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zCnName)==0 ){
|
|
- pCol = &pTab->aCol[iCol];
|
|
- makeColumnPartOfPrimaryKey(pParse, pCol);
|
|
- break;
|
|
- }
|
|
+ iCol = sqlite3ColumnIndex(pTab, pCExpr->u.zToken);
|
|
+ if( iCol>=0 ){
|
|
+ pCol = &pTab->aCol[iCol];
|
|
+ makeColumnPartOfPrimaryKey(pParse, pCol);
|
|
}
|
|
}
|
|
}
|
|
@@ -124033,8 +124874,10 @@
|
|
&& !sqlite3BtreeIsReadonly(db->aDb[db->init.iDb].pBt)
|
|
){
|
|
pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr);
|
|
- if( pParse->constraintName.n ){
|
|
- sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1);
|
|
+ assert( pParse->isCreate );
|
|
+ if( pParse->u1.cr.constraintName.n ){
|
|
+ sqlite3ExprListSetName(pParse, pTab->pCheck,
|
|
+ &pParse->u1.cr.constraintName, 1);
|
|
}else{
|
|
Token t;
|
|
for(zStart++; sqlite3Isspace(zStart[0]); zStart++){}
|
|
@@ -124229,7 +125072,8 @@
|
|
** from sqliteMalloc() and must be freed by the calling function.
|
|
*/
|
|
static char *createTableStmt(sqlite3 *db, Table *p){
|
|
- int i, k, n;
|
|
+ int i, k, len;
|
|
+ i64 n;
|
|
char *zStmt;
|
|
char *zSep, *zSep2, *zEnd;
|
|
Column *pCol;
|
|
@@ -124253,8 +125097,9 @@
|
|
sqlite3OomFault(db);
|
|
return 0;
|
|
}
|
|
- sqlite3_snprintf(n, zStmt, "CREATE TABLE ");
|
|
- k = sqlite3Strlen30(zStmt);
|
|
+ assert( n>14 && n<=0x7fffffff );
|
|
+ memcpy(zStmt, "CREATE TABLE ", 13);
|
|
+ k = 13;
|
|
identPut(zStmt, &k, p->zName);
|
|
zStmt[k++] = '(';
|
|
for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){
|
|
@@ -124266,13 +125111,15 @@
|
|
/* SQLITE_AFF_REAL */ " REAL",
|
|
/* SQLITE_AFF_FLEXNUM */ " NUM",
|
|
};
|
|
- int len;
|
|
const char *zType;
|
|
|
|
- sqlite3_snprintf(n-k, &zStmt[k], zSep);
|
|
- k += sqlite3Strlen30(&zStmt[k]);
|
|
+ len = sqlite3Strlen30(zSep);
|
|
+ assert( k+len<n );
|
|
+ memcpy(&zStmt[k], zSep, len);
|
|
+ k += len;
|
|
zSep = zSep2;
|
|
identPut(zStmt, &k, pCol->zCnName);
|
|
+ assert( k<n );
|
|
assert( pCol->affinity-SQLITE_AFF_BLOB >= 0 );
|
|
assert( pCol->affinity-SQLITE_AFF_BLOB < ArraySize(azType) );
|
|
testcase( pCol->affinity==SQLITE_AFF_BLOB );
|
|
@@ -124287,11 +125134,14 @@
|
|
assert( pCol->affinity==SQLITE_AFF_BLOB
|
|
|| pCol->affinity==SQLITE_AFF_FLEXNUM
|
|
|| pCol->affinity==sqlite3AffinityType(zType, 0) );
|
|
+ assert( k+len<n );
|
|
memcpy(&zStmt[k], zType, len);
|
|
k += len;
|
|
assert( k<=n );
|
|
}
|
|
- sqlite3_snprintf(n-k, &zStmt[k], "%s", zEnd);
|
|
+ len = sqlite3Strlen30(zEnd);
|
|
+ assert( k+len<n );
|
|
+ memcpy(&zStmt[k], zEnd, len+1);
|
|
return zStmt;
|
|
}
|
|
|
|
@@ -124299,12 +125149,17 @@
|
|
** Resize an Index object to hold N columns total. Return SQLITE_OK
|
|
** on success and SQLITE_NOMEM on an OOM error.
|
|
*/
|
|
-static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){
|
|
+static int resizeIndexObject(Parse *pParse, Index *pIdx, int N){
|
|
char *zExtra;
|
|
- int nByte;
|
|
+ u64 nByte;
|
|
+ sqlite3 *db;
|
|
if( pIdx->nColumn>=N ) return SQLITE_OK;
|
|
+ db = pParse->db;
|
|
+ assert( N>0 );
|
|
+ assert( N <= SQLITE_MAX_COLUMN*2 /* tag-20250221-1 */ );
|
|
+ testcase( N==2*pParse->db->aLimit[SQLITE_LIMIT_COLUMN] );
|
|
assert( pIdx->isResized==0 );
|
|
- nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*N;
|
|
+ nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*(u64)N;
|
|
zExtra = sqlite3DbMallocZero(db, nByte);
|
|
if( zExtra==0 ) return SQLITE_NOMEM_BKPT;
|
|
memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn);
|
|
@@ -124318,7 +125173,7 @@
|
|
zExtra += sizeof(i16)*N;
|
|
memcpy(zExtra, pIdx->aSortOrder, pIdx->nColumn);
|
|
pIdx->aSortOrder = (u8*)zExtra;
|
|
- pIdx->nColumn = N;
|
|
+ pIdx->nColumn = (u16)N; /* See tag-20250221-1 above for proof of safety */
|
|
pIdx->isResized = 1;
|
|
return SQLITE_OK;
|
|
}
|
|
@@ -124484,9 +125339,9 @@
|
|
** into BTREE_BLOBKEY.
|
|
*/
|
|
assert( !pParse->bReturning );
|
|
- if( pParse->u1.addrCrTab ){
|
|
+ if( pParse->u1.cr.addrCrTab ){
|
|
assert( v );
|
|
- sqlite3VdbeChangeP3(v, pParse->u1.addrCrTab, BTREE_BLOBKEY);
|
|
+ sqlite3VdbeChangeP3(v, pParse->u1.cr.addrCrTab, BTREE_BLOBKEY);
|
|
}
|
|
|
|
/* Locate the PRIMARY KEY index. Or, if this table was originally
|
|
@@ -124572,14 +125427,14 @@
|
|
pIdx->nColumn = pIdx->nKeyCol;
|
|
continue;
|
|
}
|
|
- if( resizeIndexObject(db, pIdx, pIdx->nKeyCol+n) ) return;
|
|
+ if( resizeIndexObject(pParse, pIdx, pIdx->nKeyCol+n) ) return;
|
|
for(i=0, j=pIdx->nKeyCol; i<nPk; i++){
|
|
if( !isDupColumn(pIdx, pIdx->nKeyCol, pPk, i) ){
|
|
testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) );
|
|
pIdx->aiColumn[j] = pPk->aiColumn[i];
|
|
pIdx->azColl[j] = pPk->azColl[i];
|
|
if( pPk->aSortOrder[i] ){
|
|
- /* See ticket https://www.sqlite.org/src/info/bba7b69f9849b5bf */
|
|
+ /* See ticket https://sqlite.org/src/info/bba7b69f9849b5bf */
|
|
pIdx->bAscKeyBug = 1;
|
|
}
|
|
j++;
|
|
@@ -124596,7 +125451,7 @@
|
|
if( !hasColumn(pPk->aiColumn, nPk, i)
|
|
&& (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) nExtra++;
|
|
}
|
|
- if( resizeIndexObject(db, pPk, nPk+nExtra) ) return;
|
|
+ if( resizeIndexObject(pParse, pPk, nPk+nExtra) ) return;
|
|
for(i=0, j=nPk; i<pTab->nCol; i++){
|
|
if( !hasColumn(pPk->aiColumn, j, i)
|
|
&& (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0
|
|
@@ -124926,7 +125781,7 @@
|
|
|
|
/* If this is a CREATE TABLE xx AS SELECT ..., execute the SELECT
|
|
** statement to populate the new table. The root-page number for the
|
|
- ** new table is in register pParse->regRoot.
|
|
+ ** new table is in register pParse->u1.cr.regRoot.
|
|
**
|
|
** Once the SELECT has been coded by sqlite3Select(), it is in a
|
|
** suitable state to query for the column names and types to be used
|
|
@@ -124957,7 +125812,8 @@
|
|
regRec = ++pParse->nMem;
|
|
regRowid = ++pParse->nMem;
|
|
sqlite3MayAbort(pParse);
|
|
- sqlite3VdbeAddOp3(v, OP_OpenWrite, iCsr, pParse->regRoot, iDb);
|
|
+ assert( pParse->isCreate );
|
|
+ sqlite3VdbeAddOp3(v, OP_OpenWrite, iCsr, pParse->u1.cr.regRoot, iDb);
|
|
sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG);
|
|
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
|
|
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
|
|
@@ -125002,6 +125858,7 @@
|
|
** schema table. We just need to update that slot with all
|
|
** the information we've collected.
|
|
*/
|
|
+ assert( pParse->isCreate );
|
|
sqlite3NestedParse(pParse,
|
|
"UPDATE %Q." LEGACY_SCHEMA_TABLE
|
|
" SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q"
|
|
@@ -125010,9 +125867,9 @@
|
|
zType,
|
|
p->zName,
|
|
p->zName,
|
|
- pParse->regRoot,
|
|
+ pParse->u1.cr.regRoot,
|
|
zStmt,
|
|
- pParse->regRowid
|
|
+ pParse->u1.cr.regRowid
|
|
);
|
|
sqlite3DbFree(db, zStmt);
|
|
sqlite3ChangeCookie(pParse, iDb);
|
|
@@ -125752,7 +126609,7 @@
|
|
}else{
|
|
nCol = pFromCol->nExpr;
|
|
}
|
|
- nByte = sizeof(*pFKey) + (nCol-1)*sizeof(pFKey->aCol[0]) + pTo->n + 1;
|
|
+ nByte = SZ_FKEY(nCol) + pTo->n + 1;
|
|
if( pToCol ){
|
|
for(i=0; i<pToCol->nExpr; i++){
|
|
nByte += sqlite3Strlen30(pToCol->a[i].zEName) + 1;
|
|
@@ -125954,7 +126811,7 @@
|
|
** not work for UNIQUE constraint indexes on WITHOUT ROWID tables
|
|
** with DESC primary keys, since those indexes have there keys in
|
|
** a different order from the main table.
|
|
- ** See ticket: https://www.sqlite.org/src/info/bba7b69f9849b5bf
|
|
+ ** See ticket: https://sqlite.org/src/info/bba7b69f9849b5bf
|
|
*/
|
|
sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx);
|
|
}
|
|
@@ -125978,13 +126835,14 @@
|
|
*/
|
|
SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(
|
|
sqlite3 *db, /* Database connection */
|
|
- i16 nCol, /* Total number of columns in the index */
|
|
+ int nCol, /* Total number of columns in the index */
|
|
int nExtra, /* Number of bytes of extra space to alloc */
|
|
char **ppExtra /* Pointer to the "extra" space */
|
|
){
|
|
Index *p; /* Allocated index object */
|
|
- int nByte; /* Bytes of space for Index object + arrays */
|
|
+ i64 nByte; /* Bytes of space for Index object + arrays */
|
|
|
|
+ assert( nCol <= 2*db->aLimit[SQLITE_LIMIT_COLUMN] );
|
|
nByte = ROUND8(sizeof(Index)) + /* Index structure */
|
|
ROUND8(sizeof(char*)*nCol) + /* Index.azColl */
|
|
ROUND8(sizeof(LogEst)*(nCol+1) + /* Index.aiRowLogEst */
|
|
@@ -125997,8 +126855,9 @@
|
|
p->aiRowLogEst = (LogEst*)pExtra; pExtra += sizeof(LogEst)*(nCol+1);
|
|
p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol;
|
|
p->aSortOrder = (u8*)pExtra;
|
|
- p->nColumn = nCol;
|
|
- p->nKeyCol = nCol - 1;
|
|
+ assert( nCol>0 );
|
|
+ p->nColumn = (u16)nCol;
|
|
+ p->nKeyCol = (u16)(nCol - 1);
|
|
*ppExtra = ((char*)p) + nByte;
|
|
}
|
|
return p;
|
|
@@ -126809,12 +127668,11 @@
|
|
sqlite3 *db = pParse->db;
|
|
int i;
|
|
if( pList==0 ){
|
|
- pList = sqlite3DbMallocZero(db, sizeof(IdList) );
|
|
+ pList = sqlite3DbMallocZero(db, SZ_IDLIST(1));
|
|
if( pList==0 ) return 0;
|
|
}else{
|
|
IdList *pNew;
|
|
- pNew = sqlite3DbRealloc(db, pList,
|
|
- sizeof(IdList) + pList->nId*sizeof(pList->a));
|
|
+ pNew = sqlite3DbRealloc(db, pList, SZ_IDLIST(pList->nId+1));
|
|
if( pNew==0 ){
|
|
sqlite3IdListDelete(db, pList);
|
|
return 0;
|
|
@@ -126913,8 +127771,7 @@
|
|
return 0;
|
|
}
|
|
if( nAlloc>SQLITE_MAX_SRCLIST ) nAlloc = SQLITE_MAX_SRCLIST;
|
|
- pNew = sqlite3DbRealloc(db, pSrc,
|
|
- sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) );
|
|
+ pNew = sqlite3DbRealloc(db, pSrc, SZ_SRCLIST(nAlloc));
|
|
if( pNew==0 ){
|
|
assert( db->mallocFailed );
|
|
return 0;
|
|
@@ -126989,7 +127846,7 @@
|
|
assert( pParse->db!=0 );
|
|
db = pParse->db;
|
|
if( pList==0 ){
|
|
- pList = sqlite3DbMallocRawNN(pParse->db, sizeof(SrcList) );
|
|
+ pList = sqlite3DbMallocRawNN(pParse->db, SZ_SRCLIST(1));
|
|
if( pList==0 ) return 0;
|
|
pList->nAlloc = 1;
|
|
pList->nSrc = 1;
|
|
@@ -127875,10 +128732,9 @@
|
|
}
|
|
|
|
if( pWith ){
|
|
- sqlite3_int64 nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte);
|
|
- pNew = sqlite3DbRealloc(db, pWith, nByte);
|
|
+ pNew = sqlite3DbRealloc(db, pWith, SZ_WITH(pWith->nCte+1));
|
|
}else{
|
|
- pNew = sqlite3DbMallocZero(db, sizeof(*pWith));
|
|
+ pNew = sqlite3DbMallocZero(db, SZ_WITH(1));
|
|
}
|
|
assert( (pNew!=0 && zName!=0) || db->mallocFailed );
|
|
|
|
@@ -129852,11 +130708,6 @@
|
|
i64 p1, p2;
|
|
|
|
assert( argc==3 || argc==2 );
|
|
- if( sqlite3_value_type(argv[1])==SQLITE_NULL
|
|
- || (argc==3 && sqlite3_value_type(argv[2])==SQLITE_NULL)
|
|
- ){
|
|
- return;
|
|
- }
|
|
p0type = sqlite3_value_type(argv[0]);
|
|
p1 = sqlite3_value_int64(argv[1]);
|
|
if( p0type==SQLITE_BLOB ){
|
|
@@ -129874,19 +130725,23 @@
|
|
}
|
|
}
|
|
}
|
|
-#ifdef SQLITE_SUBSTR_COMPATIBILITY
|
|
- /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as
|
|
- ** as substr(X,1,N) - it returns the first N characters of X. This
|
|
- ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8]
|
|
- ** from 2009-02-02 for compatibility of applications that exploited the
|
|
- ** old buggy behavior. */
|
|
- if( p1==0 ) p1 = 1; /* <rdar://problem/6778339> */
|
|
-#endif
|
|
if( argc==3 ){
|
|
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];
|
|
}
|
|
+ if( p1==0 ){
|
|
+#ifdef SQLITE_SUBSTR_COMPATIBILITY
|
|
+ /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as
|
|
+ ** as substr(X,1,N) - it returns the first N characters of X. This
|
|
+ ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8]
|
|
+ ** from 2009-02-02 for compatibility of applications that exploited the
|
|
+ ** old buggy behavior. */
|
|
+ p1 = 1; /* <rdar://problem/6778339> */
|
|
+#endif
|
|
+ if( sqlite3_value_type(argv[1])==SQLITE_NULL ) return;
|
|
+ }
|
|
if( p1<0 ){
|
|
p1 += len;
|
|
if( p1<0 ){
|
|
@@ -130587,7 +131442,7 @@
|
|
** Append to pStr text that is the SQL literal representation of the
|
|
** value contained in pValue.
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){
|
|
+SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue, int bEscape){
|
|
/* As currently implemented, the string must be initially empty.
|
|
** we might relax this requirement in the future, but that will
|
|
** require enhancements to the implementation. */
|
|
@@ -130635,7 +131490,7 @@
|
|
}
|
|
case SQLITE_TEXT: {
|
|
const unsigned char *zArg = sqlite3_value_text(pValue);
|
|
- sqlite3_str_appendf(pStr, "%Q", zArg);
|
|
+ sqlite3_str_appendf(pStr, bEscape ? "%#Q" : "%Q", zArg);
|
|
break;
|
|
}
|
|
default: {
|
|
@@ -130647,6 +131502,105 @@
|
|
}
|
|
|
|
/*
|
|
+** Return true if z[] begins with N hexadecimal digits, and write
|
|
+** a decoding of those digits into *pVal. Or return false if any
|
|
+** one of the first N characters in z[] is not a hexadecimal digit.
|
|
+*/
|
|
+static int isNHex(const char *z, int N, u32 *pVal){
|
|
+ int i;
|
|
+ int v = 0;
|
|
+ for(i=0; i<N; i++){
|
|
+ if( !sqlite3Isxdigit(z[i]) ) return 0;
|
|
+ v = (v<<4) + sqlite3HexToInt(z[i]);
|
|
+ }
|
|
+ *pVal = v;
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Implementation of the UNISTR() function.
|
|
+**
|
|
+** This is intended to be a work-alike of the UNISTR() function in
|
|
+** PostgreSQL. Quoting from the PG documentation (PostgreSQL 17 -
|
|
+** scraped on 2025-02-22):
|
|
+**
|
|
+** Evaluate escaped Unicode characters in the argument. Unicode
|
|
+** characters can be specified as \XXXX (4 hexadecimal digits),
|
|
+** \+XXXXXX (6 hexadecimal digits), \uXXXX (4 hexadecimal digits),
|
|
+** or \UXXXXXXXX (8 hexadecimal digits). To specify a backslash,
|
|
+** write two backslashes. All other characters are taken literally.
|
|
+*/
|
|
+static void unistrFunc(
|
|
+ sqlite3_context *context,
|
|
+ int argc,
|
|
+ sqlite3_value **argv
|
|
+){
|
|
+ char *zOut;
|
|
+ const char *zIn;
|
|
+ int nIn;
|
|
+ int i, j, n;
|
|
+ u32 v;
|
|
+
|
|
+ assert( argc==1 );
|
|
+ UNUSED_PARAMETER( argc );
|
|
+ zIn = (const char*)sqlite3_value_text(argv[0]);
|
|
+ if( zIn==0 ) return;
|
|
+ nIn = sqlite3_value_bytes(argv[0]);
|
|
+ zOut = sqlite3_malloc64(nIn+1);
|
|
+ if( zOut==0 ){
|
|
+ sqlite3_result_error_nomem(context);
|
|
+ return;
|
|
+ }
|
|
+ i = j = 0;
|
|
+ while( i<nIn ){
|
|
+ char *z = strchr(&zIn[i],'\\');
|
|
+ if( z==0 ){
|
|
+ n = nIn - i;
|
|
+ memmove(&zOut[j], &zIn[i], n);
|
|
+ j += n;
|
|
+ break;
|
|
+ }
|
|
+ n = z - &zIn[i];
|
|
+ if( n>0 ){
|
|
+ memmove(&zOut[j], &zIn[i], n);
|
|
+ j += n;
|
|
+ i += n;
|
|
+ }
|
|
+ if( zIn[i+1]=='\\' ){
|
|
+ i += 2;
|
|
+ zOut[j++] = '\\';
|
|
+ }else if( sqlite3Isxdigit(zIn[i+1]) ){
|
|
+ if( !isNHex(&zIn[i+1], 4, &v) ) goto unistr_error;
|
|
+ i += 5;
|
|
+ j += sqlite3AppendOneUtf8Character(&zOut[j], v);
|
|
+ }else if( zIn[i+1]=='+' ){
|
|
+ if( !isNHex(&zIn[i+2], 6, &v) ) goto unistr_error;
|
|
+ i += 8;
|
|
+ j += sqlite3AppendOneUtf8Character(&zOut[j], v);
|
|
+ }else if( zIn[i+1]=='u' ){
|
|
+ if( !isNHex(&zIn[i+2], 4, &v) ) goto unistr_error;
|
|
+ i += 6;
|
|
+ j += sqlite3AppendOneUtf8Character(&zOut[j], v);
|
|
+ }else if( zIn[i+1]=='U' ){
|
|
+ if( !isNHex(&zIn[i+2], 8, &v) ) goto unistr_error;
|
|
+ i += 10;
|
|
+ j += sqlite3AppendOneUtf8Character(&zOut[j], v);
|
|
+ }else{
|
|
+ goto unistr_error;
|
|
+ }
|
|
+ }
|
|
+ zOut[j] = 0;
|
|
+ sqlite3_result_text64(context, zOut, j, sqlite3_free, SQLITE_UTF8);
|
|
+ return;
|
|
+
|
|
+unistr_error:
|
|
+ sqlite3_free(zOut);
|
|
+ sqlite3_result_error(context, "invalid Unicode escape", -1);
|
|
+ return;
|
|
+}
|
|
+
|
|
+
|
|
+/*
|
|
** Implementation of the QUOTE() function.
|
|
**
|
|
** The quote(X) function returns the text of an SQL literal which is the
|
|
@@ -130655,6 +131609,10 @@
|
|
** as needed. BLOBs are encoded as hexadecimal literals. Strings with
|
|
** embedded NUL characters cannot be represented as string literals in SQL
|
|
** and hence the returned string literal is truncated prior to the first NUL.
|
|
+**
|
|
+** If sqlite3_user_data() is non-zero, then the UNISTR_QUOTE() function is
|
|
+** implemented instead. The difference is that UNISTR_QUOTE() uses the
|
|
+** UNISTR() function to escape control characters.
|
|
*/
|
|
static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|
sqlite3_str str;
|
|
@@ -130662,7 +131620,7 @@
|
|
assert( argc==1 );
|
|
UNUSED_PARAMETER(argc);
|
|
sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
|
|
- sqlite3QuoteValue(&str,argv[0]);
|
|
+ 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 ){
|
|
@@ -130917,7 +131875,7 @@
|
|
assert( zRep==sqlite3_value_text(argv[2]) );
|
|
nOut = nStr + 1;
|
|
assert( nOut<SQLITE_MAX_LENGTH );
|
|
- zOut = contextMalloc(context, (i64)nOut);
|
|
+ zOut = contextMalloc(context, nOut);
|
|
if( zOut==0 ){
|
|
return;
|
|
}
|
|
@@ -131061,7 +132019,7 @@
|
|
int nSep,
|
|
const char *zSep
|
|
){
|
|
- i64 j, k, n = 0;
|
|
+ i64 j, n = 0;
|
|
int i;
|
|
char *z;
|
|
for(i=0; i<argc; i++){
|
|
@@ -131075,8 +132033,8 @@
|
|
}
|
|
j = 0;
|
|
for(i=0; i<argc; i++){
|
|
- k = sqlite3_value_bytes(argv[i]);
|
|
- if( k>0 ){
|
|
+ if( sqlite3_value_type(argv[i])!=SQLITE_NULL ){
|
|
+ int k = sqlite3_value_bytes(argv[i]);
|
|
const char *v = (const char*)sqlite3_value_text(argv[i]);
|
|
if( v!=0 ){
|
|
if( j>0 && nSep>0 ){
|
|
@@ -131313,7 +132271,7 @@
|
|
** that it returns NULL if it sums over no inputs. TOTAL returns
|
|
** 0.0 in that case. In addition, TOTAL always returns a float where
|
|
** SUM might return an integer if it never encounters a floating point
|
|
-** value. TOTAL never fails, but SUM might through an exception if
|
|
+** value. TOTAL never fails, but SUM might throw an exception if
|
|
** it overflows an integer.
|
|
*/
|
|
static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|
@@ -132233,7 +133191,9 @@
|
|
DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
|
|
DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
|
|
FUNCTION(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 ),
|
|
VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
|
|
VFUNCTION(changes, 0, 0, 0, changes ),
|
|
VFUNCTION(total_changes, 0, 0, 0, total_changes ),
|
|
@@ -134520,7 +135480,7 @@
|
|
f = (f & pLeft->selFlags);
|
|
}
|
|
pSelect = sqlite3SelectNew(pParse, pRow, 0, 0, 0, 0, 0, f, 0);
|
|
- pLeft->selFlags &= ~SF_MultiValue;
|
|
+ pLeft->selFlags &= ~(u32)SF_MultiValue;
|
|
if( pSelect ){
|
|
pSelect->op = TK_ALL;
|
|
pSelect->pPrior = pLeft;
|
|
@@ -134902,28 +135862,22 @@
|
|
aTabColMap = sqlite3DbMallocZero(db, pTab->nCol*sizeof(int));
|
|
if( aTabColMap==0 ) goto insert_cleanup;
|
|
for(i=0; i<pColumn->nId; i++){
|
|
- const char *zCName = pColumn->a[i].zName;
|
|
- u8 hName = sqlite3StrIHash(zCName);
|
|
- for(j=0; j<pTab->nCol; j++){
|
|
- if( pTab->aCol[j].hName!=hName ) continue;
|
|
- if( sqlite3StrICmp(zCName, pTab->aCol[j].zCnName)==0 ){
|
|
- if( aTabColMap[j]==0 ) aTabColMap[j] = i+1;
|
|
- if( i!=j ) bIdListInOrder = 0;
|
|
- if( j==pTab->iPKey ){
|
|
- ipkColumn = i; assert( !withoutRowid );
|
|
- }
|
|
+ j = sqlite3ColumnIndex(pTab, pColumn->a[i].zName);
|
|
+ if( j>=0 ){
|
|
+ if( aTabColMap[j]==0 ) aTabColMap[j] = i+1;
|
|
+ if( i!=j ) bIdListInOrder = 0;
|
|
+ if( j==pTab->iPKey ){
|
|
+ ipkColumn = i; assert( !withoutRowid );
|
|
+ }
|
|
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
|
- if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){
|
|
- sqlite3ErrorMsg(pParse,
|
|
- "cannot INSERT into generated column \"%s\"",
|
|
- pTab->aCol[j].zCnName);
|
|
- goto insert_cleanup;
|
|
- }
|
|
-#endif
|
|
- break;
|
|
+ if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){
|
|
+ sqlite3ErrorMsg(pParse,
|
|
+ "cannot INSERT into generated column \"%s\"",
|
|
+ pTab->aCol[j].zCnName);
|
|
+ goto insert_cleanup;
|
|
}
|
|
- }
|
|
- if( j>=pTab->nCol ){
|
|
+#endif
|
|
+ }else{
|
|
if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){
|
|
ipkColumn = i;
|
|
bIdListInOrder = 0;
|
|
@@ -135221,7 +136175,7 @@
|
|
continue;
|
|
}else if( pColumn==0 ){
|
|
/* Hidden columns that are not explicitly named in the INSERT
|
|
- ** get there default value */
|
|
+ ** get their default value */
|
|
sqlite3ExprCodeFactorable(pParse,
|
|
sqlite3ColumnExpr(pTab, &pTab->aCol[i]),
|
|
iRegStore);
|
|
@@ -135946,7 +136900,7 @@
|
|
** could happen in any order, but they are grouped up front for
|
|
** convenience.
|
|
**
|
|
- ** 2018-08-14: Ticket https://www.sqlite.org/src/info/908f001483982c43
|
|
+ ** 2018-08-14: Ticket https://sqlite.org/src/info/908f001483982c43
|
|
** The order of constraints used to have OE_Update as (2) and OE_Abort
|
|
** and so forth as (1). But apparently PostgreSQL checks the OE_Update
|
|
** constraint before any others, so it had to be moved.
|
|
@@ -137756,6 +138710,8 @@
|
|
/* Version 3.44.0 and later */
|
|
void *(*get_clientdata)(sqlite3*,const char*);
|
|
int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
|
|
+ /* Version 3.50.0 and later */
|
|
+ int (*setlk_timeout)(sqlite3*,int,int);
|
|
};
|
|
|
|
/*
|
|
@@ -138089,6 +139045,8 @@
|
|
/* Version 3.44.0 and later */
|
|
#define sqlite3_get_clientdata sqlite3_api->get_clientdata
|
|
#define sqlite3_set_clientdata sqlite3_api->set_clientdata
|
|
+/* Version 3.50.0 and later */
|
|
+#define sqlite3_setlk_timeout sqlite3_api->setlk_timeout
|
|
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
|
|
|
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
|
@@ -138610,7 +139568,9 @@
|
|
sqlite3_stmt_explain,
|
|
/* Version 3.44.0 and later */
|
|
sqlite3_get_clientdata,
|
|
- sqlite3_set_clientdata
|
|
+ sqlite3_set_clientdata,
|
|
+ /* Version 3.50.0 and later */
|
|
+ sqlite3_setlk_timeout
|
|
};
|
|
|
|
/* True if x is the directory separator character
|
|
@@ -139132,48 +140092,48 @@
|
|
/* 13 */ "pk",
|
|
/* 14 */ "hidden",
|
|
/* table_info reuses 8 */
|
|
- /* 15 */ "schema", /* Used by: table_list */
|
|
- /* 16 */ "name",
|
|
+ /* 15 */ "name", /* Used by: function_list */
|
|
+ /* 16 */ "builtin",
|
|
/* 17 */ "type",
|
|
- /* 18 */ "ncol",
|
|
- /* 19 */ "wr",
|
|
- /* 20 */ "strict",
|
|
- /* 21 */ "seqno", /* Used by: index_xinfo */
|
|
- /* 22 */ "cid",
|
|
- /* 23 */ "name",
|
|
- /* 24 */ "desc",
|
|
- /* 25 */ "coll",
|
|
- /* 26 */ "key",
|
|
- /* 27 */ "name", /* Used by: function_list */
|
|
- /* 28 */ "builtin",
|
|
- /* 29 */ "type",
|
|
- /* 30 */ "enc",
|
|
- /* 31 */ "narg",
|
|
- /* 32 */ "flags",
|
|
- /* 33 */ "tbl", /* Used by: stats */
|
|
- /* 34 */ "idx",
|
|
- /* 35 */ "wdth",
|
|
- /* 36 */ "hght",
|
|
- /* 37 */ "flgs",
|
|
- /* 38 */ "seq", /* Used by: index_list */
|
|
- /* 39 */ "name",
|
|
- /* 40 */ "unique",
|
|
- /* 41 */ "origin",
|
|
- /* 42 */ "partial",
|
|
+ /* 18 */ "enc",
|
|
+ /* 19 */ "narg",
|
|
+ /* 20 */ "flags",
|
|
+ /* 21 */ "schema", /* Used by: table_list */
|
|
+ /* 22 */ "name",
|
|
+ /* 23 */ "type",
|
|
+ /* 24 */ "ncol",
|
|
+ /* 25 */ "wr",
|
|
+ /* 26 */ "strict",
|
|
+ /* 27 */ "seqno", /* Used by: index_xinfo */
|
|
+ /* 28 */ "cid",
|
|
+ /* 29 */ "name",
|
|
+ /* 30 */ "desc",
|
|
+ /* 31 */ "coll",
|
|
+ /* 32 */ "key",
|
|
+ /* 33 */ "seq", /* Used by: index_list */
|
|
+ /* 34 */ "name",
|
|
+ /* 35 */ "unique",
|
|
+ /* 36 */ "origin",
|
|
+ /* 37 */ "partial",
|
|
+ /* 38 */ "tbl", /* Used by: stats */
|
|
+ /* 39 */ "idx",
|
|
+ /* 40 */ "wdth",
|
|
+ /* 41 */ "hght",
|
|
+ /* 42 */ "flgs",
|
|
/* 43 */ "table", /* Used by: foreign_key_check */
|
|
/* 44 */ "rowid",
|
|
/* 45 */ "parent",
|
|
/* 46 */ "fkid",
|
|
- /* index_info reuses 21 */
|
|
- /* 47 */ "seq", /* Used by: database_list */
|
|
- /* 48 */ "name",
|
|
- /* 49 */ "file",
|
|
- /* 50 */ "busy", /* Used by: wal_checkpoint */
|
|
- /* 51 */ "log",
|
|
- /* 52 */ "checkpointed",
|
|
- /* collation_list reuses 38 */
|
|
+ /* 47 */ "busy", /* Used by: wal_checkpoint */
|
|
+ /* 48 */ "log",
|
|
+ /* 49 */ "checkpointed",
|
|
+ /* 50 */ "seq", /* Used by: database_list */
|
|
+ /* 51 */ "name",
|
|
+ /* 52 */ "file",
|
|
+ /* index_info reuses 27 */
|
|
/* 53 */ "database", /* Used by: lock_status */
|
|
/* 54 */ "status",
|
|
+ /* collation_list reuses 33 */
|
|
/* 55 */ "cache_size", /* Used by: default_cache_size */
|
|
/* module_list pragma_list reuses 9 */
|
|
/* 56 */ "timeout", /* Used by: busy_timeout */
|
|
@@ -139266,7 +140226,7 @@
|
|
{/* zName: */ "collation_list",
|
|
/* ePragTyp: */ PragTyp_COLLATION_LIST,
|
|
/* ePragFlg: */ PragFlg_Result0,
|
|
- /* ColNames: */ 38, 2,
|
|
+ /* ColNames: */ 33, 2,
|
|
/* iArg: */ 0 },
|
|
#endif
|
|
#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
|
|
@@ -139301,7 +140261,7 @@
|
|
{/* zName: */ "database_list",
|
|
/* ePragTyp: */ PragTyp_DATABASE_LIST,
|
|
/* ePragFlg: */ PragFlg_Result0,
|
|
- /* ColNames: */ 47, 3,
|
|
+ /* ColNames: */ 50, 3,
|
|
/* iArg: */ 0 },
|
|
#endif
|
|
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
|
|
@@ -139381,7 +140341,7 @@
|
|
{/* zName: */ "function_list",
|
|
/* ePragTyp: */ PragTyp_FUNCTION_LIST,
|
|
/* ePragFlg: */ PragFlg_Result0,
|
|
- /* ColNames: */ 27, 6,
|
|
+ /* ColNames: */ 15, 6,
|
|
/* iArg: */ 0 },
|
|
#endif
|
|
#endif
|
|
@@ -139410,17 +140370,17 @@
|
|
{/* zName: */ "index_info",
|
|
/* ePragTyp: */ PragTyp_INDEX_INFO,
|
|
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
|
- /* ColNames: */ 21, 3,
|
|
+ /* ColNames: */ 27, 3,
|
|
/* iArg: */ 0 },
|
|
{/* zName: */ "index_list",
|
|
/* ePragTyp: */ PragTyp_INDEX_LIST,
|
|
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
|
- /* ColNames: */ 38, 5,
|
|
+ /* ColNames: */ 33, 5,
|
|
/* iArg: */ 0 },
|
|
{/* zName: */ "index_xinfo",
|
|
/* ePragTyp: */ PragTyp_INDEX_INFO,
|
|
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
|
- /* ColNames: */ 21, 6,
|
|
+ /* ColNames: */ 27, 6,
|
|
/* iArg: */ 1 },
|
|
#endif
|
|
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
|
|
@@ -139599,7 +140559,7 @@
|
|
{/* zName: */ "stats",
|
|
/* ePragTyp: */ PragTyp_STATS,
|
|
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
|
|
- /* ColNames: */ 33, 5,
|
|
+ /* ColNames: */ 38, 5,
|
|
/* iArg: */ 0 },
|
|
#endif
|
|
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
|
@@ -139618,7 +140578,7 @@
|
|
{/* zName: */ "table_list",
|
|
/* ePragTyp: */ PragTyp_TABLE_LIST,
|
|
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1,
|
|
- /* ColNames: */ 15, 6,
|
|
+ /* ColNames: */ 21, 6,
|
|
/* iArg: */ 0 },
|
|
{/* zName: */ "table_xinfo",
|
|
/* ePragTyp: */ PragTyp_TABLE_INFO,
|
|
@@ -139695,7 +140655,7 @@
|
|
{/* zName: */ "wal_checkpoint",
|
|
/* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
|
|
/* ePragFlg: */ PragFlg_NeedSchema,
|
|
- /* ColNames: */ 50, 3,
|
|
+ /* ColNames: */ 47, 3,
|
|
/* iArg: */ 0 },
|
|
#endif
|
|
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
|
@@ -139717,7 +140677,7 @@
|
|
** the following macro or to the actual analysis_limit if it is non-zero,
|
|
** in order to prevent PRAGMA optimize from running for too long.
|
|
**
|
|
-** The value of 2000 is chosen emperically so that the worst-case run-time
|
|
+** The value of 2000 is chosen empirically so that the worst-case run-time
|
|
** for PRAGMA optimize does not exceed 100 milliseconds against a variety
|
|
** of test databases on a RaspberryPI-4 compiled using -Os and without
|
|
** -DSQLITE_DEBUG. Of course, your mileage may vary. For the purpose of
|
|
@@ -140834,7 +141794,10 @@
|
|
}
|
|
}else{
|
|
db->flags &= ~mask;
|
|
- if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0;
|
|
+ if( mask==SQLITE_DeferFKs ){
|
|
+ db->nDeferredImmCons = 0;
|
|
+ db->nDeferredCons = 0;
|
|
+ }
|
|
if( (mask & SQLITE_WriteSchema)!=0
|
|
&& sqlite3_stricmp(zRight, "reset")==0
|
|
){
|
|
@@ -144003,7 +144966,7 @@
|
|
pNew->addrOpenEphm[0] = -1;
|
|
pNew->addrOpenEphm[1] = -1;
|
|
pNew->nSelectRow = 0;
|
|
- if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc));
|
|
+ if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, SZ_SRCLIST_1);
|
|
pNew->pSrc = pSrc;
|
|
pNew->pWhere = pWhere;
|
|
pNew->pGroupBy = pGroupBy;
|
|
@@ -144168,10 +145131,33 @@
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3ColumnIndex(Table *pTab, const char *zCol){
|
|
int i;
|
|
- u8 h = sqlite3StrIHash(zCol);
|
|
- Column *pCol;
|
|
- for(pCol=pTab->aCol, i=0; i<pTab->nCol; pCol++, i++){
|
|
- if( pCol->hName==h && sqlite3StrICmp(pCol->zCnName, zCol)==0 ) return i;
|
|
+ u8 h;
|
|
+ const Column *aCol;
|
|
+ int nCol;
|
|
+
|
|
+ h = sqlite3StrIHash(zCol);
|
|
+ aCol = pTab->aCol;
|
|
+ nCol = pTab->nCol;
|
|
+
|
|
+ /* See if the aHx gives us a lucky match */
|
|
+ i = pTab->aHx[h % sizeof(pTab->aHx)];
|
|
+ assert( i<nCol );
|
|
+ if( aCol[i].hName==h
|
|
+ && sqlite3StrICmp(aCol[i].zCnName, zCol)==0
|
|
+ ){
|
|
+ return i;
|
|
+ }
|
|
+
|
|
+ /* No lucky match from the hash table. Do a full search. */
|
|
+ i = 0;
|
|
+ while( 1 /*exit-by-break*/ ){
|
|
+ if( aCol[i].hName==h
|
|
+ && sqlite3StrICmp(aCol[i].zCnName, zCol)==0
|
|
+ ){
|
|
+ return i;
|
|
+ }
|
|
+ i++;
|
|
+ if( i>=nCol ) break;
|
|
}
|
|
return -1;
|
|
}
|
|
@@ -144422,7 +145408,7 @@
|
|
}
|
|
pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iLeftCol);
|
|
sqlite3SrcItemColumnUsed(&pSrc->a[iLeft], iLeftCol);
|
|
- if( (pSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){
|
|
+ if( (pSrc->a[0].fg.jointype & JT_LTORJ)!=0 && pParse->nErr==0 ){
|
|
/* This branch runs if the query contains one or more RIGHT or FULL
|
|
** JOINs. If only a single table on the left side of this join
|
|
** contains the zName column, then this branch is a no-op.
|
|
@@ -144438,6 +145424,8 @@
|
|
*/
|
|
ExprList *pFuncArgs = 0; /* Arguments to the coalesce() */
|
|
static const Token tkCoalesce = { "coalesce", 8 };
|
|
+ assert( pE1!=0 );
|
|
+ ExprSetProperty(pE1, EP_CanBeNull);
|
|
while( tableAndColumnIndex(pSrc, iLeft+1, i, zName, &iLeft, &iLeftCol,
|
|
pRight->fg.isSynthUsing)!=0 ){
|
|
if( pSrc->a[iLeft].fg.isUsing==0
|
|
@@ -144454,7 +145442,13 @@
|
|
if( pFuncArgs ){
|
|
pFuncArgs = sqlite3ExprListAppend(pParse, pFuncArgs, pE1);
|
|
pE1 = sqlite3ExprFunction(pParse, pFuncArgs, &tkCoalesce, 0);
|
|
+ if( pE1 ){
|
|
+ pE1->affExpr = SQLITE_AFF_DEFER;
|
|
+ }
|
|
}
|
|
+ }else if( (pSrc->a[i+1].fg.jointype & JT_LEFT)!=0 && pParse->nErr==0 ){
|
|
+ assert( pE1!=0 );
|
|
+ ExprSetProperty(pE1, EP_CanBeNull);
|
|
}
|
|
pE2 = sqlite3CreateColumnExpr(db, pSrc, i+1, iRightCol);
|
|
sqlite3SrcItemColumnUsed(pRight, iRightCol);
|
|
@@ -145363,8 +146357,8 @@
|
|
** X extra columns.
|
|
*/
|
|
SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
|
|
- int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*);
|
|
- KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra);
|
|
+ int nExtra = (N+X)*(sizeof(CollSeq*)+1);
|
|
+ KeyInfo *p = sqlite3DbMallocRawNN(db, SZ_KEYINFO(0) + nExtra);
|
|
if( p ){
|
|
p->aSortFlags = (u8*)&p->aColl[N+X];
|
|
p->nKeyField = (u16)N;
|
|
@@ -145372,7 +146366,7 @@
|
|
p->enc = ENC(db);
|
|
p->db = db;
|
|
p->nRef = 1;
|
|
- memset(&p[1], 0, nExtra);
|
|
+ memset(p->aColl, 0, nExtra);
|
|
}else{
|
|
return (KeyInfo*)sqlite3OomFault(db);
|
|
}
|
|
@@ -147073,6 +148067,7 @@
|
|
multi_select_end:
|
|
pDest->iSdst = dest.iSdst;
|
|
pDest->nSdst = dest.nSdst;
|
|
+ pDest->iSDParm2 = dest.iSDParm2;
|
|
if( pDelete ){
|
|
sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pDelete);
|
|
}
|
|
@@ -148061,9 +149056,9 @@
|
|
** from 2015-02-09.)
|
|
**
|
|
** (3) If the subquery is the right operand of a LEFT JOIN then
|
|
-** (3a) the subquery may not be a join and
|
|
-** (3b) the FROM clause of the subquery may not contain a virtual
|
|
-** table and
|
|
+** (3a) the subquery may not be a join
|
|
+** (**) Was (3b): "the FROM clause of the subquery may not contain
|
|
+** a virtual table"
|
|
** (**) Was: "The outer query may not have a GROUP BY." This case
|
|
** is now managed correctly
|
|
** (3d) the outer query may not be DISTINCT.
|
|
@@ -148279,7 +149274,7 @@
|
|
*/
|
|
if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){
|
|
if( pSubSrc->nSrc>1 /* (3a) */
|
|
- || IsVirtual(pSubSrc->a[0].pSTab) /* (3b) */
|
|
+ /**** || IsVirtual(pSubSrc->a[0].pSTab) (3b)-omitted */
|
|
|| (p->selFlags & SF_Distinct)!=0 /* (3d) */
|
|
|| (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */
|
|
){
|
|
@@ -148683,7 +149678,8 @@
|
|
return; /* Already present. Return without doing anything. */
|
|
}
|
|
}
|
|
- if( sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){
|
|
+ assert( SQLITE_AFF_NONE<SQLITE_AFF_BLOB );
|
|
+ if( sqlite3ExprAffinity(pColumn)<=SQLITE_AFF_BLOB ){
|
|
pConst->bHasAffBlob = 1;
|
|
}
|
|
|
|
@@ -148758,7 +149754,8 @@
|
|
if( pColumn==pExpr ) continue;
|
|
if( pColumn->iTable!=pExpr->iTable ) continue;
|
|
if( pColumn->iColumn!=pExpr->iColumn ) continue;
|
|
- if( bIgnoreAffBlob && sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){
|
|
+ assert( SQLITE_AFF_NONE<SQLITE_AFF_BLOB );
|
|
+ if( bIgnoreAffBlob && sqlite3ExprAffinity(pColumn)<=SQLITE_AFF_BLOB ){
|
|
break;
|
|
}
|
|
/* A match is found. Add the EP_FixedCol property */
|
|
@@ -149411,7 +150408,7 @@
|
|
** above that generates the code for a compound SELECT with an ORDER BY clause
|
|
** uses a merge algorithm that requires the same collating sequence on the
|
|
** result columns as on the ORDER BY clause. See ticket
|
|
-** http://www.sqlite.org/src/info/6709574d2a
|
|
+** http://sqlite.org/src/info/6709574d2a
|
|
**
|
|
** This transformation is only needed for EXCEPT, INTERSECT, and UNION.
|
|
** The UNION ALL operator works fine with multiSelectOrderBy() even when
|
|
@@ -149472,7 +150469,7 @@
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
p->pWinDefn = 0;
|
|
#endif
|
|
- p->selFlags &= ~SF_Compound;
|
|
+ p->selFlags &= ~(u32)SF_Compound;
|
|
assert( (p->selFlags & SF_Converted)==0 );
|
|
p->selFlags |= SF_Converted;
|
|
assert( pNew->pPrior!=0 );
|
|
@@ -149888,7 +150885,7 @@
|
|
pEList = p->pEList;
|
|
if( pParse->pWith && (p->selFlags & SF_View) ){
|
|
if( p->pWith==0 ){
|
|
- p->pWith = (With*)sqlite3DbMallocZero(db, sizeof(With));
|
|
+ p->pWith = (With*)sqlite3DbMallocZero(db, SZ_WITH(1) );
|
|
if( p->pWith==0 ){
|
|
return WRC_Abort;
|
|
}
|
|
@@ -151027,6 +152024,7 @@
|
|
** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries
|
|
** * The outer query is a simple count(*) with no WHERE clause or other
|
|
** extraneous syntax.
|
|
+** * None of the subqueries are DISTINCT (forumpost/a860f5fb2e 2025-03-10)
|
|
**
|
|
** Return TRUE if the optimization is undertaken.
|
|
*/
|
|
@@ -151059,7 +152057,11 @@
|
|
if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */
|
|
if( pSub->pWhere ) return 0; /* No WHERE clause */
|
|
if( pSub->pLimit ) return 0; /* No LIMIT clause */
|
|
- if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */
|
|
+ if( pSub->selFlags & (SF_Aggregate|SF_Distinct) ){
|
|
+ testcase( pSub->selFlags & SF_Aggregate );
|
|
+ testcase( pSub->selFlags & SF_Distinct );
|
|
+ return 0; /* Not an aggregate nor DISTINCT */
|
|
+ }
|
|
assert( pSub->pHaving==0 ); /* Due to the previous */
|
|
pSub = pSub->pPrior; /* Repeat over compound */
|
|
}while( pSub );
|
|
@@ -151071,14 +152073,14 @@
|
|
pExpr = 0;
|
|
pSub = sqlite3SubqueryDetach(db, pFrom);
|
|
sqlite3SrcListDelete(db, p->pSrc);
|
|
- p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc));
|
|
+ p->pSrc = sqlite3DbMallocZero(pParse->db, SZ_SRCLIST_1);
|
|
while( pSub ){
|
|
Expr *pTerm;
|
|
pPrior = pSub->pPrior;
|
|
pSub->pPrior = 0;
|
|
pSub->pNext = 0;
|
|
pSub->selFlags |= SF_Aggregate;
|
|
- pSub->selFlags &= ~SF_Compound;
|
|
+ pSub->selFlags &= ~(u32)SF_Compound;
|
|
pSub->nSelectRow = 0;
|
|
sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pSub->pEList);
|
|
pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount;
|
|
@@ -151093,7 +152095,7 @@
|
|
pSub = pPrior;
|
|
}
|
|
p->pEList->a[0].pExpr = pExpr;
|
|
- p->selFlags &= ~SF_Aggregate;
|
|
+ p->selFlags &= ~(u32)SF_Aggregate;
|
|
|
|
#if TREETRACE_ENABLED
|
|
if( sqlite3TreeTrace & 0x200 ){
|
|
@@ -151300,7 +152302,7 @@
|
|
testcase( pParse->earlyCleanup );
|
|
p->pOrderBy = 0;
|
|
}
|
|
- p->selFlags &= ~SF_Distinct;
|
|
+ p->selFlags &= ~(u32)SF_Distinct;
|
|
p->selFlags |= SF_NoopOrderBy;
|
|
}
|
|
sqlite3SelectPrep(pParse, p, 0);
|
|
@@ -151339,7 +152341,7 @@
|
|
** and leaving this flag set can cause errors if a compound sub-query
|
|
** in p->pSrc is flattened into this query and this function called
|
|
** again as part of compound SELECT processing. */
|
|
- p->selFlags &= ~SF_UFSrcCheck;
|
|
+ p->selFlags &= ~(u32)SF_UFSrcCheck;
|
|
}
|
|
|
|
if( pDest->eDest==SRT_Output ){
|
|
@@ -151828,7 +152830,7 @@
|
|
&& p->pWin==0
|
|
#endif
|
|
){
|
|
- p->selFlags &= ~SF_Distinct;
|
|
+ p->selFlags &= ~(u32)SF_Distinct;
|
|
pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0);
|
|
if( pGroupBy ){
|
|
for(i=0; i<pGroupBy->nExpr; i++){
|
|
@@ -151937,6 +152939,12 @@
|
|
if( pWInfo==0 ) goto select_end;
|
|
if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
|
|
p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
|
|
+ if( pDest->eDest<=SRT_DistQueue && pDest->eDest>=SRT_DistFifo ){
|
|
+ /* TUNING: For a UNION CTE, because UNION is implies DISTINCT,
|
|
+ ** reduce the estimated output row count by 8 (LogEst 30).
|
|
+ ** Search for tag-20250414a to see other cases */
|
|
+ p->nSelectRow -= 30;
|
|
+ }
|
|
}
|
|
if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){
|
|
sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo);
|
|
@@ -152310,6 +153318,10 @@
|
|
if( iOrderByCol ){
|
|
Expr *pX = p->pEList->a[iOrderByCol-1].pExpr;
|
|
Expr *pBase = sqlite3ExprSkipCollateAndLikely(pX);
|
|
+ while( ALWAYS(pBase!=0) && pBase->op==TK_IF_NULL_ROW ){
|
|
+ pX = pBase->pLeft;
|
|
+ pBase = sqlite3ExprSkipCollateAndLikely(pX);
|
|
+ }
|
|
if( ALWAYS(pBase!=0)
|
|
&& pBase->op!=TK_AGG_COLUMN
|
|
&& pBase->op!=TK_REGISTER
|
|
@@ -152893,7 +153905,8 @@
|
|
assert( pParse->db->pVtabCtx==0 );
|
|
#endif
|
|
assert( pParse->bReturning );
|
|
- assert( &(pParse->u1.pReturning->retTrig) == pTrig );
|
|
+ assert( !pParse->isCreate );
|
|
+ assert( &(pParse->u1.d.pReturning->retTrig) == pTrig );
|
|
pTrig->table = pTab->zName;
|
|
pTrig->pTabSchema = pTab->pSchema;
|
|
pTrig->pNext = pList;
|
|
@@ -153861,7 +154874,8 @@
|
|
ExprList *pNew;
|
|
Returning *pReturning;
|
|
Select sSelect;
|
|
- SrcList sFrom;
|
|
+ SrcList *pFrom;
|
|
+ u8 fromSpace[SZ_SRCLIST_1];
|
|
|
|
assert( v!=0 );
|
|
if( !pParse->bReturning ){
|
|
@@ -153870,19 +154884,21 @@
|
|
return;
|
|
}
|
|
assert( db->pParse==pParse );
|
|
- pReturning = pParse->u1.pReturning;
|
|
+ assert( !pParse->isCreate );
|
|
+ pReturning = pParse->u1.d.pReturning;
|
|
if( pTrigger != &(pReturning->retTrig) ){
|
|
/* This RETURNING trigger is for a different statement */
|
|
return;
|
|
}
|
|
memset(&sSelect, 0, sizeof(sSelect));
|
|
- memset(&sFrom, 0, sizeof(sFrom));
|
|
+ pFrom = (SrcList*)fromSpace;
|
|
+ memset(pFrom, 0, SZ_SRCLIST_1);
|
|
sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0);
|
|
- sSelect.pSrc = &sFrom;
|
|
- sFrom.nSrc = 1;
|
|
- sFrom.a[0].pSTab = pTab;
|
|
- sFrom.a[0].zName = pTab->zName; /* tag-20240424-1 */
|
|
- sFrom.a[0].iCursor = -1;
|
|
+ sSelect.pSrc = pFrom;
|
|
+ pFrom->nSrc = 1;
|
|
+ pFrom->a[0].pSTab = pTab;
|
|
+ pFrom->a[0].zName = pTab->zName; /* tag-20240424-1 */
|
|
+ pFrom->a[0].iCursor = -1;
|
|
sqlite3SelectPrep(pParse, &sSelect, 0);
|
|
if( pParse->nErr==0 ){
|
|
assert( db->mallocFailed==0 );
|
|
@@ -154100,6 +155116,8 @@
|
|
sSubParse.eTriggerOp = pTrigger->op;
|
|
sSubParse.nQueryLoop = pParse->nQueryLoop;
|
|
sSubParse.prepFlags = pParse->prepFlags;
|
|
+ sSubParse.oldmask = 0;
|
|
+ sSubParse.newmask = 0;
|
|
|
|
v = sqlite3GetVdbe(&sSubParse);
|
|
if( v ){
|
|
@@ -154854,38 +155872,32 @@
|
|
*/
|
|
chngRowid = chngPk = 0;
|
|
for(i=0; i<pChanges->nExpr; i++){
|
|
- u8 hCol = sqlite3StrIHash(pChanges->a[i].zEName);
|
|
/* If this is an UPDATE with a FROM clause, do not resolve expressions
|
|
** here. The call to sqlite3Select() below will do that. */
|
|
if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){
|
|
goto update_cleanup;
|
|
}
|
|
- for(j=0; j<pTab->nCol; j++){
|
|
- if( pTab->aCol[j].hName==hCol
|
|
- && sqlite3StrICmp(pTab->aCol[j].zCnName, pChanges->a[i].zEName)==0
|
|
- ){
|
|
- if( j==pTab->iPKey ){
|
|
- chngRowid = 1;
|
|
- pRowidExpr = pChanges->a[i].pExpr;
|
|
- iRowidExpr = i;
|
|
- }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){
|
|
- chngPk = 1;
|
|
- }
|
|
+ j = sqlite3ColumnIndex(pTab, pChanges->a[i].zEName);
|
|
+ if( j>=0 ){
|
|
+ if( j==pTab->iPKey ){
|
|
+ chngRowid = 1;
|
|
+ pRowidExpr = pChanges->a[i].pExpr;
|
|
+ iRowidExpr = i;
|
|
+ }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){
|
|
+ chngPk = 1;
|
|
+ }
|
|
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
|
- else if( pTab->aCol[j].colFlags & COLFLAG_GENERATED ){
|
|
- testcase( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL );
|
|
- testcase( pTab->aCol[j].colFlags & COLFLAG_STORED );
|
|
- sqlite3ErrorMsg(pParse,
|
|
- "cannot UPDATE generated column \"%s\"",
|
|
- pTab->aCol[j].zCnName);
|
|
- goto update_cleanup;
|
|
- }
|
|
-#endif
|
|
- aXRef[j] = i;
|
|
- break;
|
|
+ else if( pTab->aCol[j].colFlags & COLFLAG_GENERATED ){
|
|
+ testcase( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL );
|
|
+ testcase( pTab->aCol[j].colFlags & COLFLAG_STORED );
|
|
+ sqlite3ErrorMsg(pParse,
|
|
+ "cannot UPDATE generated column \"%s\"",
|
|
+ pTab->aCol[j].zCnName);
|
|
+ goto update_cleanup;
|
|
}
|
|
- }
|
|
- if( j>=pTab->nCol ){
|
|
+#endif
|
|
+ aXRef[j] = i;
|
|
+ }else{
|
|
if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zEName) ){
|
|
j = -1;
|
|
chngRowid = 1;
|
|
@@ -156208,7 +157220,7 @@
|
|
#else
|
|
/* When SQLITE_BUG_COMPATIBLE_20160819 is defined, unrecognized arguments
|
|
** to VACUUM are silently ignored. This is a back-out of a bug fix that
|
|
- ** occurred on 2016-08-19 (https://www.sqlite.org/src/info/083f9e6270).
|
|
+ ** occurred on 2016-08-19 (https://sqlite.org/src/info/083f9e6270).
|
|
** The buggy behavior is required for binary compatibility with some
|
|
** legacy applications. */
|
|
iDb = sqlite3FindDb(pParse->db, pNm);
|
|
@@ -156287,7 +157299,7 @@
|
|
saved_nChange = db->nChange;
|
|
saved_nTotalChange = db->nTotalChange;
|
|
saved_mTrace = db->mTrace;
|
|
- db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
|
|
+ db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_Comments;
|
|
db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
|
|
db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder
|
|
| SQLITE_Defensive | SQLITE_CountRows);
|
|
@@ -156992,11 +158004,12 @@
|
|
** schema table. We just need to update that slot with all
|
|
** the information we've collected.
|
|
**
|
|
- ** The VM register number pParse->regRowid holds the rowid of an
|
|
+ ** The VM register number pParse->u1.cr.regRowid holds the rowid of an
|
|
** entry in the sqlite_schema table that was created for this vtab
|
|
** by sqlite3StartTable().
|
|
*/
|
|
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
+ assert( pParse->isCreate );
|
|
sqlite3NestedParse(pParse,
|
|
"UPDATE %Q." LEGACY_SCHEMA_TABLE " "
|
|
"SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q "
|
|
@@ -157005,7 +158018,7 @@
|
|
pTab->zName,
|
|
pTab->zName,
|
|
zStmt,
|
|
- pParse->regRowid
|
|
+ pParse->u1.cr.regRowid
|
|
);
|
|
v = sqlite3GetVdbe(pParse);
|
|
sqlite3ChangeCookie(pParse, iDb);
|
|
@@ -158415,10 +159428,15 @@
|
|
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
|
|
WhereClause sWC; /* Decomposition of the WHERE clause */
|
|
WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */
|
|
- WhereLevel a[1]; /* Information about each nest loop in WHERE */
|
|
+ WhereLevel a[FLEXARRAY]; /* Information about each nest loop in WHERE */
|
|
};
|
|
|
|
/*
|
|
+** The size (in bytes) of a WhereInfo object that holds N WhereLevels.
|
|
+*/
|
|
+#define SZ_WHEREINFO(N) ROUND8(offsetof(WhereInfo,a)+(N)*sizeof(WhereLevel))
|
|
+
|
|
+/*
|
|
** Private interfaces - callable only by other where.c routines.
|
|
**
|
|
** where.c:
|
|
@@ -159097,7 +160115,7 @@
|
|
/*
|
|
** pX is an expression of the form: (vector) IN (SELECT ...)
|
|
** In other words, it is a vector IN operator with a SELECT clause on the
|
|
-** LHS. But not all terms in the vector are indexable and the terms might
|
|
+** RHS. But not all terms in the vector are indexable and the terms might
|
|
** not be in the correct order for indexing.
|
|
**
|
|
** This routine makes a copy of the input pX expression and then adjusts
|
|
@@ -159153,7 +160171,9 @@
|
|
int iField;
|
|
assert( (pLoop->aLTerm[i]->eOperator & (WO_OR|WO_AND))==0 );
|
|
iField = pLoop->aLTerm[i]->u.x.iField - 1;
|
|
- if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */
|
|
+ if( NEVER(pOrigRhs->a[iField].pExpr==0) ){
|
|
+ continue; /* Duplicate PK column */
|
|
+ }
|
|
pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr);
|
|
pOrigRhs->a[iField].pExpr = 0;
|
|
if( pRhs ) pRhs->a[pRhs->nExpr-1].u.x.iOrderByCol = iField+1;
|
|
@@ -159250,7 +160270,7 @@
|
|
return;
|
|
}
|
|
}
|
|
- for(i=iEq;i<pLoop->nLTerm; i++){
|
|
+ for(i=iEq; i<pLoop->nLTerm; i++){
|
|
assert( pLoop->aLTerm[i]!=0 );
|
|
if( pLoop->aLTerm[i]->pExpr==pX ) nEq++;
|
|
}
|
|
@@ -159259,22 +160279,13 @@
|
|
if( !ExprUseXSelect(pX) || pX->x.pSelect->pEList->nExpr==1 ){
|
|
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab);
|
|
}else{
|
|
- Expr *pExpr = pTerm->pExpr;
|
|
- if( pExpr->iTable==0 || !ExprHasProperty(pExpr, EP_Subrtn) ){
|
|
- sqlite3 *db = pParse->db;
|
|
- pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
|
|
- if( !db->mallocFailed ){
|
|
- aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
|
|
- eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap,&iTab);
|
|
- pExpr->iTable = iTab;
|
|
- }
|
|
- sqlite3ExprDelete(db, pX);
|
|
- }else{
|
|
- int n = sqlite3ExprVectorSize(pX->pLeft);
|
|
- aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*MAX(nEq,n));
|
|
- eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab);
|
|
+ sqlite3 *db = pParse->db;
|
|
+ Expr *pXMod = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
|
|
+ if( !db->mallocFailed ){
|
|
+ aiMap = (int*)sqlite3DbMallocZero(db, sizeof(int)*nEq);
|
|
+ eType = sqlite3FindInIndex(pParse, pXMod, IN_INDEX_LOOP, 0, aiMap, &iTab);
|
|
}
|
|
- pX = pExpr;
|
|
+ sqlite3ExprDelete(db, pXMod);
|
|
}
|
|
|
|
if( eType==IN_INDEX_INDEX_DESC ){
|
|
@@ -159304,7 +160315,7 @@
|
|
if( pIn ){
|
|
int iMap = 0; /* Index in aiMap[] */
|
|
pIn += i;
|
|
- for(i=iEq;i<pLoop->nLTerm; i++){
|
|
+ for(i=iEq; i<pLoop->nLTerm; i++){
|
|
if( pLoop->aLTerm[i]->pExpr==pX ){
|
|
int iOut = iTarget + i - iEq;
|
|
if( eType==IN_INDEX_ROWID ){
|
|
@@ -160163,6 +161174,9 @@
|
|
}
|
|
sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg);
|
|
sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1);
|
|
+ /* The instruction immediately prior to OP_VFilter must be an OP_Integer
|
|
+ ** that sets the "argc" value for xVFilter. This is necessary for
|
|
+ ** resolveP2() to work correctly. See tag-20250207a. */
|
|
sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg,
|
|
pLoop->u.vtab.idxStr,
|
|
pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC);
|
|
@@ -160753,12 +161767,13 @@
|
|
if( pLevel->iLeftJoin==0 ){
|
|
/* If a partial index is driving the loop, try to eliminate WHERE clause
|
|
** terms from the query that must be true due to the WHERE clause of
|
|
- ** the partial index.
|
|
+ ** the partial index. This optimization does not work on an outer join,
|
|
+ ** as shown by:
|
|
**
|
|
- ** 2019-11-02 ticket 623eff57e76d45f6: This optimization does not work
|
|
- ** for a LEFT JOIN.
|
|
+ ** 2019-11-02 ticket 623eff57e76d45f6 (LEFT JOIN)
|
|
+ ** 2025-05-29 forum post 7dee41d32506c4ae (RIGHT JOIN)
|
|
*/
|
|
- if( pIdx->pPartIdxWhere ){
|
|
+ if( pIdx->pPartIdxWhere && pLevel->pRJ==0 ){
|
|
whereApplyPartialIndexConstraints(pIdx->pPartIdxWhere, iCur, pWC);
|
|
}
|
|
}else{
|
|
@@ -160865,8 +161880,7 @@
|
|
int nNotReady; /* The number of notReady tables */
|
|
SrcItem *origSrc; /* Original list of tables */
|
|
nNotReady = pWInfo->nLevel - iLevel - 1;
|
|
- pOrTab = sqlite3DbMallocRawNN(db,
|
|
- sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0]));
|
|
+ pOrTab = sqlite3DbMallocRawNN(db, SZ_SRCLIST(nNotReady+1));
|
|
if( pOrTab==0 ) return notReady;
|
|
pOrTab->nAlloc = (u8)(nNotReady + 1);
|
|
pOrTab->nSrc = pOrTab->nAlloc;
|
|
@@ -160917,7 +161931,7 @@
|
|
**
|
|
** This optimization also only applies if the (x1 OR x2 OR ...) term
|
|
** is not contained in the ON clause of a LEFT JOIN.
|
|
- ** See ticket http://www.sqlite.org/src/info/f2369304e4
|
|
+ ** See ticket http://sqlite.org/src/info/f2369304e4
|
|
**
|
|
** 2022-02-04: Do not push down slices of a row-value comparison.
|
|
** In other words, "w" or "y" may not be a slice of a vector. Otherwise,
|
|
@@ -161409,7 +162423,8 @@
|
|
WhereInfo *pSubWInfo;
|
|
WhereLoop *pLoop = pLevel->pWLoop;
|
|
SrcItem *pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
|
|
- SrcList sFrom;
|
|
+ SrcList *pFrom;
|
|
+ u8 fromSpace[SZ_SRCLIST_1];
|
|
Bitmask mAll = 0;
|
|
int k;
|
|
|
|
@@ -161453,13 +162468,14 @@
|
|
sqlite3ExprDup(pParse->db, pTerm->pExpr, 0));
|
|
}
|
|
}
|
|
- sFrom.nSrc = 1;
|
|
- sFrom.nAlloc = 1;
|
|
- memcpy(&sFrom.a[0], pTabItem, sizeof(SrcItem));
|
|
- sFrom.a[0].fg.jointype = 0;
|
|
+ pFrom = (SrcList*)fromSpace;
|
|
+ pFrom->nSrc = 1;
|
|
+ pFrom->nAlloc = 1;
|
|
+ memcpy(&pFrom->a[0], pTabItem, sizeof(SrcItem));
|
|
+ pFrom->a[0].fg.jointype = 0;
|
|
assert( pParse->withinRJSubrtn < 100 );
|
|
pParse->withinRJSubrtn++;
|
|
- pSubWInfo = sqlite3WhereBegin(pParse, &sFrom, pSubWhere, 0, 0, 0,
|
|
+ pSubWInfo = sqlite3WhereBegin(pParse, pFrom, pSubWhere, 0, 0, 0,
|
|
WHERE_RIGHT_JOIN, 0);
|
|
if( pSubWInfo ){
|
|
int iCur = pLevel->iTabCur;
|
|
@@ -162430,30 +163446,42 @@
|
|
** 1. The SQLITE_Transitive optimization must be enabled
|
|
** 2. Must be either an == or an IS operator
|
|
** 3. Not originating in the ON clause of an OUTER JOIN
|
|
-** 4. The affinities of A and B must be compatible
|
|
-** 5a. Both operands use the same collating sequence OR
|
|
-** 5b. The overall collating sequence is BINARY
|
|
+** 4. The operator is not IS or else the query does not contain RIGHT JOIN
|
|
+** 5. The affinities of A and B must be compatible
|
|
+** 6a. Both operands use the same collating sequence OR
|
|
+** 6b. The overall collating sequence is BINARY
|
|
** If this routine returns TRUE, that means that the RHS can be substituted
|
|
** for the LHS anyplace else in the WHERE clause where the LHS column occurs.
|
|
** This is an optimization. No harm comes from returning 0. But if 1 is
|
|
** returned when it should not be, then incorrect answers might result.
|
|
*/
|
|
-static int termIsEquivalence(Parse *pParse, Expr *pExpr){
|
|
+static int termIsEquivalence(Parse *pParse, Expr *pExpr, SrcList *pSrc){
|
|
char aff1, aff2;
|
|
CollSeq *pColl;
|
|
- if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0;
|
|
- if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0;
|
|
- if( ExprHasProperty(pExpr, EP_OuterON) ) return 0;
|
|
+ if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0; /* (1) */
|
|
+ if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0; /* (2) */
|
|
+ if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* (3) */
|
|
+ assert( pSrc!=0 );
|
|
+ if( pExpr->op==TK_IS
|
|
+ && pSrc->nSrc
|
|
+ && (pSrc->a[0].fg.jointype & JT_LTORJ)!=0
|
|
+ ){
|
|
+ return 0; /* (4) */
|
|
+ }
|
|
aff1 = sqlite3ExprAffinity(pExpr->pLeft);
|
|
aff2 = sqlite3ExprAffinity(pExpr->pRight);
|
|
if( aff1!=aff2
|
|
&& (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2))
|
|
){
|
|
- return 0;
|
|
+ return 0; /* (5) */
|
|
}
|
|
pColl = sqlite3ExprCompareCollSeq(pParse, pExpr);
|
|
- if( sqlite3IsBinary(pColl) ) return 1;
|
|
- return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight);
|
|
+ if( !sqlite3IsBinary(pColl)
|
|
+ && !sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight)
|
|
+ ){
|
|
+ return 0; /* (6) */
|
|
+ }
|
|
+ return 1;
|
|
}
|
|
|
|
/*
|
|
@@ -162718,8 +163746,8 @@
|
|
if( op==TK_IS ) pNew->wtFlags |= TERM_IS;
|
|
pTerm = &pWC->a[idxTerm];
|
|
pTerm->wtFlags |= TERM_COPIED;
|
|
-
|
|
- if( termIsEquivalence(pParse, pDup) ){
|
|
+ assert( pWInfo->pTabList!=0 );
|
|
+ if( termIsEquivalence(pParse, pDup, pWInfo->pTabList) ){
|
|
pTerm->eOperator |= WO_EQUIV;
|
|
eExtraOp = WO_EQUIV;
|
|
}
|
|
@@ -163447,11 +164475,16 @@
|
|
int eDistinct; /* Value to return from sqlite3_vtab_distinct() */
|
|
u32 mIn; /* Mask of terms that are <col> IN (...) */
|
|
u32 mHandleIn; /* Terms that vtab will handle as <col> IN (...) */
|
|
- sqlite3_value *aRhs[1]; /* RHS values for constraints. MUST BE LAST
|
|
- ** because extra space is allocated to hold up
|
|
- ** to nTerm such values */
|
|
+ sqlite3_value *aRhs[FLEXARRAY]; /* RHS values for constraints. MUST BE LAST
|
|
+ ** Extra space is allocated to hold up
|
|
+ ** to nTerm such values */
|
|
};
|
|
|
|
+/* Size (in bytes) of a HiddenIndeInfo object sufficient to hold as
|
|
+** many as N constraints */
|
|
+#define SZ_HIDDENINDEXINFO(N) \
|
|
+ (offsetof(HiddenIndexInfo,aRhs) + (N)*sizeof(sqlite3_value*))
|
|
+
|
|
/* Forward declaration of methods */
|
|
static int whereLoopResize(sqlite3*, WhereLoop*, int);
|
|
|
|
@@ -164516,6 +165549,8 @@
|
|
}
|
|
|
|
/* Construct the Index object to describe this index */
|
|
+ assert( nKeyCol <= pTable->nCol + MAX(0, pTable->nCol - BMS + 1) );
|
|
+ /* ^-- This guarantees that the number of index columns will fit in the u16 */
|
|
pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+HasRowid(pTable),
|
|
0, &zNotUsed);
|
|
if( pIdx==0 ) goto end_auto_index_create;
|
|
@@ -164927,8 +165962,8 @@
|
|
*/
|
|
pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo)
|
|
+ (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
|
|
- + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden)
|
|
- + sizeof(sqlite3_value*)*nTerm );
|
|
+ + sizeof(*pIdxOrderBy)*nOrderBy
|
|
+ + SZ_HIDDENINDEXINFO(nTerm) );
|
|
if( pIdxInfo==0 ){
|
|
sqlite3ErrorMsg(pParse, "out of memory");
|
|
return 0;
|
|
@@ -166564,11 +167599,8 @@
|
|
assert( pNew->u.btree.nBtm==0 );
|
|
opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS;
|
|
}
|
|
- if( pProbe->bUnordered || pProbe->bLowQual ){
|
|
- if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
|
|
- if( pProbe->bLowQual && pSrc->fg.isIndexedBy==0 ){
|
|
- opMask &= ~(WO_EQ|WO_IN|WO_IS);
|
|
- }
|
|
+ if( pProbe->bUnordered ){
|
|
+ opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
|
|
}
|
|
|
|
assert( pNew->u.btree.nEq<pProbe->nColumn );
|
|
@@ -166641,6 +167673,7 @@
|
|
if( ExprUseXSelect(pExpr) ){
|
|
/* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */
|
|
int i;
|
|
+ int bRedundant = 0;
|
|
nIn = 46; assert( 46==sqlite3LogEst(25) );
|
|
|
|
/* The expression may actually be of the form (x, y) IN (SELECT...).
|
|
@@ -166649,7 +167682,20 @@
|
|
** for each such term. The following loop checks that pTerm is the
|
|
** first such term in use, and sets nIn back to 0 if it is not. */
|
|
for(i=0; i<pNew->nLTerm-1; i++){
|
|
- if( pNew->aLTerm[i] && pNew->aLTerm[i]->pExpr==pExpr ) nIn = 0;
|
|
+ if( pNew->aLTerm[i] && pNew->aLTerm[i]->pExpr==pExpr ){
|
|
+ nIn = 0;
|
|
+ if( pNew->aLTerm[i]->u.x.iField == pTerm->u.x.iField ){
|
|
+ /* Detect when two or more columns of an index match the same
|
|
+ ** column of a vector IN operater, and avoid adding the column
|
|
+ ** to the WhereLoop more than once. See tag-20250707-01
|
|
+ ** in test/rowvalue.test */
|
|
+ bRedundant = 1;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if( bRedundant ){
|
|
+ pNew->nLTerm--;
|
|
+ continue;
|
|
}
|
|
}else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
|
|
/* "x IN (value, value, ...)" */
|
|
@@ -166881,7 +167927,7 @@
|
|
if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0
|
|
&& pNew->u.btree.nEq<pProbe->nColumn
|
|
&& (pNew->u.btree.nEq<pProbe->nKeyCol ||
|
|
- pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY)
|
|
+ pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY)
|
|
){
|
|
if( pNew->u.btree.nEq>3 ){
|
|
sqlite3ProgressCheck(pParse);
|
|
@@ -167010,6 +168056,7 @@
|
|
if( (!ExprHasProperty(pExpr, EP_OuterON) || pExpr->w.iJoin==iTab)
|
|
&& ((jointype & JT_OUTER)==0 || ExprHasProperty(pExpr, EP_OuterON))
|
|
&& sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab)
|
|
+ && !sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, -1)
|
|
&& (pTerm->wtFlags & TERM_VNULL)==0
|
|
){
|
|
return 1;
|
|
@@ -167505,7 +168552,7 @@
|
|
&& (HasRowid(pTab) || pWInfo->pSelect!=0 || sqlite3FaultSim(700))
|
|
){
|
|
WHERETRACE(0x200,
|
|
- ("-> %s a covering index according to bitmasks\n",
|
|
+ ("-> %s is a covering index according to bitmasks\n",
|
|
pProbe->zName, m==0 ? "is" : "is not"));
|
|
pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
|
|
}
|
|
@@ -170122,10 +171169,7 @@
|
|
** field (type Bitmask) it must be aligned on an 8-byte boundary on
|
|
** some architectures. Hence the ROUND8() below.
|
|
*/
|
|
- nByteWInfo = ROUND8P(sizeof(WhereInfo));
|
|
- if( nTabList>1 ){
|
|
- nByteWInfo = ROUND8P(nByteWInfo + (nTabList-1)*sizeof(WhereLevel));
|
|
- }
|
|
+ nByteWInfo = SZ_WHEREINFO(nTabList);
|
|
pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop));
|
|
if( db->mallocFailed ){
|
|
sqlite3DbFree(db, pWInfo);
|
|
@@ -170342,7 +171386,8 @@
|
|
}
|
|
|
|
/* TUNING: Assume that a DISTINCT clause on a subquery reduces
|
|
- ** the output size by a factor of 8 (LogEst -30).
|
|
+ ** the output size by a factor of 8 (LogEst -30). Search for
|
|
+ ** tag-20250414a to see other cases.
|
|
*/
|
|
if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)!=0 ){
|
|
WHERETRACE(0x0080,("nRowOut reduced from %d to %d due to DISTINCT\n",
|
|
@@ -172077,7 +173122,7 @@
|
|
p->pWhere = 0;
|
|
p->pGroupBy = 0;
|
|
p->pHaving = 0;
|
|
- p->selFlags &= ~SF_Aggregate;
|
|
+ p->selFlags &= ~(u32)SF_Aggregate;
|
|
p->selFlags |= SF_WinRewrite;
|
|
|
|
/* Create the ORDER BY clause for the sub-select. This is the concatenation
|
|
@@ -174218,6 +175263,11 @@
|
|
/* #include "sqliteInt.h" */
|
|
|
|
/*
|
|
+** Verify that the pParse->isCreate field is set
|
|
+*/
|
|
+#define ASSERT_IS_CREATE assert(pParse->isCreate)
|
|
+
|
|
+/*
|
|
** Disable all error recovery processing in the parser push-down
|
|
** automaton.
|
|
*/
|
|
@@ -174280,6 +175330,10 @@
|
|
static void disableLookaside(Parse *pParse){
|
|
sqlite3 *db = pParse->db;
|
|
pParse->disableLookaside++;
|
|
+#ifdef SQLITE_DEBUG
|
|
+ pParse->isCreate = 1;
|
|
+#endif
|
|
+ memset(&pParse->u1.cr, 0, sizeof(pParse->u1.cr));
|
|
DisableLookaside;
|
|
}
|
|
|
|
@@ -177916,7 +178970,9 @@
|
|
}
|
|
break;
|
|
case 14: /* createkw ::= CREATE */
|
|
-{disableLookaside(pParse);}
|
|
+{
|
|
+ disableLookaside(pParse);
|
|
+}
|
|
break;
|
|
case 15: /* ifnotexists ::= */
|
|
case 18: /* temp ::= */ yytestcase(yyruleno==18);
|
|
@@ -178008,7 +179064,7 @@
|
|
break;
|
|
case 32: /* ccons ::= CONSTRAINT nm */
|
|
case 67: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==67);
|
|
-{pParse->constraintName = yymsp[0].minor.yy0;}
|
|
+{ASSERT_IS_CREATE; pParse->u1.cr.constraintName = yymsp[0].minor.yy0;}
|
|
break;
|
|
case 33: /* ccons ::= DEFAULT scantok term */
|
|
{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy590,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
|
|
@@ -178118,7 +179174,7 @@
|
|
{yymsp[-1].minor.yy502 = 0;}
|
|
break;
|
|
case 66: /* tconscomma ::= COMMA */
|
|
-{pParse->constraintName.n = 0;}
|
|
+{ASSERT_IS_CREATE; pParse->u1.cr.constraintName.n = 0;}
|
|
break;
|
|
case 68: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
|
|
{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy402,yymsp[0].minor.yy502,yymsp[-2].minor.yy502,0);}
|
|
@@ -178205,8 +179261,8 @@
|
|
if( pRhs ){
|
|
pRhs->op = (u8)yymsp[-1].minor.yy502;
|
|
pRhs->pPrior = pLhs;
|
|
- if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue;
|
|
- pRhs->selFlags &= ~SF_MultiValue;
|
|
+ if( ALWAYS(pLhs) ) pLhs->selFlags &= ~(u32)SF_MultiValue;
|
|
+ pRhs->selFlags &= ~(u32)SF_MultiValue;
|
|
if( yymsp[-1].minor.yy502!=TK_ALL ) pParse->hasCompound = 1;
|
|
}else{
|
|
sqlite3SelectDelete(pParse->db, pLhs);
|
|
@@ -178846,12 +179902,21 @@
|
|
** expr1 IN ()
|
|
** expr1 NOT IN ()
|
|
**
|
|
- ** simplify to constants 0 (false) and 1 (true), respectively,
|
|
- ** regardless of the value of expr1.
|
|
- */
|
|
- sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy590);
|
|
- yymsp[-4].minor.yy590 = sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy502 ? "true" : "false");
|
|
- if( yymsp[-4].minor.yy590 ) sqlite3ExprIdToTrueFalse(yymsp[-4].minor.yy590);
|
|
+ ** simplify to constants 0 (false) and 1 (true), respectively.
|
|
+ **
|
|
+ ** Except, do not apply this optimization if expr1 contains a function
|
|
+ ** because that function might be an aggregate (we don't know yet whether
|
|
+ ** it is or not) and if it is an aggregate, that could change the meaning
|
|
+ ** of the whole query.
|
|
+ */
|
|
+ Expr *pB = sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy502 ? "true" : "false");
|
|
+ if( pB ) sqlite3ExprIdToTrueFalse(pB);
|
|
+ if( !ExprHasProperty(yymsp[-4].minor.yy590, EP_HasFunc) ){
|
|
+ sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy590);
|
|
+ yymsp[-4].minor.yy590 = pB;
|
|
+ }else{
|
|
+ yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, yymsp[-3].minor.yy502 ? TK_OR : TK_AND, pB, yymsp[-4].minor.yy590);
|
|
+ }
|
|
}else{
|
|
Expr *pRHS = yymsp[-1].minor.yy402->a[0].pExpr;
|
|
if( yymsp[-1].minor.yy402->nExpr==1 && sqlite3ExprIsConstant(pParse,pRHS) && yymsp[-4].minor.yy590->op!=TK_VECTOR ){
|
|
@@ -179011,6 +180076,10 @@
|
|
{
|
|
sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy502, yymsp[-4].minor.yy28.a, yymsp[-4].minor.yy28.b, yymsp[-2].minor.yy563, yymsp[0].minor.yy590, yymsp[-10].minor.yy502, yymsp[-8].minor.yy502);
|
|
yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/
|
|
+#ifdef SQLITE_DEBUG
|
|
+ assert( pParse->isCreate ); /* Set by createkw reduce action */
|
|
+ pParse->isCreate = 0; /* But, should not be set for CREATE TRIGGER */
|
|
+#endif
|
|
}
|
|
break;
|
|
case 262: /* trigger_time ::= BEFORE|AFTER */
|
|
@@ -180453,7 +181522,7 @@
|
|
int t; /* Token type to return */
|
|
do {
|
|
z += sqlite3GetToken(z, &t);
|
|
- }while( t==TK_SPACE );
|
|
+ }while( t==TK_SPACE || t==TK_COMMENT );
|
|
if( t==TK_ID
|
|
|| t==TK_STRING
|
|
|| t==TK_JOIN_KW
|
|
@@ -180946,7 +182015,11 @@
|
|
assert( n==6 );
|
|
tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed);
|
|
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
|
- }else if( tokenType==TK_COMMENT && (db->flags & SQLITE_Comments)!=0 ){
|
|
+ }else if( tokenType==TK_COMMENT
|
|
+ && (db->init.busy || (db->flags & SQLITE_Comments)!=0)
|
|
+ ){
|
|
+ /* Ignore SQL comments if either (1) we are reparsing the schema or
|
|
+ ** (2) SQLITE_DBCONFIG_ENABLE_COMMENTS is turned on (the default). */
|
|
zSql += n;
|
|
continue;
|
|
}else if( tokenType!=TK_QNUMBER ){
|
|
@@ -181841,6 +182914,14 @@
|
|
if( rc==SQLITE_OK ){
|
|
sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
|
|
sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);
|
|
+#ifdef SQLITE_EXTRA_INIT_MUTEXED
|
|
+ {
|
|
+ int SQLITE_EXTRA_INIT_MUTEXED(const char*);
|
|
+ rc = SQLITE_EXTRA_INIT_MUTEXED(0);
|
|
+ }
|
|
+#endif
|
|
+ }
|
|
+ if( rc==SQLITE_OK ){
|
|
sqlite3MemoryBarrier();
|
|
sqlite3GlobalConfig.isInit = 1;
|
|
#ifdef SQLITE_EXTRA_INIT
|
|
@@ -182297,17 +183378,22 @@
|
|
** If lookaside is already active, return SQLITE_BUSY.
|
|
**
|
|
** The sz parameter is the number of bytes in each lookaside slot.
|
|
-** The cnt parameter is the number of slots. If pStart is NULL the
|
|
-** space for the lookaside memory is obtained from sqlite3_malloc().
|
|
-** If pStart is not NULL then it is sz*cnt bytes of memory to use for
|
|
-** the lookaside memory.
|
|
-*/
|
|
-static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
|
|
+** The cnt parameter is the number of slots. If pBuf is NULL the
|
|
+** space for the lookaside memory is obtained from sqlite3_malloc()
|
|
+** or similar. If pBuf is not NULL then it is sz*cnt bytes of memory
|
|
+** to use for the lookaside memory.
|
|
+*/
|
|
+static int setupLookaside(
|
|
+ sqlite3 *db, /* Database connection being configured */
|
|
+ void *pBuf, /* Memory to use for lookaside. May be NULL */
|
|
+ int sz, /* Desired size of each lookaside memory slot */
|
|
+ int cnt /* Number of slots to allocate */
|
|
+){
|
|
#ifndef SQLITE_OMIT_LOOKASIDE
|
|
- void *pStart;
|
|
- sqlite3_int64 szAlloc;
|
|
- int nBig; /* Number of full-size slots */
|
|
- int nSm; /* Number smaller LOOKASIDE_SMALL-byte slots */
|
|
+ void *pStart; /* Start of the lookaside buffer */
|
|
+ sqlite3_int64 szAlloc; /* Total space set aside for lookaside memory */
|
|
+ int nBig; /* Number of full-size slots */
|
|
+ int nSm; /* Number smaller LOOKASIDE_SMALL-byte slots */
|
|
|
|
if( sqlite3LookasideUsed(db,0)>0 ){
|
|
return SQLITE_BUSY;
|
|
@@ -182320,19 +183406,22 @@
|
|
sqlite3_free(db->lookaside.pStart);
|
|
}
|
|
/* The size of a lookaside slot after ROUNDDOWN8 needs to be larger
|
|
- ** than a pointer to be useful.
|
|
+ ** than a pointer and small enough to fit in a u16.
|
|
*/
|
|
- sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */
|
|
+ sz = ROUNDDOWN8(sz);
|
|
if( sz<=(int)sizeof(LookasideSlot*) ) sz = 0;
|
|
if( sz>65528 ) sz = 65528;
|
|
- if( cnt<0 ) cnt = 0;
|
|
+ /* Count must be at least 1 to be useful, but not so large as to use
|
|
+ ** more than 0x7fff0000 total bytes for lookaside. */
|
|
+ if( cnt<1 ) cnt = 0;
|
|
+ if( sz>0 && cnt>(0x7fff0000/sz) ) cnt = 0x7fff0000/sz;
|
|
szAlloc = (i64)sz*(i64)cnt;
|
|
- if( sz==0 || cnt==0 ){
|
|
+ if( szAlloc==0 ){
|
|
sz = 0;
|
|
pStart = 0;
|
|
}else if( pBuf==0 ){
|
|
sqlite3BeginBenignMalloc();
|
|
- pStart = sqlite3Malloc( szAlloc ); /* IMP: R-61949-35727 */
|
|
+ pStart = sqlite3Malloc( szAlloc );
|
|
sqlite3EndBenignMalloc();
|
|
if( pStart ) szAlloc = sqlite3MallocSize(pStart);
|
|
}else{
|
|
@@ -183309,6 +184398,9 @@
|
|
db->busyHandler.pBusyArg = pArg;
|
|
db->busyHandler.nBusy = 0;
|
|
db->busyTimeout = 0;
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ db->setlkTimeout = 0;
|
|
+#endif
|
|
sqlite3_mutex_leave(db->mutex);
|
|
return SQLITE_OK;
|
|
}
|
|
@@ -183358,6 +184450,9 @@
|
|
sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
|
|
(void*)db);
|
|
db->busyTimeout = ms;
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ db->setlkTimeout = ms;
|
|
+#endif
|
|
}else{
|
|
sqlite3_busy_handler(db, 0, 0);
|
|
}
|
|
@@ -183365,6 +184460,40 @@
|
|
}
|
|
|
|
/*
|
|
+** Set the setlk timeout value.
|
|
+*/
|
|
+SQLITE_API int sqlite3_setlk_timeout(sqlite3 *db, int ms, int flags){
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ int iDb;
|
|
+ int bBOC = ((flags & SQLITE_SETLK_BLOCK_ON_CONNECT) ? 1 : 0);
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_API_ARMOR
|
|
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
|
|
+#endif
|
|
+ if( ms<-1 ) return SQLITE_RANGE;
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ sqlite3_mutex_enter(db->mutex);
|
|
+ db->setlkTimeout = ms;
|
|
+ db->setlkFlags = flags;
|
|
+ sqlite3BtreeEnterAll(db);
|
|
+ for(iDb=0; iDb<db->nDb; iDb++){
|
|
+ Btree *pBt = db->aDb[iDb].pBt;
|
|
+ if( pBt ){
|
|
+ sqlite3_file *fd = sqlite3PagerFile(sqlite3BtreePager(pBt));
|
|
+ sqlite3OsFileControlHint(fd, SQLITE_FCNTL_BLOCK_ON_CONNECT, (void*)&bBOC);
|
|
+ }
|
|
+ }
|
|
+ sqlite3BtreeLeaveAll(db);
|
|
+ sqlite3_mutex_leave(db->mutex);
|
|
+#endif
|
|
+#if !defined(SQLITE_ENABLE_API_ARMOR) && !defined(SQLITE_ENABLE_SETLK_TIMEOUT)
|
|
+ UNUSED_PARAMETER(db);
|
|
+ UNUSED_PARAMETER(flags);
|
|
+#endif
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
** Cause any pending operation to stop at its earliest opportunity.
|
|
*/
|
|
SQLITE_API void sqlite3_interrupt(sqlite3 *db){
|
|
@@ -185329,7 +186458,7 @@
|
|
return SQLITE_OK;
|
|
}else{
|
|
size_t n = strlen(zName);
|
|
- p = sqlite3_malloc64( sizeof(DbClientData)+n+1 );
|
|
+ p = sqlite3_malloc64( SZ_DBCLIENTDATA(n+1) );
|
|
if( p==0 ){
|
|
if( xDestructor ) xDestructor(pData);
|
|
sqlite3_mutex_leave(db->mutex);
|
|
@@ -185483,13 +186612,10 @@
|
|
if( zColumnName==0 ){
|
|
/* Query for existence of table only */
|
|
}else{
|
|
- for(iCol=0; iCol<pTab->nCol; iCol++){
|
|
+ iCol = sqlite3ColumnIndex(pTab, zColumnName);
|
|
+ if( iCol>=0 ){
|
|
pCol = &pTab->aCol[iCol];
|
|
- if( 0==sqlite3StrICmp(pCol->zCnName, zColumnName) ){
|
|
- break;
|
|
- }
|
|
- }
|
|
- if( iCol==pTab->nCol ){
|
|
+ }else{
|
|
if( HasRowid(pTab) && sqlite3IsRowid(zColumnName) ){
|
|
iCol = pTab->iPKey;
|
|
pCol = iCol>=0 ? &pTab->aCol[iCol] : 0;
|
|
@@ -185698,8 +186824,8 @@
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_FK_NO_ACTION, sqlite3 *db, int b);
|
|
**
|
|
** If b is true, then activate the SQLITE_FkNoAction setting. If b is
|
|
- ** false then clearn that setting. If the SQLITE_FkNoAction setting is
|
|
- ** abled, all foreign key ON DELETE and ON UPDATE actions behave as if
|
|
+ ** false then clear that setting. If the SQLITE_FkNoAction setting is
|
|
+ ** enabled, all foreign key ON DELETE and ON UPDATE actions behave as if
|
|
** they were NO ACTION, regardless of how they are defined.
|
|
**
|
|
** NB: One must usually run "PRAGMA writable_schema=RESET" after
|
|
@@ -187046,7 +188172,7 @@
|
|
** Here, array { X } means zero or more occurrences of X, adjacent in
|
|
** memory. A "position" is an index of a token in the token stream
|
|
** generated by the tokenizer. Note that POS_END and POS_COLUMN occur
|
|
-** in the same logical place as the position element, and act as sentinals
|
|
+** in the same logical place as the position element, and act as sentinels
|
|
** ending a position list array. POS_END is 0. POS_COLUMN is 1.
|
|
** The positions numbers are not stored literally but rather as two more
|
|
** than the difference from the prior position, or the just the position plus
|
|
@@ -187265,6 +188391,13 @@
|
|
#ifndef _FTSINT_H
|
|
#define _FTSINT_H
|
|
|
|
+/* #include <assert.h> */
|
|
+/* #include <stdlib.h> */
|
|
+/* #include <stddef.h> */
|
|
+/* #include <stdio.h> */
|
|
+/* #include <string.h> */
|
|
+/* #include <stdarg.h> */
|
|
+
|
|
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
|
|
# define NDEBUG 1
|
|
#endif
|
|
@@ -187734,6 +188867,19 @@
|
|
|
|
#define deliberate_fall_through
|
|
|
|
+/*
|
|
+** Macros needed to provide flexible arrays in a portable way
|
|
+*/
|
|
+#ifndef offsetof
|
|
+# define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD))
|
|
+#endif
|
|
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
|
|
+# define FLEXARRAY
|
|
+#else
|
|
+# define FLEXARRAY 1
|
|
+#endif
|
|
+
|
|
+
|
|
#endif /* SQLITE_AMALGAMATION */
|
|
|
|
#ifdef SQLITE_DEBUG
|
|
@@ -187838,7 +188984,7 @@
|
|
#endif
|
|
|
|
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
|
- /* True to disable the incremental doclist optimization. This is controled
|
|
+ /* True to disable the incremental doclist optimization. This is controlled
|
|
** by special insert command 'test-no-incr-doclist'. */
|
|
int bNoIncrDoclist;
|
|
|
|
@@ -187890,7 +189036,7 @@
|
|
|
|
/*
|
|
** The Fts3Cursor.eSearch member is always set to one of the following.
|
|
-** Actualy, Fts3Cursor.eSearch can be greater than or equal to
|
|
+** Actually, Fts3Cursor.eSearch can be greater than or equal to
|
|
** FTS3_FULLTEXT_SEARCH. If so, then Fts3Cursor.eSearch - 2 is the index
|
|
** of the column to be searched. For example, in
|
|
**
|
|
@@ -187963,9 +189109,13 @@
|
|
*/
|
|
int nToken; /* Number of tokens in the phrase */
|
|
int iColumn; /* Index of column this phrase must match */
|
|
- Fts3PhraseToken aToken[1]; /* One entry for each token in the phrase */
|
|
+ Fts3PhraseToken aToken[FLEXARRAY]; /* One for each token in the phrase */
|
|
};
|
|
|
|
+/* Size (in bytes) of an Fts3Phrase object large enough to hold N tokens */
|
|
+#define SZ_FTS3PHRASE(N) \
|
|
+ (offsetof(Fts3Phrase,aToken)+(N)*sizeof(Fts3PhraseToken))
|
|
+
|
|
/*
|
|
** A tree of these objects forms the RHS of a MATCH operator.
|
|
**
|
|
@@ -188199,12 +189349,6 @@
|
|
# define SQLITE_CORE 1
|
|
#endif
|
|
|
|
-/* #include <assert.h> */
|
|
-/* #include <stdlib.h> */
|
|
-/* #include <stddef.h> */
|
|
-/* #include <stdio.h> */
|
|
-/* #include <string.h> */
|
|
-/* #include <stdarg.h> */
|
|
|
|
/* #include "fts3.h" */
|
|
#ifndef SQLITE_CORE
|
|
@@ -190543,7 +191687,7 @@
|
|
** sizes of the two inputs, plus enough space for exactly one of the input
|
|
** docids to grow.
|
|
**
|
|
- ** A symetric argument may be made if the doclists are in descending
|
|
+ ** A symmetric argument may be made if the doclists are in descending
|
|
** order.
|
|
*/
|
|
aOut = sqlite3_malloc64((i64)n1+n2+FTS3_VARINT_MAX-1+FTS3_BUFFER_PADDING);
|
|
@@ -192342,7 +193486,7 @@
|
|
nDistance = iPrev - nMaxUndeferred;
|
|
}
|
|
|
|
- aOut = (char *)sqlite3Fts3MallocZero(nPoslist+FTS3_BUFFER_PADDING);
|
|
+ aOut = (char *)sqlite3Fts3MallocZero(((i64)nPoslist)+FTS3_BUFFER_PADDING);
|
|
if( !aOut ){
|
|
sqlite3_free(aPoslist);
|
|
return SQLITE_NOMEM;
|
|
@@ -192641,7 +193785,7 @@
|
|
**
|
|
** * does not contain any deferred tokens.
|
|
**
|
|
-** Advance it to the next matching documnent in the database and populate
|
|
+** Advance it to the next matching document in the database and populate
|
|
** the Fts3Doclist.pList and nList fields.
|
|
**
|
|
** If there is no "next" entry and no error occurs, then *pbEof is set to
|
|
@@ -193648,7 +194792,7 @@
|
|
}
|
|
|
|
/*
|
|
-** Restart interation for expression pExpr so that the next call to
|
|
+** Restart iteration for expression pExpr so that the next call to
|
|
** fts3EvalNext() visits the first row. Do not allow incremental
|
|
** loading or merging of phrase doclists for this iteration.
|
|
**
|
|
@@ -194841,6 +195985,23 @@
|
|
static int fts3ExprParse(ParseContext *, const char *, int, Fts3Expr **, int *);
|
|
|
|
/*
|
|
+** Search buffer z[], size n, for a '"' character. Or, if enable_parenthesis
|
|
+** is defined, search for '(' and ')' as well. Return the index of the first
|
|
+** such character in the buffer. If there is no such character, return -1.
|
|
+*/
|
|
+static int findBarredChar(const char *z, int n){
|
|
+ int ii;
|
|
+ for(ii=0; ii<n; ii++){
|
|
+ if( (z[ii]=='"')
|
|
+ || (sqlite3_fts3_enable_parentheses && (z[ii]=='(' || z[ii]==')'))
|
|
+ ){
|
|
+ return ii;
|
|
+ }
|
|
+ }
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+/*
|
|
** Extract the next token from buffer z (length n) using the tokenizer
|
|
** and other information (column names etc.) in pParse. Create an Fts3Expr
|
|
** structure of type FTSQUERY_PHRASE containing a phrase consisting of this
|
|
@@ -194864,16 +196025,9 @@
|
|
int rc;
|
|
sqlite3_tokenizer_cursor *pCursor;
|
|
Fts3Expr *pRet = 0;
|
|
- int i = 0;
|
|
-
|
|
- /* Set variable i to the maximum number of bytes of input to tokenize. */
|
|
- for(i=0; i<n; i++){
|
|
- if( sqlite3_fts3_enable_parentheses && (z[i]=='(' || z[i]==')') ) break;
|
|
- if( z[i]=='"' ) break;
|
|
- }
|
|
|
|
- *pnConsumed = i;
|
|
- rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, i, &pCursor);
|
|
+ *pnConsumed = n;
|
|
+ rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, n, &pCursor);
|
|
if( rc==SQLITE_OK ){
|
|
const char *zToken;
|
|
int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0;
|
|
@@ -194881,7 +196035,18 @@
|
|
|
|
rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition);
|
|
if( rc==SQLITE_OK ){
|
|
- nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken;
|
|
+ /* Check that this tokenization did not gobble up any " characters. Or,
|
|
+ ** if enable_parenthesis is true, that it did not gobble up any
|
|
+ ** open or close parenthesis characters either. If it did, call
|
|
+ ** getNextToken() again, but pass only that part of the input buffer
|
|
+ ** up to the first such character. */
|
|
+ int iBarred = findBarredChar(z, iEnd);
|
|
+ if( iBarred>=0 ){
|
|
+ pModule->xClose(pCursor);
|
|
+ return getNextToken(pParse, iCol, z, iBarred, ppExpr, pnConsumed);
|
|
+ }
|
|
+
|
|
+ nByte = sizeof(Fts3Expr) + SZ_FTS3PHRASE(1) + nToken;
|
|
pRet = (Fts3Expr *)sqlite3Fts3MallocZero(nByte);
|
|
if( !pRet ){
|
|
rc = SQLITE_NOMEM;
|
|
@@ -194891,7 +196056,7 @@
|
|
pRet->pPhrase->nToken = 1;
|
|
pRet->pPhrase->iColumn = iCol;
|
|
pRet->pPhrase->aToken[0].n = nToken;
|
|
- pRet->pPhrase->aToken[0].z = (char *)&pRet->pPhrase[1];
|
|
+ pRet->pPhrase->aToken[0].z = (char*)&pRet->pPhrase->aToken[1];
|
|
memcpy(pRet->pPhrase->aToken[0].z, zToken, nToken);
|
|
|
|
if( iEnd<n && z[iEnd]=='*' ){
|
|
@@ -194915,7 +196080,11 @@
|
|
|
|
}
|
|
*pnConsumed = iEnd;
|
|
- }else if( i && rc==SQLITE_DONE ){
|
|
+ }else if( n && rc==SQLITE_DONE ){
|
|
+ int iBarred = findBarredChar(z, n);
|
|
+ if( iBarred>=0 ){
|
|
+ *pnConsumed = iBarred;
|
|
+ }
|
|
rc = SQLITE_OK;
|
|
}
|
|
|
|
@@ -194962,9 +196131,9 @@
|
|
Fts3Expr *p = 0;
|
|
sqlite3_tokenizer_cursor *pCursor = 0;
|
|
char *zTemp = 0;
|
|
- int nTemp = 0;
|
|
+ i64 nTemp = 0;
|
|
|
|
- const int nSpace = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
|
|
+ const int nSpace = sizeof(Fts3Expr) + SZ_FTS3PHRASE(1);
|
|
int nToken = 0;
|
|
|
|
/* The final Fts3Expr data structure, including the Fts3Phrase,
|
|
@@ -195336,7 +196505,7 @@
|
|
|
|
/* The isRequirePhrase variable is set to true if a phrase or
|
|
** an expression contained in parenthesis is required. If a
|
|
- ** binary operator (AND, OR, NOT or NEAR) is encounted when
|
|
+ ** binary operator (AND, OR, NOT or NEAR) is encountered when
|
|
** isRequirePhrase is set, this is a syntax error.
|
|
*/
|
|
if( !isPhrase && isRequirePhrase ){
|
|
@@ -195918,7 +197087,6 @@
|
|
}
|
|
|
|
if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
|
|
- sqlite3Fts3ExprFree(pExpr);
|
|
sqlite3_result_error(context, "Error parsing expression", -1);
|
|
}else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){
|
|
sqlite3_result_error_nomem(context);
|
|
@@ -196161,7 +197329,7 @@
|
|
}
|
|
|
|
|
|
-/* Resize the hash table so that it cantains "new_size" buckets.
|
|
+/* Resize the hash table so that it contains "new_size" buckets.
|
|
** "new_size" must be a power of 2. The hash table might fail
|
|
** to resize if sqliteMalloc() fails.
|
|
**
|
|
@@ -196616,7 +197784,7 @@
|
|
|
|
/*
|
|
** If the word ends with zFrom and xCond() is true for the stem
|
|
-** of the word that preceeds the zFrom ending, then change the
|
|
+** of the word that precedes the zFrom ending, then change the
|
|
** ending to zTo.
|
|
**
|
|
** The input word *pz and zFrom are both in reverse order. zTo
|
|
@@ -198127,7 +199295,7 @@
|
|
fts3tokResetCursor(pCsr);
|
|
if( idxNum==1 ){
|
|
const char *zByte = (const char *)sqlite3_value_text(apVal[0]);
|
|
- int nByte = sqlite3_value_bytes(apVal[0]);
|
|
+ sqlite3_int64 nByte = sqlite3_value_bytes(apVal[0]);
|
|
pCsr->zInput = sqlite3_malloc64(nByte+1);
|
|
if( pCsr->zInput==0 ){
|
|
rc = SQLITE_NOMEM;
|
|
@@ -202199,7 +203367,7 @@
|
|
**
|
|
** It is assumed that the buffer associated with pNode is already large
|
|
** enough to accommodate the new entry. The buffer associated with pPrev
|
|
-** is extended by this function if requrired.
|
|
+** is extended by this function if required.
|
|
**
|
|
** If an error (i.e. OOM condition) occurs, an SQLite error code is
|
|
** returned. Otherwise, SQLITE_OK.
|
|
@@ -203862,7 +205030,7 @@
|
|
/*
|
|
** SQLite value pRowid contains the rowid of a row that may or may not be
|
|
** present in the FTS3 table. If it is, delete it and adjust the contents
|
|
-** of subsiduary data structures accordingly.
|
|
+** of subsidiary data structures accordingly.
|
|
*/
|
|
static int fts3DeleteByRowid(
|
|
Fts3Table *p,
|
|
@@ -204188,9 +205356,13 @@
|
|
int nElem;
|
|
int bGlobal; /* Set if global data is loaded */
|
|
char *zMatchinfo;
|
|
- u32 aMatchinfo[1];
|
|
+ u32 aMI[FLEXARRAY];
|
|
};
|
|
|
|
+/* Size (in bytes) of a MatchinfoBuffer sufficient for N elements */
|
|
+#define SZ_MATCHINFOBUFFER(N) \
|
|
+ (offsetof(MatchinfoBuffer,aMI)+(((N)+1)/2)*sizeof(u64))
|
|
+
|
|
|
|
/*
|
|
** The snippet() and offsets() functions both return text values. An instance
|
|
@@ -204215,13 +205387,13 @@
|
|
static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){
|
|
MatchinfoBuffer *pRet;
|
|
sqlite3_int64 nByte = sizeof(u32) * (2*(sqlite3_int64)nElem + 1)
|
|
- + sizeof(MatchinfoBuffer);
|
|
+ + SZ_MATCHINFOBUFFER(1);
|
|
sqlite3_int64 nStr = strlen(zMatchinfo);
|
|
|
|
pRet = sqlite3Fts3MallocZero(nByte + nStr+1);
|
|
if( pRet ){
|
|
- pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet;
|
|
- pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0]
|
|
+ pRet->aMI[0] = (u8*)(&pRet->aMI[1]) - (u8*)pRet;
|
|
+ pRet->aMI[1+nElem] = pRet->aMI[0]
|
|
+ sizeof(u32)*((int)nElem+1);
|
|
pRet->nElem = (int)nElem;
|
|
pRet->zMatchinfo = ((char*)pRet) + nByte;
|
|
@@ -204235,10 +205407,10 @@
|
|
static void fts3MIBufferFree(void *p){
|
|
MatchinfoBuffer *pBuf = (MatchinfoBuffer*)((u8*)p - ((u32*)p)[-1]);
|
|
|
|
- assert( (u32*)p==&pBuf->aMatchinfo[1]
|
|
- || (u32*)p==&pBuf->aMatchinfo[pBuf->nElem+2]
|
|
+ assert( (u32*)p==&pBuf->aMI[1]
|
|
+ || (u32*)p==&pBuf->aMI[pBuf->nElem+2]
|
|
);
|
|
- if( (u32*)p==&pBuf->aMatchinfo[1] ){
|
|
+ if( (u32*)p==&pBuf->aMI[1] ){
|
|
pBuf->aRef[1] = 0;
|
|
}else{
|
|
pBuf->aRef[2] = 0;
|
|
@@ -204255,18 +205427,18 @@
|
|
|
|
if( p->aRef[1]==0 ){
|
|
p->aRef[1] = 1;
|
|
- aOut = &p->aMatchinfo[1];
|
|
+ aOut = &p->aMI[1];
|
|
xRet = fts3MIBufferFree;
|
|
}
|
|
else if( p->aRef[2]==0 ){
|
|
p->aRef[2] = 1;
|
|
- aOut = &p->aMatchinfo[p->nElem+2];
|
|
+ aOut = &p->aMI[p->nElem+2];
|
|
xRet = fts3MIBufferFree;
|
|
}else{
|
|
aOut = (u32*)sqlite3_malloc64(p->nElem * sizeof(u32));
|
|
if( aOut ){
|
|
xRet = sqlite3_free;
|
|
- if( p->bGlobal ) memcpy(aOut, &p->aMatchinfo[1], p->nElem*sizeof(u32));
|
|
+ if( p->bGlobal ) memcpy(aOut, &p->aMI[1], p->nElem*sizeof(u32));
|
|
}
|
|
}
|
|
|
|
@@ -204276,7 +205448,7 @@
|
|
|
|
static void fts3MIBufferSetGlobal(MatchinfoBuffer *p){
|
|
p->bGlobal = 1;
|
|
- memcpy(&p->aMatchinfo[2+p->nElem], &p->aMatchinfo[1], p->nElem*sizeof(u32));
|
|
+ memcpy(&p->aMI[2+p->nElem], &p->aMI[1], p->nElem*sizeof(u32));
|
|
}
|
|
|
|
/*
|
|
@@ -204691,7 +205863,7 @@
|
|
}
|
|
|
|
/* If there is insufficient space allocated at StrBuffer.z, use realloc()
|
|
- ** to grow the buffer until so that it is big enough to accomadate the
|
|
+ ** to grow the buffer until so that it is big enough to accommodate the
|
|
** appended data.
|
|
*/
|
|
if( pStr->n+nAppend+1>=pStr->nAlloc ){
|
|
@@ -205103,16 +206275,16 @@
|
|
break;
|
|
|
|
case FTS3_MATCHINFO_LHITS:
|
|
- nVal = pInfo->nCol * pInfo->nPhrase;
|
|
+ nVal = (size_t)pInfo->nCol * pInfo->nPhrase;
|
|
break;
|
|
|
|
case FTS3_MATCHINFO_LHITS_BM:
|
|
- nVal = pInfo->nPhrase * ((pInfo->nCol + 31) / 32);
|
|
+ nVal = (size_t)pInfo->nPhrase * ((pInfo->nCol + 31) / 32);
|
|
break;
|
|
|
|
default:
|
|
assert( cArg==FTS3_MATCHINFO_HITS );
|
|
- nVal = pInfo->nCol * pInfo->nPhrase * 3;
|
|
+ nVal = (size_t)pInfo->nCol * pInfo->nPhrase * 3;
|
|
break;
|
|
}
|
|
|
|
@@ -206670,8 +207842,8 @@
|
|
** Beginning with version 3.45.0 (circa 2024-01-01), these routines also
|
|
** accept BLOB values that have JSON encoded using a binary representation
|
|
** called "JSONB". The name JSONB comes from PostgreSQL, however the on-disk
|
|
-** format SQLite JSONB is completely different and incompatible with
|
|
-** PostgreSQL JSONB.
|
|
+** format for SQLite-JSONB is completely different and incompatible with
|
|
+** PostgreSQL-JSONB.
|
|
**
|
|
** Decoding and interpreting JSONB is still O(N) where N is the size of
|
|
** the input, the same as text JSON. However, the constant of proportionality
|
|
@@ -206728,7 +207900,7 @@
|
|
**
|
|
** The payload size need not be expressed in its minimal form. For example,
|
|
** if the payload size is 10, the size can be expressed in any of 5 different
|
|
-** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by on 0x0a byte,
|
|
+** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by one 0x0a byte,
|
|
** (3) (X>>4)==13 followed by 0x00 and 0x0a, (4) (X>>4)==14 followed by
|
|
** 0x00 0x00 0x00 0x0a, or (5) (X>>4)==15 followed by 7 bytes of 0x00 and
|
|
** a single byte of 0x0a. The shorter forms are preferred, of course, but
|
|
@@ -206738,7 +207910,7 @@
|
|
** the size when it becomes known, resulting in a non-minimal encoding.
|
|
**
|
|
** The value (X>>4)==15 is not actually used in the current implementation
|
|
-** (as SQLite is currently unable handle BLOBs larger than about 2GB)
|
|
+** (as SQLite is currently unable to handle BLOBs larger than about 2GB)
|
|
** but is included in the design to allow for future enhancements.
|
|
**
|
|
** The payload follows the header. NULL, TRUE, and FALSE have no payload and
|
|
@@ -206798,23 +207970,47 @@
|
|
** increase for the text-JSON parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
|
|
*/
|
|
static const char jsonIsSpace[] = {
|
|
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
|
|
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
-
|
|
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
+#ifdef SQLITE_ASCII
|
|
+/*0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0 */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */
|
|
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */
|
|
+
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* b */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* c */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* e */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* f */
|
|
+#endif
|
|
+#ifdef SQLITE_EBCDIC
|
|
+/*0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
|
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, /* 0 */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */
|
|
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */
|
|
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */
|
|
+
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* b */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* c */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* e */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* f */
|
|
+#endif
|
|
+
|
|
};
|
|
#define jsonIsspace(x) (jsonIsSpace[(unsigned char)x])
|
|
|
|
@@ -206822,7 +208018,13 @@
|
|
** The set of all space characters recognized by jsonIsspace().
|
|
** Useful as the second argument to strspn().
|
|
*/
|
|
+#ifdef SQLITE_ASCII
|
|
static const char jsonSpaces[] = "\011\012\015\040";
|
|
+#endif
|
|
+#ifdef SQLITE_EBCDIC
|
|
+static const char jsonSpaces[] = "\005\045\015\100";
|
|
+#endif
|
|
+
|
|
|
|
/*
|
|
** Characters that are special to JSON. Control characters,
|
|
@@ -206831,23 +208033,46 @@
|
|
** it in the set of special characters.
|
|
*/
|
|
static const char jsonIsOk[256] = {
|
|
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
- 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
|
|
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
-
|
|
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
|
|
+#ifdef SQLITE_ASCII
|
|
+/*0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */
|
|
+ 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* 2 */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 3 */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4 */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* 5 */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */
|
|
+
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8 */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9 */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* c */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* d */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* f */
|
|
+#endif
|
|
+#ifdef SQLITE_EBCDIC
|
|
+/*0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
|
|
+ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* 3 */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4 */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 5 */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, /* 7 */
|
|
+
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8 */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9 */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* c */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* d */
|
|
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */
|
|
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* f */
|
|
+#endif
|
|
};
|
|
|
|
/* Objects */
|
|
@@ -206992,7 +208217,7 @@
|
|
** Forward references
|
|
**************************************************************************/
|
|
static void jsonReturnStringAsBlob(JsonString*);
|
|
-static int jsonFuncArgMightBeBinary(sqlite3_value *pJson);
|
|
+static int jsonArgIsJsonb(sqlite3_value *pJson, JsonParse *p);
|
|
static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*);
|
|
static void jsonReturnParse(sqlite3_context*,JsonParse*);
|
|
static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32);
|
|
@@ -207066,7 +208291,7 @@
|
|
** most-recently used entry if it isn't so already.
|
|
**
|
|
** The JsonParse object returned still belongs to the Cache and might
|
|
-** be deleted at any moment. If the caller whants the JsonParse to
|
|
+** be deleted at any moment. If the caller wants the JsonParse to
|
|
** linger, it needs to increment the nPJRef reference counter.
|
|
*/
|
|
static JsonParse *jsonCacheSearch(
|
|
@@ -207410,11 +208635,9 @@
|
|
break;
|
|
}
|
|
default: {
|
|
- if( jsonFuncArgMightBeBinary(pValue) ){
|
|
- JsonParse px;
|
|
- memset(&px, 0, sizeof(px));
|
|
- px.aBlob = (u8*)sqlite3_value_blob(pValue);
|
|
- px.nBlob = sqlite3_value_bytes(pValue);
|
|
+ JsonParse px;
|
|
+ memset(&px, 0, sizeof(px));
|
|
+ if( jsonArgIsJsonb(pValue, &px) ){
|
|
jsonTranslateBlobToText(&px, 0, p);
|
|
}else if( p->eErr==0 ){
|
|
sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
|
|
@@ -207733,7 +208956,7 @@
|
|
*/
|
|
static int jsonBlobExpand(JsonParse *pParse, u32 N){
|
|
u8 *aNew;
|
|
- u32 t;
|
|
+ u64 t;
|
|
assert( N>pParse->nBlobAlloc );
|
|
if( pParse->nBlobAlloc==0 ){
|
|
t = 100;
|
|
@@ -207743,8 +208966,9 @@
|
|
if( t<N ) t = N+100;
|
|
aNew = sqlite3DbRealloc(pParse->db, pParse->aBlob, t);
|
|
if( aNew==0 ){ pParse->oom = 1; return 1; }
|
|
+ assert( t<0x7fffffff );
|
|
pParse->aBlob = aNew;
|
|
- pParse->nBlobAlloc = t;
|
|
+ pParse->nBlobAlloc = (u32)t;
|
|
return 0;
|
|
}
|
|
|
|
@@ -207811,7 +209035,7 @@
|
|
}
|
|
|
|
|
|
-/* Append an node type byte together with the payload size and
|
|
+/* Append a node type byte together with the payload size and
|
|
** possibly also the payload.
|
|
**
|
|
** If aPayload is not NULL, then it is a pointer to the payload which
|
|
@@ -207880,8 +209104,10 @@
|
|
nExtra = 1;
|
|
}else if( szType==13 ){
|
|
nExtra = 2;
|
|
- }else{
|
|
+ }else if( szType==14 ){
|
|
nExtra = 4;
|
|
+ }else{
|
|
+ nExtra = 8;
|
|
}
|
|
if( szPayload<=11 ){
|
|
nNeeded = 0;
|
|
@@ -208351,7 +209577,12 @@
|
|
|| c=='n' || c=='r' || c=='t'
|
|
|| (c=='u' && jsonIs4Hex(&z[j+1])) ){
|
|
if( opcode==JSONB_TEXT ) opcode = JSONB_TEXTJ;
|
|
- }else if( c=='\'' || c=='0' || c=='v' || c=='\n'
|
|
+ }else if( c=='\'' || c=='v' || c=='\n'
|
|
+#ifdef SQLITE_BUG_COMPATIBLE_20250510
|
|
+ || (c=='0') /* Legacy bug compatible */
|
|
+#else
|
|
+ || (c=='0' && !sqlite3Isdigit(z[j+1])) /* Correct implementation */
|
|
+#endif
|
|
|| (0xe2==(u8)c && 0x80==(u8)z[j+1]
|
|
&& (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2]))
|
|
|| (c=='x' && jsonIs2Hex(&z[j+1])) ){
|
|
@@ -208701,10 +209932,7 @@
|
|
u8 x;
|
|
u32 sz;
|
|
u32 n;
|
|
- if( NEVER(i>pParse->nBlob) ){
|
|
- *pSz = 0;
|
|
- return 0;
|
|
- }
|
|
+ assert( i<=pParse->nBlob );
|
|
x = pParse->aBlob[i]>>4;
|
|
if( x<=11 ){
|
|
sz = x;
|
|
@@ -208741,15 +209969,15 @@
|
|
*pSz = 0;
|
|
return 0;
|
|
}
|
|
- sz = (pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) +
|
|
+ sz = ((u32)pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) +
|
|
(pParse->aBlob[i+7]<<8) + pParse->aBlob[i+8];
|
|
n = 9;
|
|
}
|
|
if( (i64)i+sz+n > pParse->nBlob
|
|
&& (i64)i+sz+n > pParse->nBlob-pParse->delta
|
|
){
|
|
- sz = 0;
|
|
- n = 0;
|
|
+ *pSz = 0;
|
|
+ return 0;
|
|
}
|
|
*pSz = sz;
|
|
return n;
|
|
@@ -208846,9 +210074,12 @@
|
|
}
|
|
case JSONB_TEXT:
|
|
case JSONB_TEXTJ: {
|
|
- jsonAppendChar(pOut, '"');
|
|
- jsonAppendRaw(pOut, (const char*)&pParse->aBlob[i+n], sz);
|
|
- jsonAppendChar(pOut, '"');
|
|
+ if( pOut->nUsed+sz+2<=pOut->nAlloc || jsonStringGrow(pOut, sz+2)==0 ){
|
|
+ pOut->zBuf[pOut->nUsed] = '"';
|
|
+ memcpy(pOut->zBuf+pOut->nUsed+1,(const char*)&pParse->aBlob[i+n],sz);
|
|
+ pOut->zBuf[pOut->nUsed+sz+1] = '"';
|
|
+ pOut->nUsed += sz+2;
|
|
+ }
|
|
break;
|
|
}
|
|
case JSONB_TEXT5: {
|
|
@@ -209087,33 +210318,6 @@
|
|
return i;
|
|
}
|
|
|
|
-
|
|
-/* Return true if the input pJson
|
|
-**
|
|
-** For performance reasons, this routine does not do a detailed check of the
|
|
-** input BLOB to ensure that it is well-formed. Hence, false positives are
|
|
-** possible. False negatives should never occur, however.
|
|
-*/
|
|
-static int jsonFuncArgMightBeBinary(sqlite3_value *pJson){
|
|
- u32 sz, n;
|
|
- const u8 *aBlob;
|
|
- int nBlob;
|
|
- JsonParse s;
|
|
- if( sqlite3_value_type(pJson)!=SQLITE_BLOB ) return 0;
|
|
- aBlob = sqlite3_value_blob(pJson);
|
|
- nBlob = sqlite3_value_bytes(pJson);
|
|
- if( nBlob<1 ) return 0;
|
|
- if( NEVER(aBlob==0) || (aBlob[0] & 0x0f)>JSONB_OBJECT ) return 0;
|
|
- memset(&s, 0, sizeof(s));
|
|
- s.aBlob = (u8*)aBlob;
|
|
- s.nBlob = nBlob;
|
|
- n = jsonbPayloadSize(&s, 0, &sz);
|
|
- if( n==0 ) return 0;
|
|
- if( sz+n!=(u32)nBlob ) return 0;
|
|
- if( (aBlob[0] & 0x0f)<=JSONB_FALSE && sz>0 ) return 0;
|
|
- return sz+n==(u32)nBlob;
|
|
-}
|
|
-
|
|
/*
|
|
** Given that a JSONB_ARRAY object starts at offset i, return
|
|
** the number of entries in that array.
|
|
@@ -209147,6 +210351,82 @@
|
|
}
|
|
|
|
/*
|
|
+** If the JSONB at aIns[0..nIns-1] can be expanded (by denormalizing the
|
|
+** size field) by d bytes, then write the expansion into aOut[] and
|
|
+** return true. In this way, an overwrite happens without changing the
|
|
+** size of the JSONB, which reduces memcpy() operations and also make it
|
|
+** faster and easier to update the B-Tree entry that contains the JSONB
|
|
+** in the database.
|
|
+**
|
|
+** If the expansion of aIns[] by d bytes cannot be (easily) accomplished
|
|
+** then return false.
|
|
+**
|
|
+** The d parameter is guaranteed to be between 1 and 8.
|
|
+**
|
|
+** This routine is an optimization. A correct answer is obtained if it
|
|
+** always leaves the output unchanged and returns false.
|
|
+*/
|
|
+static int jsonBlobOverwrite(
|
|
+ u8 *aOut, /* Overwrite here */
|
|
+ const u8 *aIns, /* New content */
|
|
+ u32 nIns, /* Bytes of new content */
|
|
+ u32 d /* Need to expand new content by this much */
|
|
+){
|
|
+ u32 szPayload; /* Bytes of payload */
|
|
+ u32 i; /* New header size, after expansion & a loop counter */
|
|
+ u8 szHdr; /* Size of header before expansion */
|
|
+
|
|
+ /* Lookup table for finding the upper 4 bits of the first byte of the
|
|
+ ** expanded aIns[], based on the size of the expanded aIns[] header:
|
|
+ **
|
|
+ ** 2 3 4 5 6 7 8 9 */
|
|
+ static const u8 aType[] = { 0xc0, 0xd0, 0, 0xe0, 0, 0, 0, 0xf0 };
|
|
+
|
|
+ if( (aIns[0]&0x0f)<=2 ) return 0; /* Cannot enlarge NULL, true, false */
|
|
+ switch( aIns[0]>>4 ){
|
|
+ default: { /* aIns[] header size 1 */
|
|
+ if( ((1<<d)&0x116)==0 ) return 0; /* d must be 1, 2, 4, or 8 */
|
|
+ i = d + 1; /* New hdr sz: 2, 3, 5, or 9 */
|
|
+ szHdr = 1;
|
|
+ break;
|
|
+ }
|
|
+ case 12: { /* aIns[] header size is 2 */
|
|
+ if( ((1<<d)&0x8a)==0) return 0; /* d must be 1, 3, or 7 */
|
|
+ i = d + 2; /* New hdr sz: 2, 5, or 9 */
|
|
+ szHdr = 2;
|
|
+ break;
|
|
+ }
|
|
+ case 13: { /* aIns[] header size is 3 */
|
|
+ if( d!=2 && d!=6 ) return 0; /* d must be 2 or 6 */
|
|
+ i = d + 3; /* New hdr sz: 5 or 9 */
|
|
+ szHdr = 3;
|
|
+ break;
|
|
+ }
|
|
+ case 14: { /* aIns[] header size is 5 */
|
|
+ if( d!=4 ) return 0; /* d must be 4 */
|
|
+ i = 9; /* New hdr sz: 9 */
|
|
+ szHdr = 5;
|
|
+ break;
|
|
+ }
|
|
+ case 15: { /* aIns[] header size is 9 */
|
|
+ return 0; /* No solution */
|
|
+ }
|
|
+ }
|
|
+ assert( i>=2 && i<=9 && aType[i-2]!=0 );
|
|
+ aOut[0] = (aIns[0] & 0x0f) | aType[i-2];
|
|
+ memcpy(&aOut[i], &aIns[szHdr], nIns-szHdr);
|
|
+ szPayload = nIns - szHdr;
|
|
+ while( 1/*edit-by-break*/ ){
|
|
+ i--;
|
|
+ aOut[i] = szPayload & 0xff;
|
|
+ if( i==1 ) break;
|
|
+ szPayload >>= 8;
|
|
+ }
|
|
+ assert( (szPayload>>8)==0 );
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+/*
|
|
** Modify the JSONB blob at pParse->aBlob by removing nDel bytes of
|
|
** content beginning at iDel, and replacing them with nIns bytes of
|
|
** content given by aIns.
|
|
@@ -209167,6 +210447,11 @@
|
|
u32 nIns /* Bytes of content to insert */
|
|
){
|
|
i64 d = (i64)nIns - (i64)nDel;
|
|
+ if( d<0 && d>=(-8) && aIns!=0
|
|
+ && jsonBlobOverwrite(&pParse->aBlob[iDel], aIns, nIns, (int)-d)
|
|
+ ){
|
|
+ return;
|
|
+ }
|
|
if( d!=0 ){
|
|
if( pParse->nBlob + d > pParse->nBlobAlloc ){
|
|
jsonBlobExpand(pParse, pParse->nBlob+d);
|
|
@@ -209178,7 +210463,9 @@
|
|
pParse->nBlob += d;
|
|
pParse->delta += d;
|
|
}
|
|
- if( nIns && aIns ) memcpy(&pParse->aBlob[iDel], aIns, nIns);
|
|
+ if( nIns && aIns ){
|
|
+ memcpy(&pParse->aBlob[iDel], aIns, nIns);
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -209263,7 +210550,21 @@
|
|
case 'r': { *piOut = '\r'; return 2; }
|
|
case 't': { *piOut = '\t'; return 2; }
|
|
case 'v': { *piOut = '\v'; return 2; }
|
|
- case '0': { *piOut = 0; return 2; }
|
|
+ case '0': {
|
|
+ /* JSON5 requires that the \0 escape not be followed by a digit.
|
|
+ ** But SQLite did not enforce this restriction in versions 3.42.0
|
|
+ ** through 3.49.2. That was a bug. But some applications might have
|
|
+ ** come to depend on that bug. Use the SQLITE_BUG_COMPATIBLE_20250510
|
|
+ ** option to restore the old buggy behavior. */
|
|
+#ifdef SQLITE_BUG_COMPATIBLE_20250510
|
|
+ /* Legacy bug-compatible behavior */
|
|
+ *piOut = 0;
|
|
+#else
|
|
+ /* Correct behavior */
|
|
+ *piOut = (n>2 && sqlite3Isdigit(z[2])) ? JSON_INVALID_CHAR : 0;
|
|
+#endif
|
|
+ return 2;
|
|
+ }
|
|
case '\'':
|
|
case '"':
|
|
case '/':
|
|
@@ -209763,7 +211064,7 @@
|
|
char *zOut;
|
|
u32 nOut = sz;
|
|
z = (const char*)&pParse->aBlob[i+n];
|
|
- zOut = sqlite3DbMallocRaw(db, nOut+1);
|
|
+ zOut = sqlite3DbMallocRaw(db, ((u64)nOut)+1);
|
|
if( zOut==0 ) goto returnfromblob_oom;
|
|
for(iIn=iOut=0; iIn<sz; iIn++){
|
|
char c = z[iIn];
|
|
@@ -209858,10 +211159,7 @@
|
|
return 0;
|
|
}
|
|
case SQLITE_BLOB: {
|
|
- if( jsonFuncArgMightBeBinary(pArg) ){
|
|
- pParse->aBlob = (u8*)sqlite3_value_blob(pArg);
|
|
- pParse->nBlob = sqlite3_value_bytes(pArg);
|
|
- }else{
|
|
+ if( !jsonArgIsJsonb(pArg, pParse) ){
|
|
sqlite3_result_error(ctx, "JSON cannot hold BLOB values", -1);
|
|
return 1;
|
|
}
|
|
@@ -209941,7 +211239,7 @@
|
|
}
|
|
|
|
/* argv[0] is a BLOB that seems likely to be a JSONB. Subsequent
|
|
-** arguments come in parse where each pair contains a JSON path and
|
|
+** arguments come in pairs where each pair contains a JSON path and
|
|
** content to insert or set at that patch. Do the updates
|
|
** and return the result.
|
|
**
|
|
@@ -210012,27 +211310,46 @@
|
|
/*
|
|
** If pArg is a blob that seems like a JSONB blob, then initialize
|
|
** p to point to that JSONB and return TRUE. If pArg does not seem like
|
|
-** a JSONB blob, then return FALSE;
|
|
+** a JSONB blob, then return FALSE.
|
|
**
|
|
-** This routine is only called if it is already known that pArg is a
|
|
-** blob. The only open question is whether or not the blob appears
|
|
-** to be a JSONB blob.
|
|
+** For small BLOBs (having no more than 7 bytes of payload) a full
|
|
+** validity check is done. So for small BLOBs this routine only returns
|
|
+** true if the value is guaranteed to be a valid JSONB. For larger BLOBs
|
|
+** (8 byte or more of payload) only the size of the outermost element is
|
|
+** checked to verify that the BLOB is superficially valid JSONB.
|
|
+**
|
|
+** A full JSONB validation is done on smaller BLOBs because those BLOBs might
|
|
+** also be text JSON that has been incorrectly cast into a BLOB.
|
|
+** (See tag-20240123-a and https://sqlite.org/forum/forumpost/012136abd5)
|
|
+** If the BLOB is 9 bytes are larger, then it is not possible for the
|
|
+** superficial size check done here to pass if the input is really text
|
|
+** JSON so we do not need to look deeper in that case.
|
|
+**
|
|
+** Why we only need to do full JSONB validation for smaller BLOBs:
|
|
+**
|
|
+** The first byte of valid JSON text must be one of: '{', '[', '"', ' ', '\n',
|
|
+** '\r', '\t', '-', or a digit '0' through '9'. Of these, only a subset
|
|
+** can also be the first byte of JSONB: '{', '[', and digits '3'
|
|
+** through '9'. In every one of those cases, the payload size is 7 bytes
|
|
+** or less. So if we do full JSONB validation for every BLOB where the
|
|
+** payload is less than 7 bytes, we will never get a false positive for
|
|
+** JSONB on an input that is really text JSON.
|
|
*/
|
|
static int jsonArgIsJsonb(sqlite3_value *pArg, JsonParse *p){
|
|
u32 n, sz = 0;
|
|
+ u8 c;
|
|
+ if( sqlite3_value_type(pArg)!=SQLITE_BLOB ) return 0;
|
|
p->aBlob = (u8*)sqlite3_value_blob(pArg);
|
|
p->nBlob = (u32)sqlite3_value_bytes(pArg);
|
|
- if( p->nBlob==0 ){
|
|
- p->aBlob = 0;
|
|
- return 0;
|
|
- }
|
|
- if( NEVER(p->aBlob==0) ){
|
|
- return 0;
|
|
- }
|
|
- if( (p->aBlob[0] & 0x0f)<=JSONB_OBJECT
|
|
+ if( p->nBlob>0
|
|
+ && ALWAYS(p->aBlob!=0)
|
|
+ && ((c = p->aBlob[0]) & 0x0f)<=JSONB_OBJECT
|
|
&& (n = jsonbPayloadSize(p, 0, &sz))>0
|
|
&& sz+n==p->nBlob
|
|
- && ((p->aBlob[0] & 0x0f)>JSONB_FALSE || sz==0)
|
|
+ && ((c & 0x0f)>JSONB_FALSE || sz==0)
|
|
+ && (sz>7
|
|
+ || (c!=0x7b && c!=0x5b && !sqlite3Isdigit(c))
|
|
+ || jsonbValidityCheck(p, 0, p->nBlob, 1)==0)
|
|
){
|
|
return 1;
|
|
}
|
|
@@ -210110,7 +211427,7 @@
|
|
** JSON functions were suppose to work. From the beginning, blob was
|
|
** reserved for expansion and a blob value should have raised an error.
|
|
** But it did not, due to a bug. And many applications came to depend
|
|
- ** upon this buggy behavior, espeically when using the CLI and reading
|
|
+ ** upon this buggy behavior, especially when using the CLI and reading
|
|
** JSON text using readfile(), which returns a blob. For this reason
|
|
** we will continue to support the bug moving forward.
|
|
** See for example https://sqlite.org/forum/forumpost/012136abd5292b8d
|
|
@@ -211125,21 +212442,17 @@
|
|
return;
|
|
}
|
|
case SQLITE_BLOB: {
|
|
- if( jsonFuncArgMightBeBinary(argv[0]) ){
|
|
+ JsonParse py;
|
|
+ memset(&py, 0, sizeof(py));
|
|
+ if( jsonArgIsJsonb(argv[0], &py) ){
|
|
if( flags & 0x04 ){
|
|
/* Superficial checking only - accomplished by the
|
|
- ** jsonFuncArgMightBeBinary() call above. */
|
|
+ ** jsonArgIsJsonb() call above. */
|
|
res = 1;
|
|
}else if( flags & 0x08 ){
|
|
/* Strict checking. Check by translating BLOB->TEXT->BLOB. If
|
|
** no errors occur, call that a "strict check". */
|
|
- JsonParse px;
|
|
- u32 iErr;
|
|
- memset(&px, 0, sizeof(px));
|
|
- px.aBlob = (u8*)sqlite3_value_blob(argv[0]);
|
|
- px.nBlob = sqlite3_value_bytes(argv[0]);
|
|
- iErr = jsonbValidityCheck(&px, 0, px.nBlob, 1);
|
|
- res = iErr==0;
|
|
+ res = 0==jsonbValidityCheck(&py, 0, py.nBlob, 1);
|
|
}
|
|
break;
|
|
}
|
|
@@ -211197,9 +212510,7 @@
|
|
UNUSED_PARAMETER(argc);
|
|
memset(&s, 0, sizeof(s));
|
|
s.db = sqlite3_context_db_handle(ctx);
|
|
- if( jsonFuncArgMightBeBinary(argv[0]) ){
|
|
- s.aBlob = (u8*)sqlite3_value_blob(argv[0]);
|
|
- s.nBlob = sqlite3_value_bytes(argv[0]);
|
|
+ if( jsonArgIsJsonb(argv[0], &s) ){
|
|
iErrPos = (i64)jsonbValidityCheck(&s, 0, s.nBlob, 1);
|
|
}else{
|
|
s.zJson = (char*)sqlite3_value_text(argv[0]);
|
|
@@ -211360,18 +212671,20 @@
|
|
UNUSED_PARAMETER(argc);
|
|
pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
|
|
if( pStr ){
|
|
+ z = (const char*)sqlite3_value_text(argv[0]);
|
|
+ n = sqlite3Strlen30(z);
|
|
if( pStr->zBuf==0 ){
|
|
jsonStringInit(pStr, ctx);
|
|
jsonAppendChar(pStr, '{');
|
|
- }else if( pStr->nUsed>1 ){
|
|
+ }else if( pStr->nUsed>1 && z!=0 ){
|
|
jsonAppendChar(pStr, ',');
|
|
}
|
|
pStr->pCtx = ctx;
|
|
- z = (const char*)sqlite3_value_text(argv[0]);
|
|
- n = sqlite3Strlen30(z);
|
|
- jsonAppendString(pStr, z, n);
|
|
- jsonAppendChar(pStr, ':');
|
|
- jsonAppendSqlValue(pStr, argv[1]);
|
|
+ if( z!=0 ){
|
|
+ jsonAppendString(pStr, z, n);
|
|
+ jsonAppendChar(pStr, ':');
|
|
+ jsonAppendSqlValue(pStr, argv[1]);
|
|
+ }
|
|
}
|
|
}
|
|
static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
|
|
@@ -211884,9 +213197,8 @@
|
|
memset(&p->sParse, 0, sizeof(p->sParse));
|
|
p->sParse.nJPRef = 1;
|
|
p->sParse.db = p->db;
|
|
- if( jsonFuncArgMightBeBinary(argv[0]) ){
|
|
- p->sParse.nBlob = sqlite3_value_bytes(argv[0]);
|
|
- p->sParse.aBlob = (u8*)sqlite3_value_blob(argv[0]);
|
|
+ if( jsonArgIsJsonb(argv[0], &p->sParse) ){
|
|
+ /* We have JSONB */
|
|
}else{
|
|
p->sParse.zJson = (char*)sqlite3_value_text(argv[0]);
|
|
p->sParse.nJson = sqlite3_value_bytes(argv[0]);
|
|
@@ -212180,6 +213492,8 @@
|
|
#endif
|
|
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char*,int*); /* In the SQLite core */
|
|
|
|
+/* #include <stddef.h> */
|
|
+
|
|
/*
|
|
** If building separately, we will need some setup that is normally
|
|
** found in sqliteInt.h
|
|
@@ -212210,6 +213524,14 @@
|
|
# define ALWAYS(X) (X)
|
|
# define NEVER(X) (X)
|
|
#endif
|
|
+#ifndef offsetof
|
|
+#define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD))
|
|
+#endif
|
|
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
|
|
+# define FLEXARRAY
|
|
+#else
|
|
+# define FLEXARRAY 1
|
|
+#endif
|
|
#endif /* !defined(SQLITE_AMALGAMATION) */
|
|
|
|
/* Macro to check for 4-byte alignment. Only used inside of assert() */
|
|
@@ -212530,9 +213852,13 @@
|
|
RtreeGeomCallback cb; /* Info about the callback functions */
|
|
int nParam; /* Number of parameters to the SQL function */
|
|
sqlite3_value **apSqlParam; /* Original SQL parameter values */
|
|
- RtreeDValue aParam[1]; /* Values for parameters to the SQL function */
|
|
+ RtreeDValue aParam[FLEXARRAY]; /* Values for parameters to the SQL function */
|
|
};
|
|
|
|
+/* Size of an RtreeMatchArg object with N parameters */
|
|
+#define SZ_RTREEMATCHARG(N) \
|
|
+ (offsetof(RtreeMatchArg,aParam)+(N)*sizeof(RtreeDValue))
|
|
+
|
|
#ifndef MAX
|
|
# define MAX(x,y) ((x) < (y) ? (y) : (x))
|
|
#endif
|
|
@@ -214221,7 +215547,7 @@
|
|
}
|
|
|
|
/*
|
|
-** Return the N-dimensional volumn of the cell stored in *p.
|
|
+** Return the N-dimensional volume of the cell stored in *p.
|
|
*/
|
|
static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){
|
|
RtreeDValue area = (RtreeDValue)1;
|
|
@@ -215987,7 +217313,7 @@
|
|
/*
|
|
** The second and subsequent arguments to this function are a printf()
|
|
** style format string and arguments. This function formats the string and
|
|
-** appends it to the report being accumuated in pCheck.
|
|
+** appends it to the report being accumulated in pCheck.
|
|
*/
|
|
static void rtreeCheckAppendMsg(RtreeCheck *pCheck, const char *zFmt, ...){
|
|
va_list ap;
|
|
@@ -217175,7 +218501,7 @@
|
|
** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2).
|
|
** Returns:
|
|
**
|
|
-** +2 x0,y0 is on the line segement
|
|
+** +2 x0,y0 is on the line segment
|
|
**
|
|
** +1 x0,y0 is beneath line segment
|
|
**
|
|
@@ -217281,7 +218607,7 @@
|
|
sqlite3_free(p2);
|
|
}
|
|
|
|
-/* Objects used by the overlap algorihm. */
|
|
+/* Objects used by the overlap algorithm. */
|
|
typedef struct GeoEvent GeoEvent;
|
|
typedef struct GeoSegment GeoSegment;
|
|
typedef struct GeoOverlap GeoOverlap;
|
|
@@ -218328,8 +219654,7 @@
|
|
sqlite3_int64 nBlob;
|
|
int memErr = 0;
|
|
|
|
- nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue)
|
|
- + nArg*sizeof(sqlite3_value*);
|
|
+ nBlob = SZ_RTREEMATCHARG(nArg) + nArg*sizeof(sqlite3_value*);
|
|
pBlob = (RtreeMatchArg *)sqlite3_malloc64(nBlob);
|
|
if( !pBlob ){
|
|
sqlite3_result_error_nomem(ctx);
|
|
@@ -219424,7 +220749,7 @@
|
|
**
|
|
** "RBU" stands for "Resumable Bulk Update". As in a large database update
|
|
** transmitted via a wireless network to a mobile device. A transaction
|
|
-** applied using this extension is hence refered to as an "RBU update".
|
|
+** applied using this extension is hence referred to as an "RBU update".
|
|
**
|
|
**
|
|
** LIMITATIONS
|
|
@@ -219721,7 +221046,7 @@
|
|
** the next call to sqlite3rbu_vacuum() opens a handle that starts a
|
|
** new RBU vacuum operation.
|
|
**
|
|
-** As with sqlite3rbu_open(), Zipvfs users should rever to the comment
|
|
+** As with sqlite3rbu_open(), Zipvfs users should refer to the comment
|
|
** describing the sqlite3rbu_create_vfs() API function below for
|
|
** a description of the complications associated with using RBU with
|
|
** zipvfs databases.
|
|
@@ -219817,7 +221142,7 @@
|
|
**
|
|
** If the RBU update has been completely applied, mark the RBU database
|
|
** as fully applied. Otherwise, assuming no error has occurred, save the
|
|
-** current state of the RBU update appliation to the RBU database.
|
|
+** current state of the RBU update application to the RBU database.
|
|
**
|
|
** If an error has already occurred as part of an sqlite3rbu_step()
|
|
** or sqlite3rbu_open() call, or if one occurs within this function, an
|
|
@@ -224743,7 +226068,7 @@
|
|
|
|
/* If this is an RBU vacuum operation and this is the target database,
|
|
** pretend that it has at least one page. Otherwise, SQLite will not
|
|
- ** check for the existance of a *-wal file. rbuVfsRead() contains
|
|
+ ** check for the existence of a *-wal file. rbuVfsRead() contains
|
|
** similar logic. */
|
|
if( rc==SQLITE_OK && *pSize==0
|
|
&& p->pRbu && rbuIsVacuum(p->pRbu)
|
|
@@ -226675,8 +228000,8 @@
|
|
/* "INSERT INTO dbpage($PGNO,NULL)" causes page number $PGNO and
|
|
** all subsequent pages to be deleted. */
|
|
pTab->iDbTrunc = iDb;
|
|
- pgno--;
|
|
- pTab->pgnoTrunc = pgno;
|
|
+ pTab->pgnoTrunc = pgno-1;
|
|
+ pgno = 1;
|
|
}else{
|
|
zErr = "bad page value";
|
|
goto update_fail;
|
|
@@ -227973,7 +229298,7 @@
|
|
/*
|
|
** This function is called to initialize the SessionTable.nCol, azCol[]
|
|
** abPK[] and azDflt[] members of SessionTable object pTab. If these
|
|
-** fields are already initilialized, this function is a no-op.
|
|
+** fields are already initialized, this function is a no-op.
|
|
**
|
|
** If an error occurs, an error code is stored in sqlite3_session.rc and
|
|
** non-zero returned. Or, if no error occurs but the table has no primary
|
|
@@ -227992,6 +229317,8 @@
|
|
if( pTab->nCol==0 ){
|
|
u8 *abPK;
|
|
assert( pTab->azCol==0 || pTab->abPK==0 );
|
|
+ sqlite3_free(pTab->azCol);
|
|
+ pTab->abPK = 0;
|
|
rc = sessionTableInfo(pSession, db, zDb,
|
|
pTab->zName, &pTab->nCol, &pTab->nTotalCol, 0, &pTab->azCol,
|
|
&pTab->azDflt, &pTab->aiIdx, &abPK,
|
|
@@ -228999,7 +230326,9 @@
|
|
SessionTable *pTo; /* Table zTbl */
|
|
|
|
/* Locate and if necessary initialize the target table object */
|
|
+ pSession->bAutoAttach++;
|
|
rc = sessionFindTable(pSession, zTbl, &pTo);
|
|
+ pSession->bAutoAttach--;
|
|
if( pTo==0 ) goto diff_out;
|
|
if( sessionInitTable(pSession, pTo, pSession->db, pSession->zDb) ){
|
|
rc = pSession->rc;
|
|
@@ -229010,17 +230339,43 @@
|
|
if( rc==SQLITE_OK ){
|
|
int bHasPk = 0;
|
|
int bMismatch = 0;
|
|
- int nCol; /* Columns in zFrom.zTbl */
|
|
+ int nCol = 0; /* Columns in zFrom.zTbl */
|
|
int bRowid = 0;
|
|
- u8 *abPK;
|
|
+ u8 *abPK = 0;
|
|
const char **azCol = 0;
|
|
- rc = sessionTableInfo(0, db, zFrom, zTbl,
|
|
- &nCol, 0, 0, &azCol, 0, 0, &abPK,
|
|
- pSession->bImplicitPK ? &bRowid : 0
|
|
- );
|
|
+ char *zDbExists = 0;
|
|
+
|
|
+ /* Check that database zFrom is attached. */
|
|
+ zDbExists = sqlite3_mprintf("SELECT * FROM %Q.sqlite_schema", zFrom);
|
|
+ if( zDbExists==0 ){
|
|
+ rc = SQLITE_NOMEM;
|
|
+ }else{
|
|
+ sqlite3_stmt *pDbExists = 0;
|
|
+ rc = sqlite3_prepare_v2(db, zDbExists, -1, &pDbExists, 0);
|
|
+ if( rc==SQLITE_ERROR ){
|
|
+ rc = SQLITE_OK;
|
|
+ nCol = -1;
|
|
+ }
|
|
+ sqlite3_finalize(pDbExists);
|
|
+ sqlite3_free(zDbExists);
|
|
+ }
|
|
+
|
|
+ if( rc==SQLITE_OK && nCol==0 ){
|
|
+ rc = sessionTableInfo(0, db, zFrom, zTbl,
|
|
+ &nCol, 0, 0, &azCol, 0, 0, &abPK,
|
|
+ pSession->bImplicitPK ? &bRowid : 0
|
|
+ );
|
|
+ }
|
|
if( rc==SQLITE_OK ){
|
|
if( pTo->nCol!=nCol ){
|
|
- bMismatch = 1;
|
|
+ if( nCol<=0 ){
|
|
+ rc = SQLITE_SCHEMA;
|
|
+ if( pzErrMsg ){
|
|
+ *pzErrMsg = sqlite3_mprintf("no such table: %s.%s", zFrom, zTbl);
|
|
+ }
|
|
+ }else{
|
|
+ bMismatch = 1;
|
|
+ }
|
|
}else{
|
|
int i;
|
|
for(i=0; i<nCol; i++){
|
|
@@ -229796,7 +231151,7 @@
|
|
){
|
|
sqlite3 *db = pSession->db; /* Source database handle */
|
|
SessionTable *pTab; /* Used to iterate through attached tables */
|
|
- SessionBuffer buf = {0,0,0}; /* Buffer in which to accumlate changeset */
|
|
+ SessionBuffer buf = {0,0,0}; /* Buffer in which to accumulate changeset */
|
|
int rc; /* Return code */
|
|
|
|
assert( xOutput==0 || (pnChangeset==0 && ppChangeset==0) );
|
|
@@ -230149,14 +231504,15 @@
|
|
** object and the buffer is full, discard some data to free up space.
|
|
*/
|
|
static void sessionDiscardData(SessionInput *pIn){
|
|
- if( pIn->xInput && pIn->iNext>=sessions_strm_chunk_size ){
|
|
- int nMove = pIn->buf.nBuf - pIn->iNext;
|
|
+ if( pIn->xInput && pIn->iCurrent>=sessions_strm_chunk_size ){
|
|
+ int nMove = pIn->buf.nBuf - pIn->iCurrent;
|
|
assert( nMove>=0 );
|
|
if( nMove>0 ){
|
|
- memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iNext], nMove);
|
|
+ memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iCurrent], nMove);
|
|
}
|
|
- pIn->buf.nBuf -= pIn->iNext;
|
|
- pIn->iNext = 0;
|
|
+ pIn->buf.nBuf -= pIn->iCurrent;
|
|
+ pIn->iNext -= pIn->iCurrent;
|
|
+ pIn->iCurrent = 0;
|
|
pIn->nData = pIn->buf.nBuf;
|
|
}
|
|
}
|
|
@@ -230510,8 +231866,8 @@
|
|
p->rc = sessionInputBuffer(&p->in, 2);
|
|
if( p->rc!=SQLITE_OK ) return p->rc;
|
|
|
|
- sessionDiscardData(&p->in);
|
|
p->in.iCurrent = p->in.iNext;
|
|
+ sessionDiscardData(&p->in);
|
|
|
|
/* If the iterator is already at the end of the changeset, return DONE. */
|
|
if( p->in.iNext>=p->in.nData ){
|
|
@@ -232870,14 +234226,19 @@
|
|
sqlite3_changegroup *pGrp,
|
|
sqlite3_changeset_iter *pIter
|
|
){
|
|
+ int rc = SQLITE_OK;
|
|
+
|
|
if( pIter->in.iCurrent==pIter->in.iNext
|
|
|| pIter->rc!=SQLITE_OK
|
|
|| pIter->bInvert
|
|
){
|
|
/* Iterator does not point to any valid entry or is an INVERT iterator. */
|
|
- return SQLITE_ERROR;
|
|
+ rc = SQLITE_ERROR;
|
|
+ }else{
|
|
+ pIter->in.bNoDiscard = 1;
|
|
+ rc = sessionOneChangeToHash(pGrp, pIter, 0);
|
|
}
|
|
- return sessionOneChangeToHash(pGrp, pIter, 0);
|
|
+ return rc;
|
|
}
|
|
|
|
/*
|
|
@@ -234175,6 +235536,7 @@
|
|
|
|
/* #include <string.h> */
|
|
/* #include <assert.h> */
|
|
+/* #include <stddef.h> */
|
|
|
|
#ifndef SQLITE_AMALGAMATION
|
|
|
|
@@ -234230,6 +235592,18 @@
|
|
# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0)
|
|
#endif
|
|
|
|
+/*
|
|
+** Macros needed to provide flexible arrays in a portable way
|
|
+*/
|
|
+#ifndef offsetof
|
|
+# define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD))
|
|
+#endif
|
|
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
|
|
+# define FLEXARRAY
|
|
+#else
|
|
+# define FLEXARRAY 1
|
|
+#endif
|
|
+
|
|
#endif
|
|
|
|
/* Truncate very long tokens to this many bytes. Hard limit is
|
|
@@ -234302,10 +235676,11 @@
|
|
*/
|
|
struct Fts5Colset {
|
|
int nCol;
|
|
- int aiCol[1];
|
|
+ int aiCol[FLEXARRAY];
|
|
};
|
|
|
|
-
|
|
+/* Size (int bytes) of a complete Fts5Colset object with N columns. */
|
|
+#define SZ_FTS5COLSET(N) (sizeof(i64)*((N+2)/2))
|
|
|
|
/**************************************************************************
|
|
** Interface to code in fts5_config.c. fts5_config.c contains contains code
|
|
@@ -235134,7 +236509,7 @@
|
|
**
|
|
** The "lemon" program processes an LALR(1) input grammar file, then uses
|
|
** this template to construct a parser. The "lemon" program inserts text
|
|
-** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the
|
|
+** 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
|
|
@@ -237288,7 +238663,7 @@
|
|
** under consideration.
|
|
**
|
|
** The problem with this is that if (N < 2*nHit), the IDF is
|
|
- ** negative. Which is undesirable. So the mimimum allowable IDF is
|
|
+ ** negative. Which is undesirable. So the minimum allowable IDF is
|
|
** (1e-6) - roughly the same as a term that appears in just over
|
|
** half of set of 5,000,000 documents. */
|
|
double idf = log( (nRow - nHit + 0.5) / (nHit + 0.5) );
|
|
@@ -237751,7 +239126,7 @@
|
|
** * The 52 upper and lower case ASCII characters, and
|
|
** * The 10 integer ASCII characters.
|
|
** * The underscore character "_" (0x5F).
|
|
-** * The unicode "subsitute" character (0x1A).
|
|
+** * The unicode "substitute" character (0x1A).
|
|
*/
|
|
static int sqlite3Fts5IsBareword(char t){
|
|
u8 aBareword[128] = {
|
|
@@ -239069,9 +240444,13 @@
|
|
/* Child nodes. For a NOT node, this array always contains 2 entries. For
|
|
** AND or OR nodes, it contains 2 or more entries. */
|
|
int nChild; /* Number of child nodes */
|
|
- Fts5ExprNode *apChild[1]; /* Array of child nodes */
|
|
+ Fts5ExprNode *apChild[FLEXARRAY]; /* Array of child nodes */
|
|
};
|
|
|
|
+/* Size (in bytes) of an Fts5ExprNode object that holds up to N children */
|
|
+#define SZ_FTS5EXPRNODE(N) \
|
|
+ (offsetof(Fts5ExprNode,apChild) + (N)*sizeof(Fts5ExprNode*))
|
|
+
|
|
#define Fts5NodeIsString(p) ((p)->eType==FTS5_TERM || (p)->eType==FTS5_STRING)
|
|
|
|
/*
|
|
@@ -239102,9 +240481,13 @@
|
|
Fts5ExprNode *pNode; /* FTS5_STRING node this phrase is part of */
|
|
Fts5Buffer poslist; /* Current position list */
|
|
int nTerm; /* Number of entries in aTerm[] */
|
|
- Fts5ExprTerm aTerm[1]; /* Terms that make up this phrase */
|
|
+ Fts5ExprTerm aTerm[FLEXARRAY]; /* Terms that make up this phrase */
|
|
};
|
|
|
|
+/* Size (in bytes) of an Fts5ExprPhrase object that holds up to N terms */
|
|
+#define SZ_FTS5EXPRPHRASE(N) \
|
|
+ (offsetof(Fts5ExprPhrase,aTerm) + (N)*sizeof(Fts5ExprTerm))
|
|
+
|
|
/*
|
|
** One or more phrases that must appear within a certain token distance of
|
|
** each other within each matching document.
|
|
@@ -239113,9 +240496,12 @@
|
|
int nNear; /* NEAR parameter */
|
|
Fts5Colset *pColset; /* Columns to search (NULL -> all columns) */
|
|
int nPhrase; /* Number of entries in aPhrase[] array */
|
|
- Fts5ExprPhrase *apPhrase[1]; /* Array of phrase pointers */
|
|
+ Fts5ExprPhrase *apPhrase[FLEXARRAY]; /* Array of phrase pointers */
|
|
};
|
|
|
|
+/* Size (in bytes) of an Fts5ExprNearset object covering up to N phrases */
|
|
+#define SZ_FTS5EXPRNEARSET(N) \
|
|
+ (offsetof(Fts5ExprNearset,apPhrase)+(N)*sizeof(Fts5ExprPhrase*))
|
|
|
|
/*
|
|
** Parse context.
|
|
@@ -239275,7 +240661,7 @@
|
|
/* If the LHS of the MATCH expression was a user column, apply the
|
|
** implicit column-filter. */
|
|
if( sParse.rc==SQLITE_OK && iCol<pConfig->nCol ){
|
|
- int n = sizeof(Fts5Colset);
|
|
+ int n = SZ_FTS5COLSET(1);
|
|
Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n);
|
|
if( pColset ){
|
|
pColset->nCol = 1;
|
|
@@ -240633,7 +242019,7 @@
|
|
if( pParse->rc==SQLITE_OK ){
|
|
if( pNear==0 ){
|
|
sqlite3_int64 nByte;
|
|
- nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*);
|
|
+ nByte = SZ_FTS5EXPRNEARSET(SZALLOC+1);
|
|
pRet = sqlite3_malloc64(nByte);
|
|
if( pRet==0 ){
|
|
pParse->rc = SQLITE_NOMEM;
|
|
@@ -240644,7 +242030,7 @@
|
|
int nNew = pNear->nPhrase + SZALLOC;
|
|
sqlite3_int64 nByte;
|
|
|
|
- nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*);
|
|
+ nByte = SZ_FTS5EXPRNEARSET(nNew+1);
|
|
pRet = (Fts5ExprNearset*)sqlite3_realloc64(pNear, nByte);
|
|
if( pRet==0 ){
|
|
pParse->rc = SQLITE_NOMEM;
|
|
@@ -240735,12 +242121,12 @@
|
|
int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0);
|
|
|
|
pNew = (Fts5ExprPhrase*)sqlite3_realloc64(pPhrase,
|
|
- sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * nNew
|
|
+ SZ_FTS5EXPRPHRASE(nNew+1)
|
|
);
|
|
if( pNew==0 ){
|
|
rc = SQLITE_NOMEM;
|
|
}else{
|
|
- if( pPhrase==0 ) memset(pNew, 0, sizeof(Fts5ExprPhrase));
|
|
+ if( pPhrase==0 ) memset(pNew, 0, SZ_FTS5EXPRPHRASE(1));
|
|
pCtx->pPhrase = pPhrase = pNew;
|
|
pNew->nTerm = nNew - SZALLOC;
|
|
}
|
|
@@ -240848,7 +242234,7 @@
|
|
if( sCtx.pPhrase==0 ){
|
|
/* This happens when parsing a token or quoted phrase that contains
|
|
** no token characters at all. (e.g ... MATCH '""'). */
|
|
- sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5ExprPhrase));
|
|
+ sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, SZ_FTS5EXPRPHRASE(1));
|
|
}else if( sCtx.pPhrase->nTerm ){
|
|
sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = (u8)bPrefix;
|
|
}
|
|
@@ -240883,19 +242269,18 @@
|
|
sizeof(Fts5ExprPhrase*));
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
- pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc,
|
|
- sizeof(Fts5ExprNode));
|
|
+ pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, SZ_FTS5EXPRNODE(1));
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc,
|
|
- sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*));
|
|
+ SZ_FTS5EXPRNEARSET(2));
|
|
}
|
|
if( rc==SQLITE_OK && ALWAYS(pOrig!=0) ){
|
|
Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset;
|
|
if( pColsetOrig ){
|
|
sqlite3_int64 nByte;
|
|
Fts5Colset *pColset;
|
|
- nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int);
|
|
+ nByte = SZ_FTS5COLSET(pColsetOrig->nCol);
|
|
pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte);
|
|
if( pColset ){
|
|
memcpy(pColset, pColsetOrig, (size_t)nByte);
|
|
@@ -240923,7 +242308,7 @@
|
|
}else{
|
|
/* This happens when parsing a token or quoted phrase that contains
|
|
** no token characters at all. (e.g ... MATCH '""'). */
|
|
- sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
|
|
+ sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, SZ_FTS5EXPRPHRASE(1));
|
|
}
|
|
}
|
|
|
|
@@ -240988,7 +242373,8 @@
|
|
);
|
|
return;
|
|
}
|
|
- nNear = nNear * 10 + (p->p[i] - '0');
|
|
+ if( nNear<214748363 ) nNear = nNear * 10 + (p->p[i] - '0');
|
|
+ /* ^^^^^^^^^^^^^^^--- Prevent integer overflow */
|
|
}
|
|
}else{
|
|
nNear = FTS5_DEFAULT_NEARDIST;
|
|
@@ -241017,7 +242403,7 @@
|
|
assert( pParse->rc==SQLITE_OK );
|
|
assert( iCol>=0 && iCol<pParse->pConfig->nCol );
|
|
|
|
- pNew = sqlite3_realloc64(p, sizeof(Fts5Colset) + sizeof(int)*nCol);
|
|
+ pNew = sqlite3_realloc64(p, SZ_FTS5COLSET(nCol+1));
|
|
if( pNew==0 ){
|
|
pParse->rc = SQLITE_NOMEM;
|
|
}else{
|
|
@@ -241052,7 +242438,7 @@
|
|
int nCol = pParse->pConfig->nCol;
|
|
|
|
pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc,
|
|
- sizeof(Fts5Colset) + sizeof(int)*nCol
|
|
+ SZ_FTS5COLSET(nCol+1)
|
|
);
|
|
if( pRet ){
|
|
int i;
|
|
@@ -241113,7 +242499,7 @@
|
|
static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){
|
|
Fts5Colset *pRet;
|
|
if( pOrig ){
|
|
- sqlite3_int64 nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int);
|
|
+ sqlite3_int64 nByte = SZ_FTS5COLSET(pOrig->nCol);
|
|
pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte);
|
|
if( pRet ){
|
|
memcpy(pRet, pOrig, (size_t)nByte);
|
|
@@ -241281,7 +242667,7 @@
|
|
assert( pNear->nPhrase==1 );
|
|
assert( pParse->bPhraseToAnd );
|
|
|
|
- nByte = sizeof(Fts5ExprNode) + nTerm*sizeof(Fts5ExprNode*);
|
|
+ nByte = SZ_FTS5EXPRNODE(nTerm+1);
|
|
pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
|
|
if( pRet ){
|
|
pRet->eType = FTS5_AND;
|
|
@@ -241291,7 +242677,7 @@
|
|
pParse->nPhrase--;
|
|
for(ii=0; ii<nTerm; ii++){
|
|
Fts5ExprPhrase *pPhrase = (Fts5ExprPhrase*)sqlite3Fts5MallocZero(
|
|
- &pParse->rc, sizeof(Fts5ExprPhrase)
|
|
+ &pParse->rc, SZ_FTS5EXPRPHRASE(1)
|
|
);
|
|
if( pPhrase ){
|
|
if( parseGrowPhraseArray(pParse) ){
|
|
@@ -241360,7 +242746,7 @@
|
|
if( pRight->eType==eType ) nChild += pRight->nChild-1;
|
|
}
|
|
|
|
- nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1);
|
|
+ nByte = SZ_FTS5EXPRNODE(nChild);
|
|
pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
|
|
|
|
if( pRet ){
|
|
@@ -242235,7 +243621,7 @@
|
|
}
|
|
|
|
/*
|
|
-** Clear the token mappings for all Fts5IndexIter objects mannaged by
|
|
+** Clear the token mappings for all Fts5IndexIter objects managed by
|
|
** the expression passed as the only argument.
|
|
*/
|
|
static void sqlite3Fts5ExprClearTokens(Fts5Expr *pExpr){
|
|
@@ -242270,7 +243656,7 @@
|
|
|
|
/*
|
|
** This file contains the implementation of an in-memory hash table used
|
|
-** to accumuluate "term -> doclist" content before it is flused to a level-0
|
|
+** to accumulate "term -> doclist" content before it is flushed to a level-0
|
|
** segment.
|
|
*/
|
|
|
|
@@ -242327,7 +243713,7 @@
|
|
};
|
|
|
|
/*
|
|
-** Eqivalent to:
|
|
+** Equivalent to:
|
|
**
|
|
** char *fts5EntryKey(Fts5HashEntry *pEntry){ return zKey; }
|
|
*/
|
|
@@ -243263,9 +244649,13 @@
|
|
u64 nOriginCntr; /* Origin value for next top-level segment */
|
|
int nSegment; /* Total segments in this structure */
|
|
int nLevel; /* Number of levels in this index */
|
|
- Fts5StructureLevel aLevel[1]; /* Array of nLevel level objects */
|
|
+ Fts5StructureLevel aLevel[FLEXARRAY]; /* Array of nLevel level objects */
|
|
};
|
|
|
|
+/* Size (in bytes) of an Fts5Structure object holding up to N levels */
|
|
+#define SZ_FTS5STRUCTURE(N) \
|
|
+ (offsetof(Fts5Structure,aLevel) + (N)*sizeof(Fts5StructureLevel))
|
|
+
|
|
/*
|
|
** An object of type Fts5SegWriter is used to write to segments.
|
|
*/
|
|
@@ -243395,11 +244785,15 @@
|
|
** Array of tombstone pages. Reference counted.
|
|
*/
|
|
struct Fts5TombstoneArray {
|
|
- int nRef; /* Number of pointers to this object */
|
|
+ int nRef; /* Number of pointers to this object */
|
|
int nTombstone;
|
|
- Fts5Data *apTombstone[1]; /* Array of tombstone pages */
|
|
+ Fts5Data *apTombstone[FLEXARRAY]; /* Array of tombstone pages */
|
|
};
|
|
|
|
+/* Size (in bytes) of an Fts5TombstoneArray holding up to N tombstones */
|
|
+#define SZ_FTS5TOMBSTONEARRAY(N) \
|
|
+ (offsetof(Fts5TombstoneArray,apTombstone)+(N)*sizeof(Fts5Data*))
|
|
+
|
|
/*
|
|
** Argument is a pointer to an Fts5Data structure that contains a
|
|
** leaf page.
|
|
@@ -243468,9 +244862,12 @@
|
|
|
|
i64 iSwitchRowid; /* Firstest rowid of other than aFirst[1] */
|
|
Fts5CResult *aFirst; /* Current merge state (see above) */
|
|
- Fts5SegIter aSeg[1]; /* Array of segment iterators */
|
|
+ Fts5SegIter aSeg[FLEXARRAY]; /* Array of segment iterators */
|
|
};
|
|
|
|
+/* Size (in bytes) of an Fts5Iter object holding up to N segment iterators */
|
|
+#define SZ_FTS5ITER(N) (offsetof(Fts5Iter,aSeg)+(N)*sizeof(Fts5SegIter))
|
|
+
|
|
/*
|
|
** An instance of the following type is used to iterate through the contents
|
|
** of a doclist-index record.
|
|
@@ -243497,9 +244894,13 @@
|
|
struct Fts5DlidxIter {
|
|
int nLvl;
|
|
int iSegid;
|
|
- Fts5DlidxLvl aLvl[1];
|
|
+ Fts5DlidxLvl aLvl[FLEXARRAY];
|
|
};
|
|
|
|
+/* Size (in bytes) of an Fts5DlidxIter object with up to N levels */
|
|
+#define SZ_FTS5DLIDXITER(N) \
|
|
+ (offsetof(Fts5DlidxIter,aLvl)+(N)*sizeof(Fts5DlidxLvl))
|
|
+
|
|
static void fts5PutU16(u8 *aOut, u16 iVal){
|
|
aOut[0] = (iVal>>8);
|
|
aOut[1] = (iVal&0xFF);
|
|
@@ -243867,7 +245268,7 @@
|
|
static void fts5StructureMakeWritable(int *pRc, Fts5Structure **pp){
|
|
Fts5Structure *p = *pp;
|
|
if( *pRc==SQLITE_OK && p->nRef>1 ){
|
|
- i64 nByte = sizeof(Fts5Structure)+(p->nLevel-1)*sizeof(Fts5StructureLevel);
|
|
+ i64 nByte = SZ_FTS5STRUCTURE(p->nLevel);
|
|
Fts5Structure *pNew;
|
|
pNew = (Fts5Structure*)sqlite3Fts5MallocZero(pRc, nByte);
|
|
if( pNew ){
|
|
@@ -243941,10 +245342,7 @@
|
|
){
|
|
return FTS5_CORRUPT;
|
|
}
|
|
- nByte = (
|
|
- sizeof(Fts5Structure) + /* Main structure */
|
|
- sizeof(Fts5StructureLevel) * (nLevel-1) /* aLevel[] array */
|
|
- );
|
|
+ nByte = SZ_FTS5STRUCTURE(nLevel);
|
|
pRet = (Fts5Structure*)sqlite3Fts5MallocZero(&rc, nByte);
|
|
|
|
if( pRet ){
|
|
@@ -244024,10 +245422,7 @@
|
|
if( *pRc==SQLITE_OK ){
|
|
Fts5Structure *pStruct = *ppStruct;
|
|
int nLevel = pStruct->nLevel;
|
|
- sqlite3_int64 nByte = (
|
|
- sizeof(Fts5Structure) + /* Main structure */
|
|
- sizeof(Fts5StructureLevel) * (nLevel+1) /* aLevel[] array */
|
|
- );
|
|
+ sqlite3_int64 nByte = SZ_FTS5STRUCTURE(nLevel+2);
|
|
|
|
pStruct = sqlite3_realloc64(pStruct, nByte);
|
|
if( pStruct ){
|
|
@@ -244566,7 +245961,7 @@
|
|
int bDone = 0;
|
|
|
|
for(i=0; p->rc==SQLITE_OK && bDone==0; i++){
|
|
- sqlite3_int64 nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl);
|
|
+ sqlite3_int64 nByte = SZ_FTS5DLIDXITER(i+1);
|
|
Fts5DlidxIter *pNew;
|
|
|
|
pNew = (Fts5DlidxIter*)sqlite3_realloc64(pIter, nByte);
|
|
@@ -244782,9 +246177,9 @@
|
|
** leave an error in the Fts5Index object.
|
|
*/
|
|
static void fts5SegIterAllocTombstone(Fts5Index *p, Fts5SegIter *pIter){
|
|
- const int nTomb = pIter->pSeg->nPgTombstone;
|
|
+ const i64 nTomb = (i64)pIter->pSeg->nPgTombstone;
|
|
if( nTomb>0 ){
|
|
- int nByte = nTomb * sizeof(Fts5Data*) + sizeof(Fts5TombstoneArray);
|
|
+ i64 nByte = SZ_FTS5TOMBSTONEARRAY(nTomb+1);
|
|
Fts5TombstoneArray *pNew;
|
|
pNew = (Fts5TombstoneArray*)sqlite3Fts5MallocZero(&p->rc, nByte);
|
|
if( pNew ){
|
|
@@ -246245,8 +247640,7 @@
|
|
|
|
for(nSlot=2; nSlot<nSeg; nSlot=nSlot*2);
|
|
pNew = fts5IdxMalloc(p,
|
|
- sizeof(Fts5Iter) + /* pNew */
|
|
- sizeof(Fts5SegIter) * (nSlot-1) + /* pNew->aSeg[] */
|
|
+ SZ_FTS5ITER(nSlot) + /* pNew + pNew->aSeg[] */
|
|
sizeof(Fts5CResult) * nSlot /* pNew->aFirst[] */
|
|
);
|
|
if( pNew ){
|
|
@@ -248047,7 +249441,7 @@
|
|
int iDelKeyOff = 0; /* Offset of deleted key, if any */
|
|
|
|
nIdx = nPg-iPgIdx;
|
|
- aIdx = sqlite3Fts5MallocZero(&p->rc, nIdx+16);
|
|
+ aIdx = sqlite3Fts5MallocZero(&p->rc, ((i64)nIdx)+16);
|
|
if( p->rc ) return;
|
|
memcpy(aIdx, &aPg[iPgIdx], nIdx);
|
|
|
|
@@ -248612,7 +250006,7 @@
|
|
Fts5Structure *pStruct
|
|
){
|
|
Fts5Structure *pNew = 0;
|
|
- sqlite3_int64 nByte = sizeof(Fts5Structure);
|
|
+ sqlite3_int64 nByte = SZ_FTS5STRUCTURE(1);
|
|
int nSeg = pStruct->nSegment;
|
|
int i;
|
|
|
|
@@ -248641,7 +250035,8 @@
|
|
assert( pStruct->aLevel[i].nMerge<=nThis );
|
|
}
|
|
|
|
- nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel);
|
|
+ nByte += (((i64)pStruct->nLevel)+1) * sizeof(Fts5StructureLevel);
|
|
+ assert( nByte==SZ_FTS5STRUCTURE(pStruct->nLevel+2) );
|
|
pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte);
|
|
|
|
if( pNew ){
|
|
@@ -249218,9 +250613,13 @@
|
|
int nIterAlloc;
|
|
Fts5PoslistReader *aPoslistReader;
|
|
int *aPoslistToIter;
|
|
- Fts5Iter *apIter[1];
|
|
+ Fts5Iter *apIter[FLEXARRAY];
|
|
};
|
|
|
|
+/* Size in bytes of an Fts5TokenDataIter object holding up to N iterators */
|
|
+#define SZ_FTS5TOKENDATAITER(N) \
|
|
+ (offsetof(Fts5TokenDataIter,apIter) + (N)*sizeof(Fts5Iter))
|
|
+
|
|
/*
|
|
** The two input arrays - a1[] and a2[] - are in sorted order. This function
|
|
** merges the two arrays together and writes the result to output array
|
|
@@ -249292,7 +250691,7 @@
|
|
/*
|
|
** Sort the contents of the pT->aMap[] array.
|
|
**
|
|
-** The sorting algorithm requries a malloc(). If this fails, an error code
|
|
+** The sorting algorithm requires a malloc(). If this fails, an error code
|
|
** is left in Fts5Index.rc before returning.
|
|
*/
|
|
static void fts5TokendataIterSortMap(Fts5Index *p, Fts5TokenDataIter *pT){
|
|
@@ -249483,7 +250882,7 @@
|
|
&& p->pConfig->bPrefixInsttoken
|
|
){
|
|
s.pTokendata = &s2;
|
|
- s2.pT = (Fts5TokenDataIter*)fts5IdxMalloc(p, sizeof(*s2.pT));
|
|
+ s2.pT = (Fts5TokenDataIter*)fts5IdxMalloc(p, SZ_FTS5TOKENDATAITER(1));
|
|
}
|
|
|
|
if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
|
|
@@ -249529,7 +250928,8 @@
|
|
}
|
|
}
|
|
|
|
- pData = fts5IdxMalloc(p, sizeof(*pData)+s.doclist.n+FTS5_DATA_ZERO_PADDING);
|
|
+ pData = fts5IdxMalloc(p, sizeof(*pData)
|
|
+ + ((i64)s.doclist.n)+FTS5_DATA_ZERO_PADDING);
|
|
assert( pData!=0 || p->rc!=SQLITE_OK );
|
|
if( pData ){
|
|
pData->p = (u8*)&pData[1];
|
|
@@ -249610,15 +251010,17 @@
|
|
** and the initial version of the "averages" record (a zero-byte blob).
|
|
*/
|
|
static int sqlite3Fts5IndexReinit(Fts5Index *p){
|
|
- Fts5Structure s;
|
|
+ Fts5Structure *pTmp;
|
|
+ u8 tmpSpace[SZ_FTS5STRUCTURE(1)];
|
|
fts5StructureInvalidate(p);
|
|
fts5IndexDiscardData(p);
|
|
- memset(&s, 0, sizeof(Fts5Structure));
|
|
+ pTmp = (Fts5Structure*)tmpSpace;
|
|
+ memset(pTmp, 0, SZ_FTS5STRUCTURE(1));
|
|
if( p->pConfig->bContentlessDelete ){
|
|
- s.nOriginCntr = 1;
|
|
+ pTmp->nOriginCntr = 1;
|
|
}
|
|
fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0);
|
|
- fts5StructureWrite(p, &s);
|
|
+ fts5StructureWrite(p, pTmp);
|
|
return fts5IndexReturn(p);
|
|
}
|
|
|
|
@@ -249826,7 +251228,7 @@
|
|
if( p->rc==SQLITE_OK ){
|
|
if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){
|
|
int nAlloc = pIn ? pIn->nIterAlloc*2 : 16;
|
|
- int nByte = nAlloc * sizeof(Fts5Iter*) + sizeof(Fts5TokenDataIter);
|
|
+ int nByte = SZ_FTS5TOKENDATAITER(nAlloc+1);
|
|
Fts5TokenDataIter *pNew = (Fts5TokenDataIter*)sqlite3_realloc(pIn, nByte);
|
|
|
|
if( pNew==0 ){
|
|
@@ -250342,7 +251744,8 @@
|
|
|
|
fts5BufferGrow(&p->rc, &token, nToken+1);
|
|
assert( token.p!=0 || p->rc!=SQLITE_OK );
|
|
- ctx.pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, sizeof(*ctx.pT));
|
|
+ ctx.pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc,
|
|
+ SZ_FTS5TOKENDATAITER(1));
|
|
|
|
if( p->rc==SQLITE_OK ){
|
|
|
|
@@ -250473,7 +251876,8 @@
|
|
if( pIter->nSeg>0 ){
|
|
/* This is a prefix term iterator. */
|
|
if( pT==0 ){
|
|
- pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, sizeof(*pT));
|
|
+ pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc,
|
|
+ SZ_FTS5TOKENDATAITER(1));
|
|
pIter->pTokenDataIter = pT;
|
|
}
|
|
if( pT ){
|
|
@@ -251507,7 +252911,7 @@
|
|
|
|
#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
|
|
static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){
|
|
- int iSegid, iHeight, iPgno, bDlidx, bTomb; /* Rowid compenents */
|
|
+ int iSegid, iHeight, iPgno, bDlidx, bTomb; /* Rowid components */
|
|
fts5DecodeRowid(iKey, &bTomb, &iSegid, &bDlidx, &iHeight, &iPgno);
|
|
|
|
if( iSegid==0 ){
|
|
@@ -251753,7 +253157,7 @@
|
|
** buffer overreads even if the record is corrupt. */
|
|
n = sqlite3_value_bytes(apVal[1]);
|
|
aBlob = sqlite3_value_blob(apVal[1]);
|
|
- nSpace = n + FTS5_DATA_ZERO_PADDING;
|
|
+ nSpace = ((i64)n) + FTS5_DATA_ZERO_PADDING;
|
|
a = (u8*)sqlite3Fts5MallocZero(&rc, nSpace);
|
|
if( a==0 ) goto decode_out;
|
|
if( n>0 ) memcpy(a, aBlob, n);
|
|
@@ -252468,9 +253872,11 @@
|
|
i64 iRowid; /* Current rowid */
|
|
const u8 *aPoslist; /* Position lists for current row */
|
|
int nIdx; /* Number of entries in aIdx[] */
|
|
- int aIdx[1]; /* Offsets into aPoslist for current row */
|
|
+ int aIdx[FLEXARRAY]; /* Offsets into aPoslist for current row */
|
|
};
|
|
|
|
+/* Size (int bytes) of an Fts5Sorter object with N indexes */
|
|
+#define SZ_FTS5SORTER(N) (offsetof(Fts5Sorter,nIdx)+((N+2)/2)*sizeof(i64))
|
|
|
|
/*
|
|
** Virtual-table cursor object.
|
|
@@ -253348,7 +254754,7 @@
|
|
const char *zRankArgs = pCsr->zRankArgs;
|
|
|
|
nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
|
|
- nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1);
|
|
+ nByte = SZ_FTS5SORTER(nPhrase);
|
|
pSorter = (Fts5Sorter*)sqlite3_malloc64(nByte);
|
|
if( pSorter==0 ) return SQLITE_NOMEM;
|
|
memset(pSorter, 0, (size_t)nByte);
|
|
@@ -255874,7 +257280,7 @@
|
|
){
|
|
assert( nArg==0 );
|
|
UNUSED_PARAM2(nArg, apUnused);
|
|
- sqlite3_result_text(pCtx, "fts5: 2025-02-18 13:38:58 873d4e274b4988d260ba8354a9718324a1c26187a4ab4c1cc0227c03d0f10e70", -1, SQLITE_TRANSIENT);
|
|
+ sqlite3_result_text(pCtx, "fts5: 2025-07-17 13:25:10 3ce993b8657d6d9deda380a93cdd6404a8c8ba1b185b2bc423703e41ae5f2543", -1, SQLITE_TRANSIENT);
|
|
}
|
|
|
|
/*
|
|
@@ -256099,8 +257505,8 @@
|
|
** its entry point to enable the matchinfo() demo. */
|
|
#ifdef SQLITE_FTS5_ENABLE_TEST_MI
|
|
if( rc==SQLITE_OK ){
|
|
- extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*);
|
|
- rc = sqlite3Fts5TestRegisterMatchinfo(db);
|
|
+ extern int sqlite3Fts5TestRegisterMatchinfoAPI(fts5_api*);
|
|
+ rc = sqlite3Fts5TestRegisterMatchinfoAPI(&pGlobal->api);
|
|
}
|
|
#endif
|
|
|
|
@@ -256689,6 +258095,7 @@
|
|
for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
|
|
if( pConfig->abUnindexed[iCol-1]==0 ){
|
|
sqlite3_value *pVal = 0;
|
|
+ sqlite3_value *pFree = 0;
|
|
const char *pText = 0;
|
|
int nText = 0;
|
|
const char *pLoc = 0;
|
|
@@ -256705,11 +258112,22 @@
|
|
if( pConfig->bLocale && sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
|
|
rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
|
|
}else{
|
|
- pText = (const char*)sqlite3_value_text(pVal);
|
|
- nText = sqlite3_value_bytes(pVal);
|
|
- if( pConfig->bLocale && pSeek ){
|
|
- pLoc = (const char*)sqlite3_column_text(pSeek, iCol + pConfig->nCol);
|
|
- nLoc = sqlite3_column_bytes(pSeek, iCol + pConfig->nCol);
|
|
+ if( sqlite3_value_type(pVal)!=SQLITE_TEXT ){
|
|
+ /* Make a copy of the value to work with. This is because the call
|
|
+ ** to sqlite3_value_text() below forces the type of the value to
|
|
+ ** SQLITE_TEXT, and we may need to use it again later. */
|
|
+ pFree = pVal = sqlite3_value_dup(pVal);
|
|
+ if( pVal==0 ){
|
|
+ rc = SQLITE_NOMEM;
|
|
+ }
|
|
+ }
|
|
+ if( rc==SQLITE_OK ){
|
|
+ pText = (const char*)sqlite3_value_text(pVal);
|
|
+ nText = sqlite3_value_bytes(pVal);
|
|
+ if( pConfig->bLocale && pSeek ){
|
|
+ pLoc = (const char*)sqlite3_column_text(pSeek, iCol+pConfig->nCol);
|
|
+ nLoc = sqlite3_column_bytes(pSeek, iCol + pConfig->nCol);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -256725,6 +258143,7 @@
|
|
}
|
|
sqlite3Fts5ClearLocale(pConfig);
|
|
}
|
|
+ sqlite3_value_free(pFree);
|
|
}
|
|
}
|
|
if( rc==SQLITE_OK && p->nTotalRow<1 ){
|
|
@@ -259938,7 +261357,6 @@
|
|
aAscii[0] = 0; /* 0x00 is never a token character */
|
|
}
|
|
|
|
-
|
|
/*
|
|
** 2015 May 30
|
|
**
|
|
@@ -260479,12 +261897,12 @@
|
|
*pzErr = sqlite3_mprintf("wrong number of vtable arguments");
|
|
rc = SQLITE_ERROR;
|
|
}else{
|
|
- int nByte; /* Bytes of space to allocate */
|
|
+ i64 nByte; /* Bytes of space to allocate */
|
|
const char *zDb = bDb ? argv[3] : argv[1];
|
|
const char *zTab = bDb ? argv[4] : argv[3];
|
|
const char *zType = bDb ? argv[5] : argv[4];
|
|
- int nDb = (int)strlen(zDb)+1;
|
|
- int nTab = (int)strlen(zTab)+1;
|
|
+ i64 nDb = strlen(zDb)+1;
|
|
+ i64 nTab = strlen(zTab)+1;
|
|
int eType = 0;
|
|
|
|
rc = fts5VocabTableType(zType, pzErr, &eType);
|
|
diff --color -ruN node-v22.16.0/deps/sqlite/sqlite3ext.h node-modded/deps/sqlite/sqlite3ext.h
|
|
--- node-v22.16.0/deps/sqlite/sqlite3ext.h 2025-05-21 06:12:48.000000000 +0200
|
|
+++ node-modded/deps/sqlite/sqlite3ext.h 2025-07-17 16:20:17.642660211 +0200
|
|
@@ -366,6 +366,8 @@
|
|
/* Version 3.44.0 and later */
|
|
void *(*get_clientdata)(sqlite3*,const char*);
|
|
int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
|
|
+ /* Version 3.50.0 and later */
|
|
+ int (*setlk_timeout)(sqlite3*,int,int);
|
|
};
|
|
|
|
/*
|
|
@@ -699,6 +701,8 @@
|
|
/* Version 3.44.0 and later */
|
|
#define sqlite3_get_clientdata sqlite3_api->get_clientdata
|
|
#define sqlite3_set_clientdata sqlite3_api->set_clientdata
|
|
+/* Version 3.50.0 and later */
|
|
+#define sqlite3_setlk_timeout sqlite3_api->setlk_timeout
|
|
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
|
|
|
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
|
diff --color -ruN node-v22.16.0/deps/sqlite/sqlite3.h node-modded/deps/sqlite/sqlite3.h
|
|
--- node-v22.16.0/deps/sqlite/sqlite3.h 2025-05-21 06:12:48.000000000 +0200
|
|
+++ node-modded/deps/sqlite/sqlite3.h 2025-07-17 16:20:17.635901069 +0200
|
|
@@ -133,7 +133,7 @@
|
|
**
|
|
** Since [version 3.6.18] ([dateof:3.6.18]),
|
|
** SQLite source code has been stored in the
|
|
-** <a href="http://www.fossil-scm.org/">Fossil configuration management
|
|
+** <a href="http://fossil-scm.org/">Fossil configuration management
|
|
** system</a>. ^The SQLITE_SOURCE_ID macro evaluates to
|
|
** a string which identifies a particular check-in of SQLite
|
|
** within its configuration management system. ^The SQLITE_SOURCE_ID
|
|
@@ -146,9 +146,9 @@
|
|
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
|
** [sqlite_version()] and [sqlite_source_id()].
|
|
*/
|
|
-#define SQLITE_VERSION "3.49.1"
|
|
-#define SQLITE_VERSION_NUMBER 3049001
|
|
-#define SQLITE_SOURCE_ID "2025-02-18 13:38:58 873d4e274b4988d260ba8354a9718324a1c26187a4ab4c1cc0227c03d0f10e70"
|
|
+#define SQLITE_VERSION "3.50.3"
|
|
+#define SQLITE_VERSION_NUMBER 3050003
|
|
+#define SQLITE_SOURCE_ID "2025-07-17 13:25:10 3ce993b8657d6d9deda380a93cdd6404a8c8ba1b185b2bc423703e41ae5f2543"
|
|
|
|
/*
|
|
** CAPI3REF: Run-Time Library Version Numbers
|
|
@@ -1163,6 +1163,12 @@
|
|
** the value that M is to be set to. Before returning, the 32-bit signed
|
|
** integer is overwritten with the previous value of M.
|
|
**
|
|
+** <li>[[SQLITE_FCNTL_BLOCK_ON_CONNECT]]
|
|
+** The [SQLITE_FCNTL_BLOCK_ON_CONNECT] opcode is used to configure the
|
|
+** VFS to block when taking a SHARED lock to connect to a wal mode database.
|
|
+** This is used to implement the functionality associated with
|
|
+** SQLITE_SETLK_BLOCK_ON_CONNECT.
|
|
+**
|
|
** <li>[[SQLITE_FCNTL_DATA_VERSION]]
|
|
** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to
|
|
** a database file. The argument is a pointer to a 32-bit unsigned integer.
|
|
@@ -1259,6 +1265,7 @@
|
|
#define SQLITE_FCNTL_CKSM_FILE 41
|
|
#define SQLITE_FCNTL_RESET_CACHE 42
|
|
#define SQLITE_FCNTL_NULL_IO 43
|
|
+#define SQLITE_FCNTL_BLOCK_ON_CONNECT 44
|
|
|
|
/* deprecated names */
|
|
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
|
|
@@ -1989,13 +1996,16 @@
|
|
**
|
|
** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt>
|
|
** <dd> ^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine
|
|
-** the default size of lookaside memory on each [database connection].
|
|
+** the default size of [lookaside memory] on each [database connection].
|
|
** The first argument is the
|
|
-** size of each lookaside buffer slot and the second is the number of
|
|
-** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE
|
|
-** sets the <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE]
|
|
-** option to [sqlite3_db_config()] can be used to change the lookaside
|
|
-** configuration on individual connections.)^ </dd>
|
|
+** size of each lookaside buffer slot ("sz") and the second is the number of
|
|
+** slots allocated to each database connection ("cnt").)^
|
|
+** ^(SQLITE_CONFIG_LOOKASIDE sets the <i>default</i> lookaside size.
|
|
+** The [SQLITE_DBCONFIG_LOOKASIDE] option to [sqlite3_db_config()] can
|
|
+** be used to change the lookaside configuration on individual connections.)^
|
|
+** The [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to change the
|
|
+** default lookaside configuration at compile-time.
|
|
+** </dd>
|
|
**
|
|
** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt>
|
|
** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is
|
|
@@ -2232,31 +2242,50 @@
|
|
** [[SQLITE_DBCONFIG_LOOKASIDE]]
|
|
** <dt>SQLITE_DBCONFIG_LOOKASIDE</dt>
|
|
** <dd> The SQLITE_DBCONFIG_LOOKASIDE option is used to adjust the
|
|
-** configuration of the lookaside memory allocator within a database
|
|
+** configuration of the [lookaside memory allocator] within a database
|
|
** connection.
|
|
** The arguments to the SQLITE_DBCONFIG_LOOKASIDE option are <i>not</i>
|
|
** in the [DBCONFIG arguments|usual format].
|
|
** The SQLITE_DBCONFIG_LOOKASIDE option takes three arguments, not two,
|
|
** so that a call to [sqlite3_db_config()] that uses SQLITE_DBCONFIG_LOOKASIDE
|
|
** should have a total of five parameters.
|
|
-** ^The first argument (the third parameter to [sqlite3_db_config()] is a
|
|
+** <ol>
|
|
+** <li><p>The first argument ("buf") is a
|
|
** pointer to a memory buffer to use for lookaside memory.
|
|
-** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb
|
|
-** may be NULL in which case SQLite will allocate the
|
|
-** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the
|
|
-** size of each lookaside buffer slot. ^The third argument is the number of
|
|
-** slots. The size of the buffer in the first argument must be greater than
|
|
-** or equal to the product of the second and third arguments. The buffer
|
|
-** must be aligned to an 8-byte boundary. ^If the second argument to
|
|
-** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally
|
|
-** rounded down to the next smaller multiple of 8. ^(The lookaside memory
|
|
+** The first argument may be NULL in which case SQLite will allocate the
|
|
+** lookaside buffer itself using [sqlite3_malloc()].
|
|
+** <li><P>The second argument ("sz") is the
|
|
+** size of each lookaside buffer slot. Lookaside is disabled if "sz"
|
|
+** is less than 8. The "sz" argument should be a multiple of 8 less than
|
|
+** 65536. If "sz" does not meet this constraint, it is reduced in size until
|
|
+** it does.
|
|
+** <li><p>The third argument ("cnt") is the number of slots. Lookaside is disabled
|
|
+** if "cnt"is less than 1. The "cnt" value will be reduced, if necessary, so
|
|
+** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt"
|
|
+** parameter is usually chosen so that the product of "sz" and "cnt" is less
|
|
+** than 1,000,000.
|
|
+** </ol>
|
|
+** <p>If the "buf" argument is not NULL, then it must
|
|
+** point to a memory buffer with a size that is greater than
|
|
+** or equal to the product of "sz" and "cnt".
|
|
+** The buffer must be aligned to an 8-byte boundary.
|
|
+** The lookaside memory
|
|
** configuration for a database connection can only be changed when that
|
|
** connection is not currently using lookaside memory, or in other words
|
|
-** when the "current value" returned by
|
|
-** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero.
|
|
+** when the value returned by [SQLITE_DBSTATUS_LOOKASIDE_USED] is zero.
|
|
** Any attempt to change the lookaside memory configuration when lookaside
|
|
** memory is in use leaves the configuration unchanged and returns
|
|
-** [SQLITE_BUSY].)^</dd>
|
|
+** [SQLITE_BUSY].
|
|
+** If the "buf" argument is NULL and an attempt
|
|
+** to allocate memory based on "sz" and "cnt" fails, then
|
|
+** lookaside is silently disabled.
|
|
+** <p>
|
|
+** The [SQLITE_CONFIG_LOOKASIDE] configuration option can be used to set the
|
|
+** default lookaside configuration at initialization. The
|
|
+** [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to set the default lookaside
|
|
+** configuration at compile-time. Typical values for lookaside are 1200 for
|
|
+** "sz" and 40 to 100 for "cnt".
|
|
+** </dd>
|
|
**
|
|
** [[SQLITE_DBCONFIG_ENABLE_FKEY]]
|
|
** <dt>SQLITE_DBCONFIG_ENABLE_FKEY</dt>
|
|
@@ -2994,6 +3023,44 @@
|
|
SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
|
|
|
|
/*
|
|
+** CAPI3REF: Set the Setlk Timeout
|
|
+** METHOD: sqlite3
|
|
+**
|
|
+** This routine is only useful in SQLITE_ENABLE_SETLK_TIMEOUT builds. If
|
|
+** the VFS supports blocking locks, it sets the timeout in ms used by
|
|
+** eligible locks taken on wal mode databases by the specified database
|
|
+** handle. In non-SQLITE_ENABLE_SETLK_TIMEOUT builds, or if the VFS does
|
|
+** not support blocking locks, this function is a no-op.
|
|
+**
|
|
+** Passing 0 to this function disables blocking locks altogether. Passing
|
|
+** -1 to this function requests that the VFS blocks for a long time -
|
|
+** indefinitely if possible. The results of passing any other negative value
|
|
+** are undefined.
|
|
+**
|
|
+** Internally, each SQLite database handle store two timeout values - the
|
|
+** busy-timeout (used for rollback mode databases, or if the VFS does not
|
|
+** support blocking locks) and the setlk-timeout (used for blocking locks
|
|
+** on wal-mode databases). The sqlite3_busy_timeout() method sets both
|
|
+** values, this function sets only the setlk-timeout value. Therefore,
|
|
+** to configure separate busy-timeout and setlk-timeout values for a single
|
|
+** database handle, call sqlite3_busy_timeout() followed by this function.
|
|
+**
|
|
+** Whenever the number of connections to a wal mode database falls from
|
|
+** 1 to 0, the last connection takes an exclusive lock on the database,
|
|
+** then checkpoints and deletes the wal file. While it is doing this, any
|
|
+** new connection that tries to read from the database fails with an
|
|
+** SQLITE_BUSY error. Or, if the SQLITE_SETLK_BLOCK_ON_CONNECT flag is
|
|
+** passed to this API, the new connection blocks until the exclusive lock
|
|
+** has been released.
|
|
+*/
|
|
+SQLITE_API int sqlite3_setlk_timeout(sqlite3*, int ms, int flags);
|
|
+
|
|
+/*
|
|
+** CAPI3REF: Flags for sqlite3_setlk_timeout()
|
|
+*/
|
|
+#define SQLITE_SETLK_BLOCK_ON_CONNECT 0x01
|
|
+
|
|
+/*
|
|
** CAPI3REF: Convenience Routines For Running Queries
|
|
** METHOD: sqlite3
|
|
**
|
|
@@ -4012,7 +4079,7 @@
|
|
**
|
|
** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
|
|
** database filename D with corresponding journal file J and WAL file W and
|
|
-** with N URI parameters key/values pairs in the array P. The result from
|
|
+** an array P of N URI Key/Value pairs. The result from
|
|
** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that
|
|
** is safe to pass to routines like:
|
|
** <ul>
|
|
@@ -4693,7 +4760,7 @@
|
|
** METHOD: sqlite3_stmt
|
|
**
|
|
** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants,
|
|
-** literals may be replaced by a [parameter] that matches one of following
|
|
+** literals may be replaced by a [parameter] that matches one of the following
|
|
** templates:
|
|
**
|
|
** <ul>
|
|
@@ -4738,7 +4805,7 @@
|
|
**
|
|
** [[byte-order determination rules]] ^The byte-order of
|
|
** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF)
|
|
-** found in first character, which is removed, or in the absence of a BOM
|
|
+** found in the first character, which is removed, or in the absence of a BOM
|
|
** the byte order is the native byte order of the host
|
|
** machine for sqlite3_bind_text16() or the byte order specified in
|
|
** the 6th parameter for sqlite3_bind_text64().)^
|
|
@@ -4758,7 +4825,7 @@
|
|
** or sqlite3_bind_text16() or sqlite3_bind_text64() then
|
|
** that parameter must be the byte offset
|
|
** where the NUL terminator would occur assuming the string were NUL
|
|
-** terminated. If any NUL characters occurs at byte offsets less than
|
|
+** terminated. If any NUL characters occur at byte offsets less than
|
|
** the value of the fourth parameter then the resulting string value will
|
|
** contain embedded NULs. The result of expressions involving strings
|
|
** with embedded NULs is undefined.
|
|
@@ -4970,7 +5037,7 @@
|
|
** METHOD: sqlite3_stmt
|
|
**
|
|
** ^These routines provide a means to determine the database, table, and
|
|
-** table column that is the origin of a particular result column in
|
|
+** table column that is the origin of a particular result column in a
|
|
** [SELECT] statement.
|
|
** ^The name of the database or table or column can be returned as
|
|
** either a UTF-8 or UTF-16 string. ^The _database_ routines return
|
|
@@ -5108,7 +5175,7 @@
|
|
** other than [SQLITE_ROW] before any subsequent invocation of
|
|
** sqlite3_step(). Failure to reset the prepared statement using
|
|
** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
|
|
-** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1],
|
|
+** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1]),
|
|
** sqlite3_step() began
|
|
** calling [sqlite3_reset()] automatically in this circumstance rather
|
|
** than returning [SQLITE_MISUSE]. This is not considered a compatibility
|
|
@@ -5539,8 +5606,8 @@
|
|
**
|
|
** For best security, the [SQLITE_DIRECTONLY] flag is recommended for
|
|
** all application-defined SQL functions that do not need to be
|
|
-** used inside of triggers, view, CHECK constraints, or other elements of
|
|
-** the database schema. This flags is especially recommended for SQL
|
|
+** used inside of triggers, views, CHECK constraints, or other elements of
|
|
+** the database schema. This flag is especially recommended for SQL
|
|
** functions that have side effects or reveal internal application state.
|
|
** Without this flag, an attacker might be able to modify the schema of
|
|
** a database file to include invocations of the function with parameters
|
|
@@ -5571,7 +5638,7 @@
|
|
** [user-defined window functions|available here].
|
|
**
|
|
** ^(If the final parameter to sqlite3_create_function_v2() or
|
|
-** sqlite3_create_window_function() is not NULL, then it is destructor for
|
|
+** sqlite3_create_window_function() is not NULL, then it is the destructor for
|
|
** the application data pointer. The destructor is invoked when the function
|
|
** is deleted, either by being overloaded or when the database connection
|
|
** closes.)^ ^The destructor is also invoked if the call to
|
|
@@ -5971,7 +6038,7 @@
|
|
** METHOD: sqlite3_value
|
|
**
|
|
** ^The sqlite3_value_dup(V) interface makes a copy of the [sqlite3_value]
|
|
-** object D and returns a pointer to that copy. ^The [sqlite3_value] returned
|
|
+** object V and returns a pointer to that copy. ^The [sqlite3_value] returned
|
|
** is a [protected sqlite3_value] object even if the input is not.
|
|
** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a
|
|
** memory allocation fails. ^If V is a [pointer value], then the result
|
|
@@ -6009,7 +6076,7 @@
|
|
** allocation error occurs.
|
|
**
|
|
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
|
|
-** determined by the N parameter on first successful call. Changing the
|
|
+** determined by the N parameter on the first successful call. Changing the
|
|
** value of N in any subsequent call to sqlite3_aggregate_context() within
|
|
** the same aggregate function instance will not resize the memory
|
|
** allocation.)^ Within the xFinal callback, it is customary to set
|
|
@@ -6171,7 +6238,7 @@
|
|
**
|
|
** Security Warning: These interfaces should not be exposed in scripting
|
|
** languages or in other circumstances where it might be possible for an
|
|
-** an attacker to invoke them. Any agent that can invoke these interfaces
|
|
+** attacker to invoke them. Any agent that can invoke these interfaces
|
|
** can probably also take control of the process.
|
|
**
|
|
** Database connection client data is only available for SQLite
|
|
@@ -6285,7 +6352,7 @@
|
|
** pointed to by the 2nd parameter are taken as the application-defined
|
|
** function result. If the 3rd parameter is non-negative, then it
|
|
** must be the byte offset into the string where the NUL terminator would
|
|
-** appear if the string where NUL terminated. If any NUL characters occur
|
|
+** appear if the string were NUL terminated. If any NUL characters occur
|
|
** in the string at a byte offset that is less than the value of the 3rd
|
|
** parameter, then the resulting string will contain embedded NULs and the
|
|
** result of expressions operating on strings with embedded NULs is undefined.
|
|
@@ -6343,7 +6410,7 @@
|
|
** string and preferably a string literal. The sqlite3_result_pointer()
|
|
** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
|
|
**
|
|
-** If these routines are called from within the different thread
|
|
+** If these routines are called from within a different thread
|
|
** than the one containing the application-defined function that received
|
|
** the [sqlite3_context] pointer, the results are undefined.
|
|
*/
|
|
@@ -6749,7 +6816,7 @@
|
|
** METHOD: sqlite3
|
|
**
|
|
** ^The sqlite3_db_name(D,N) interface returns a pointer to the schema name
|
|
-** for the N-th database on database connection D, or a NULL pointer of N is
|
|
+** for the N-th database on database connection D, or a NULL pointer if N is
|
|
** out of range. An N value of 0 means the main database file. An N of 1 is
|
|
** the "temp" schema. Larger values of N correspond to various ATTACH-ed
|
|
** databases.
|
|
@@ -6844,7 +6911,7 @@
|
|
** <dd>The SQLITE_TXN_READ state means that the database is currently
|
|
** in a read transaction. Content has been read from the database file
|
|
** but nothing in the database file has changed. The transaction state
|
|
-** will advanced to SQLITE_TXN_WRITE if any changes occur and there are
|
|
+** will be advanced to SQLITE_TXN_WRITE if any changes occur and there are
|
|
** no other conflicting concurrent write transactions. The transaction
|
|
** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or
|
|
** [COMMIT].</dd>
|
|
@@ -6853,7 +6920,7 @@
|
|
** <dd>The SQLITE_TXN_WRITE state means that the database is currently
|
|
** in a write transaction. Content has been written to the database file
|
|
** but has not yet committed. The transaction state will change to
|
|
-** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].</dd>
|
|
+** SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].</dd>
|
|
*/
|
|
#define SQLITE_TXN_NONE 0
|
|
#define SQLITE_TXN_READ 1
|
|
@@ -7004,6 +7071,8 @@
|
|
**
|
|
** ^The second argument is a pointer to the function to invoke when a
|
|
** row is updated, inserted or deleted in a rowid table.
|
|
+** ^The update hook is disabled by invoking sqlite3_update_hook()
|
|
+** with a NULL pointer as the second parameter.
|
|
** ^The first argument to the callback is a copy of the third argument
|
|
** to sqlite3_update_hook().
|
|
** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE],
|
|
@@ -7132,7 +7201,7 @@
|
|
** CAPI3REF: Impose A Limit On Heap Size
|
|
**
|
|
** These interfaces impose limits on the amount of heap memory that will be
|
|
-** by all database connections within a single process.
|
|
+** used by all database connections within a single process.
|
|
**
|
|
** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the
|
|
** soft limit on the amount of heap memory that may be allocated by SQLite.
|
|
@@ -7190,7 +7259,7 @@
|
|
** </ul>)^
|
|
**
|
|
** The circumstances under which SQLite will enforce the heap limits may
|
|
-** changes in future releases of SQLite.
|
|
+** change in future releases of SQLite.
|
|
*/
|
|
SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
|
|
SQLITE_API sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 N);
|
|
@@ -7305,8 +7374,8 @@
|
|
** ^The entry point is zProc.
|
|
** ^(zProc may be 0, in which case SQLite will try to come up with an
|
|
** entry point name on its own. It first tries "sqlite3_extension_init".
|
|
-** If that does not work, it constructs a name "sqlite3_X_init" where the
|
|
-** X is consists of the lower-case equivalent of all ASCII alphabetic
|
|
+** If that does not work, it constructs a name "sqlite3_X_init" where
|
|
+** X consists of the lower-case equivalent of all ASCII alphabetic
|
|
** characters in the filename from the last "/" to the first following
|
|
** "." and omitting any initial "lib".)^
|
|
** ^The sqlite3_load_extension() interface returns
|
|
@@ -7377,7 +7446,7 @@
|
|
** ^(Even though the function prototype shows that xEntryPoint() takes
|
|
** no arguments and returns void, SQLite invokes xEntryPoint() with three
|
|
** arguments and expects an integer result as if the signature of the
|
|
-** entry point where as follows:
|
|
+** entry point were as follows:
|
|
**
|
|
** <blockquote><pre>
|
|
** int xEntryPoint(
|
|
@@ -7541,7 +7610,7 @@
|
|
** virtual table and might not be checked again by the byte code.)^ ^(The
|
|
** aConstraintUsage[].omit flag is an optimization hint. When the omit flag
|
|
** is left in its default setting of false, the constraint will always be
|
|
-** checked separately in byte code. If the omit flag is change to true, then
|
|
+** checked separately in byte code. If the omit flag is changed to true, then
|
|
** the constraint may or may not be checked in byte code. In other words,
|
|
** when the omit flag is true there is no guarantee that the constraint will
|
|
** not be checked again using byte code.)^
|
|
@@ -7567,7 +7636,7 @@
|
|
** The xBestIndex method may optionally populate the idxFlags field with a
|
|
** mask of SQLITE_INDEX_SCAN_* flags. One such flag is
|
|
** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN]
|
|
-** output to show the idxNum has hex instead of as decimal. Another flag is
|
|
+** output to show the idxNum as hex instead of as decimal. Another flag is
|
|
** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will
|
|
** return at most one row.
|
|
**
|
|
@@ -7708,7 +7777,7 @@
|
|
** the implementation of the [virtual table module]. ^The fourth
|
|
** parameter is an arbitrary client data pointer that is passed through
|
|
** into the [xCreate] and [xConnect] methods of the virtual table module
|
|
-** when a new virtual table is be being created or reinitialized.
|
|
+** when a new virtual table is being created or reinitialized.
|
|
**
|
|
** ^The sqlite3_create_module_v2() interface has a fifth parameter which
|
|
** is a pointer to a destructor for the pClientData. ^SQLite will
|
|
@@ -7873,7 +7942,7 @@
|
|
** in *ppBlob. Otherwise an [error code] is returned and, unless the error
|
|
** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided
|
|
** the API is not misused, it is always safe to call [sqlite3_blob_close()]
|
|
-** on *ppBlob after this function it returns.
|
|
+** on *ppBlob after this function returns.
|
|
**
|
|
** This function fails with SQLITE_ERROR if any of the following are true:
|
|
** <ul>
|
|
@@ -7993,7 +8062,7 @@
|
|
**
|
|
** ^Returns the size in bytes of the BLOB accessible via the
|
|
** successfully opened [BLOB handle] in its only argument. ^The
|
|
-** incremental blob I/O routines can only read or overwriting existing
|
|
+** incremental blob I/O routines can only read or overwrite existing
|
|
** blob content; they cannot change the size of a blob.
|
|
**
|
|
** This routine only works on a [BLOB handle] which has been created
|
|
@@ -8143,7 +8212,7 @@
|
|
** ^The sqlite3_mutex_alloc() routine allocates a new
|
|
** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc()
|
|
** routine returns NULL if it is unable to allocate the requested
|
|
-** mutex. The argument to sqlite3_mutex_alloc() must one of these
|
|
+** mutex. The argument to sqlite3_mutex_alloc() must be one of these
|
|
** integer constants:
|
|
**
|
|
** <ul>
|
|
@@ -8376,7 +8445,7 @@
|
|
** CAPI3REF: Retrieve the mutex for a database connection
|
|
** METHOD: sqlite3
|
|
**
|
|
-** ^This interface returns a pointer the [sqlite3_mutex] object that
|
|
+** ^This interface returns a pointer to the [sqlite3_mutex] object that
|
|
** serializes access to the [database connection] given in the argument
|
|
** when the [threading mode] is Serialized.
|
|
** ^If the [threading mode] is Single-thread or Multi-thread then this
|
|
@@ -8499,7 +8568,7 @@
|
|
** CAPI3REF: SQL Keyword Checking
|
|
**
|
|
** These routines provide access to the set of SQL language keywords
|
|
-** recognized by SQLite. Applications can uses these routines to determine
|
|
+** recognized by SQLite. Applications can use these routines to determine
|
|
** whether or not a specific identifier needs to be escaped (for example,
|
|
** by enclosing in double-quotes) so as not to confuse the parser.
|
|
**
|
|
@@ -8667,7 +8736,7 @@
|
|
** content of the dynamic string under construction in X. The value
|
|
** returned by [sqlite3_str_value(X)] is managed by the sqlite3_str object X
|
|
** and might be freed or altered by any subsequent method on the same
|
|
-** [sqlite3_str] object. Applications must not used the pointer returned
|
|
+** [sqlite3_str] object. Applications must not use the pointer returned by
|
|
** [sqlite3_str_value(X)] after any subsequent method call on the same
|
|
** object. ^Applications may change the content of the string returned
|
|
** by [sqlite3_str_value(X)] as long as they do not write into any bytes
|
|
@@ -8753,7 +8822,7 @@
|
|
** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE]
|
|
** buffer and where forced to overflow to [sqlite3_malloc()]. The
|
|
** returned value includes allocations that overflowed because they
|
|
-** where too large (they were larger than the "sz" parameter to
|
|
+** were too large (they were larger than the "sz" parameter to
|
|
** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because
|
|
** no space was left in the page cache.</dd>)^
|
|
**
|
|
@@ -8837,28 +8906,29 @@
|
|
** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
|
|
** <dd>This parameter returns the number of malloc attempts that were
|
|
** satisfied using lookaside memory. Only the high-water value is meaningful;
|
|
-** the current value is always zero.)^
|
|
+** the current value is always zero.</dd>)^
|
|
**
|
|
** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]]
|
|
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt>
|
|
-** <dd>This parameter returns the number malloc attempts that might have
|
|
+** <dd>This parameter returns the number of malloc attempts that might have
|
|
** been satisfied using lookaside memory but failed due to the amount of
|
|
** memory requested being larger than the lookaside slot size.
|
|
** Only the high-water value is meaningful;
|
|
-** the current value is always zero.)^
|
|
+** the current value is always zero.</dd>)^
|
|
**
|
|
** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]]
|
|
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt>
|
|
-** <dd>This parameter returns the number malloc attempts that might have
|
|
+** <dd>This parameter returns the number of malloc attempts that might have
|
|
** been satisfied using lookaside memory but failed due to all lookaside
|
|
** memory already being in use.
|
|
** Only the high-water value is meaningful;
|
|
-** the current value is always zero.)^
|
|
+** the current value is always zero.</dd>)^
|
|
**
|
|
** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
|
|
** <dd>This parameter returns the approximate number of bytes of heap
|
|
** memory used by all pager caches associated with the database connection.)^
|
|
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
|
|
+** </dd>
|
|
**
|
|
** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]]
|
|
** ^(<dt>SQLITE_DBSTATUS_CACHE_USED_SHARED</dt>
|
|
@@ -8867,10 +8937,10 @@
|
|
** memory used by that pager cache is divided evenly between the attached
|
|
** connections.)^ In other words, if none of the pager caches associated
|
|
** with the database connection are shared, this request returns the same
|
|
-** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are
|
|
+** value as DBSTATUS_CACHE_USED. Or, if one or more of the pager caches are
|
|
** shared, the value returned by this call will be smaller than that returned
|
|
** by DBSTATUS_CACHE_USED. ^The highwater mark associated with
|
|
-** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0.
|
|
+** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0.</dd>
|
|
**
|
|
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
|
|
** <dd>This parameter returns the approximate number of bytes of heap
|
|
@@ -8880,6 +8950,7 @@
|
|
** schema memory is shared with other database connections due to
|
|
** [shared cache mode] being enabled.
|
|
** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0.
|
|
+** </dd>
|
|
**
|
|
** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt>
|
|
** <dd>This parameter returns the approximate number of bytes of heap
|
|
@@ -8916,7 +8987,7 @@
|
|
** been written to disk in the middle of a transaction due to the page
|
|
** cache overflowing. Transactions are more efficient if they are written
|
|
** to disk all at once. When pages spill mid-transaction, that introduces
|
|
-** additional overhead. This parameter can be used help identify
|
|
+** additional overhead. This parameter can be used to help identify
|
|
** inefficiencies that can be resolved by increasing the cache size.
|
|
** </dd>
|
|
**
|
|
@@ -8987,13 +9058,13 @@
|
|
** [[SQLITE_STMTSTATUS_SORT]] <dt>SQLITE_STMTSTATUS_SORT</dt>
|
|
** <dd>^This is the number of sort operations that have occurred.
|
|
** A non-zero value in this counter may indicate an opportunity to
|
|
-** improvement performance through careful use of indices.</dd>
|
|
+** improve performance through careful use of indices.</dd>
|
|
**
|
|
** [[SQLITE_STMTSTATUS_AUTOINDEX]] <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt>
|
|
** <dd>^This is the number of rows inserted into transient indices that
|
|
** were created automatically in order to help joins run faster.
|
|
** A non-zero value in this counter may indicate an opportunity to
|
|
-** improvement performance by adding permanent indices that do not
|
|
+** improve performance by adding permanent indices that do not
|
|
** need to be reinitialized each time the statement is run.</dd>
|
|
**
|
|
** [[SQLITE_STMTSTATUS_VM_STEP]] <dt>SQLITE_STMTSTATUS_VM_STEP</dt>
|
|
@@ -9002,19 +9073,19 @@
|
|
** to 2147483647. The number of virtual machine operations can be
|
|
** used as a proxy for the total work done by the prepared statement.
|
|
** If the number of virtual machine operations exceeds 2147483647
|
|
-** then the value returned by this statement status code is undefined.
|
|
+** then the value returned by this statement status code is undefined.</dd>
|
|
**
|
|
** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt>
|
|
** <dd>^This is the number of times that the prepare statement has been
|
|
** automatically regenerated due to schema changes or changes to
|
|
-** [bound parameters] that might affect the query plan.
|
|
+** [bound parameters] that might affect the query plan.</dd>
|
|
**
|
|
** [[SQLITE_STMTSTATUS_RUN]] <dt>SQLITE_STMTSTATUS_RUN</dt>
|
|
** <dd>^This is the number of times that the prepared statement has
|
|
** been run. A single "run" for the purposes of this counter is one
|
|
** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()].
|
|
** The counter is incremented on the first [sqlite3_step()] call of each
|
|
-** cycle.
|
|
+** cycle.</dd>
|
|
**
|
|
** [[SQLITE_STMTSTATUS_FILTER_MISS]]
|
|
** [[SQLITE_STMTSTATUS_FILTER HIT]]
|
|
@@ -9024,7 +9095,7 @@
|
|
** step was bypassed because a Bloom filter returned not-found. The
|
|
** corresponding SQLITE_STMTSTATUS_FILTER_MISS value is the number of
|
|
** times that the Bloom filter returned a find, and thus the join step
|
|
-** had to be processed as normal.
|
|
+** had to be processed as normal.</dd>
|
|
**
|
|
** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt>
|
|
** <dd>^This is the approximate number of bytes of heap memory
|
|
@@ -9129,9 +9200,9 @@
|
|
** SQLite will typically create one cache instance for each open database file,
|
|
** though this is not guaranteed. ^The
|
|
** first parameter, szPage, is the size in bytes of the pages that must
|
|
-** be allocated by the cache. ^szPage will always a power of two. ^The
|
|
+** be allocated by the cache. ^szPage will always be a power of two. ^The
|
|
** second parameter szExtra is a number of bytes of extra storage
|
|
-** associated with each page cache entry. ^The szExtra parameter will
|
|
+** associated with each page cache entry. ^The szExtra parameter will be
|
|
** a number less than 250. SQLite will use the
|
|
** extra szExtra bytes on each page to store metadata about the underlying
|
|
** database page on disk. The value passed into szExtra depends
|
|
@@ -9139,17 +9210,17 @@
|
|
** ^The third argument to xCreate(), bPurgeable, is true if the cache being
|
|
** created will be used to cache database pages of a file stored on disk, or
|
|
** false if it is used for an in-memory database. The cache implementation
|
|
-** does not have to do anything special based with the value of bPurgeable;
|
|
+** does not have to do anything special based upon the value of bPurgeable;
|
|
** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will
|
|
** never invoke xUnpin() except to deliberately delete a page.
|
|
** ^In other words, calls to xUnpin() on a cache with bPurgeable set to
|
|
** false will always have the "discard" flag set to true.
|
|
-** ^Hence, a cache created with bPurgeable false will
|
|
+** ^Hence, a cache created with bPurgeable set to false will
|
|
** never contain any unpinned pages.
|
|
**
|
|
** [[the xCachesize() page cache method]]
|
|
** ^(The xCachesize() method may be called at any time by SQLite to set the
|
|
-** suggested maximum cache-size (number of pages stored by) the cache
|
|
+** suggested maximum cache-size (number of pages stored) for the cache
|
|
** instance passed as the first argument. This is the value configured using
|
|
** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable
|
|
** parameter, the implementation is not required to do anything with this
|
|
@@ -9176,12 +9247,12 @@
|
|
** implementation must return a pointer to the page buffer with its content
|
|
** intact. If the requested page is not already in the cache, then the
|
|
** cache implementation should use the value of the createFlag
|
|
-** parameter to help it determined what action to take:
|
|
+** parameter to help it determine what action to take:
|
|
**
|
|
** <table border=1 width=85% align=center>
|
|
** <tr><th> createFlag <th> Behavior when page is not already in cache
|
|
** <tr><td> 0 <td> Do not allocate a new page. Return NULL.
|
|
-** <tr><td> 1 <td> Allocate a new page if it easy and convenient to do so.
|
|
+** <tr><td> 1 <td> Allocate a new page if it is easy and convenient to do so.
|
|
** Otherwise return NULL.
|
|
** <tr><td> 2 <td> Make every effort to allocate a new page. Only return
|
|
** NULL if allocating a new page is effectively impossible.
|
|
@@ -9198,7 +9269,7 @@
|
|
** as its second argument. If the third parameter, discard, is non-zero,
|
|
** then the page must be evicted from the cache.
|
|
** ^If the discard parameter is
|
|
-** zero, then the page may be discarded or retained at the discretion of
|
|
+** zero, then the page may be discarded or retained at the discretion of the
|
|
** page cache implementation. ^The page cache implementation
|
|
** may choose to evict unpinned pages at any time.
|
|
**
|
|
@@ -9216,7 +9287,7 @@
|
|
** When SQLite calls the xTruncate() method, the cache must discard all
|
|
** existing cache entries with page numbers (keys) greater than or equal
|
|
** to the value of the iLimit parameter passed to xTruncate(). If any
|
|
-** of these pages are pinned, they are implicitly unpinned, meaning that
|
|
+** of these pages are pinned, they become implicitly unpinned, meaning that
|
|
** they can be safely discarded.
|
|
**
|
|
** [[the xDestroy() page cache method]]
|
|
@@ -9396,7 +9467,7 @@
|
|
** external process or via a database connection other than the one being
|
|
** used by the backup operation, then the backup will be automatically
|
|
** restarted by the next call to sqlite3_backup_step(). ^If the source
|
|
-** database is modified by the using the same database connection as is used
|
|
+** database is modified by using the same database connection as is used
|
|
** by the backup operation, then the backup database is automatically
|
|
** updated at the same time.
|
|
**
|
|
@@ -9413,7 +9484,7 @@
|
|
** and may not be used following a call to sqlite3_backup_finish().
|
|
**
|
|
** ^The value returned by sqlite3_backup_finish is [SQLITE_OK] if no
|
|
-** sqlite3_backup_step() errors occurred, regardless or whether or not
|
|
+** sqlite3_backup_step() errors occurred, regardless of whether or not
|
|
** sqlite3_backup_step() completed.
|
|
** ^If an out-of-memory condition or IO error occurred during any prior
|
|
** sqlite3_backup_step() call on the same [sqlite3_backup] object, then
|
|
@@ -9515,7 +9586,7 @@
|
|
** application receives an SQLITE_LOCKED error, it may call the
|
|
** sqlite3_unlock_notify() method with the blocked connection handle as
|
|
** the first argument to register for a callback that will be invoked
|
|
-** when the blocking connections current transaction is concluded. ^The
|
|
+** when the blocking connection's current transaction is concluded. ^The
|
|
** callback is invoked from within the [sqlite3_step] or [sqlite3_close]
|
|
** call that concludes the blocking connection's transaction.
|
|
**
|
|
@@ -9535,7 +9606,7 @@
|
|
** blocked connection already has a registered unlock-notify callback,
|
|
** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is
|
|
** called with a NULL pointer as its second argument, then any existing
|
|
-** unlock-notify callback is canceled. ^The blocked connections
|
|
+** unlock-notify callback is canceled. ^The blocked connection's
|
|
** unlock-notify callback may also be canceled by closing the blocked
|
|
** connection using [sqlite3_close()].
|
|
**
|
|
@@ -9933,7 +10004,7 @@
|
|
** support constraints. In this configuration (which is the default) if
|
|
** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire
|
|
** statement is rolled back as if [ON CONFLICT | OR ABORT] had been
|
|
-** specified as part of the users SQL statement, regardless of the actual
|
|
+** specified as part of the user's SQL statement, regardless of the actual
|
|
** ON CONFLICT mode specified.
|
|
**
|
|
** If X is non-zero, then the virtual table implementation guarantees
|
|
@@ -9967,7 +10038,7 @@
|
|
** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
|
|
** <dd>Calls of the form
|
|
** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
|
|
-** the [xConnect] or [xCreate] methods of a [virtual table] implementation
|
|
+** [xConnect] or [xCreate] methods of a [virtual table] implementation
|
|
** identify that virtual table as being safe to use from within triggers
|
|
** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
|
|
** virtual table can do no serious harm even if it is controlled by a
|
|
@@ -10135,7 +10206,7 @@
|
|
** </table>
|
|
**
|
|
** ^For the purposes of comparing virtual table output values to see if the
|
|
-** values are same value for sorting purposes, two NULL values are considered
|
|
+** values are the same value for sorting purposes, two NULL values are considered
|
|
** to be the same. In other words, the comparison operator is "IS"
|
|
** (or "IS NOT DISTINCT FROM") and not "==".
|
|
**
|
|
@@ -10145,7 +10216,7 @@
|
|
**
|
|
** ^A virtual table implementation is always free to return rows in any order
|
|
** it wants, as long as the "orderByConsumed" flag is not set. ^When the
|
|
-** the "orderByConsumed" flag is unset, the query planner will add extra
|
|
+** "orderByConsumed" flag is unset, the query planner will add extra
|
|
** [bytecode] to ensure that the final results returned by the SQL query are
|
|
** ordered correctly. The use of the "orderByConsumed" flag and the
|
|
** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful
|
|
@@ -10242,7 +10313,7 @@
|
|
** sqlite3_vtab_in_next(X,P) should be one of the parameters to the
|
|
** xFilter method which invokes these routines, and specifically
|
|
** a parameter that was previously selected for all-at-once IN constraint
|
|
-** processing use the [sqlite3_vtab_in()] interface in the
|
|
+** processing using the [sqlite3_vtab_in()] interface in the
|
|
** [xBestIndex|xBestIndex method]. ^(If the X parameter is not
|
|
** an xFilter argument that was selected for all-at-once IN constraint
|
|
** processing, then these routines return [SQLITE_ERROR].)^
|
|
@@ -10297,7 +10368,7 @@
|
|
** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V)
|
|
** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th
|
|
** constraint is not available. ^The sqlite3_vtab_rhs_value() interface
|
|
-** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if
|
|
+** can return a result code other than SQLITE_OK or SQLITE_NOTFOUND if
|
|
** something goes wrong.
|
|
**
|
|
** The sqlite3_vtab_rhs_value() interface is usually only successful if
|
|
@@ -10325,8 +10396,8 @@
|
|
** KEYWORDS: {conflict resolution mode}
|
|
**
|
|
** These constants are returned by [sqlite3_vtab_on_conflict()] to
|
|
-** inform a [virtual table] implementation what the [ON CONFLICT] mode
|
|
-** is for the SQL statement being evaluated.
|
|
+** inform a [virtual table] implementation of the [ON CONFLICT] mode
|
|
+** for the SQL statement being evaluated.
|
|
**
|
|
** Note that the [SQLITE_IGNORE] constant is also used as a potential
|
|
** return value from the [sqlite3_set_authorizer()] callback and that
|
|
@@ -10366,39 +10437,39 @@
|
|
** [[SQLITE_SCANSTAT_EST]] <dt>SQLITE_SCANSTAT_EST</dt>
|
|
** <dd>^The "double" variable pointed to by the V parameter will be set to the
|
|
** query planner's estimate for the average number of rows output from each
|
|
-** iteration of the X-th loop. If the query planner's estimates was accurate,
|
|
+** iteration of the X-th loop. If the query planner's estimate was accurate,
|
|
** then this value will approximate the quotient NVISIT/NLOOP and the
|
|
** product of this value for all prior loops with the same SELECTID will
|
|
-** be the NLOOP value for the current loop.
|
|
+** be the NLOOP value for the current loop.</dd>
|
|
**
|
|
** [[SQLITE_SCANSTAT_NAME]] <dt>SQLITE_SCANSTAT_NAME</dt>
|
|
** <dd>^The "const char *" variable pointed to by the V parameter will be set
|
|
** to a zero-terminated UTF-8 string containing the name of the index or table
|
|
-** used for the X-th loop.
|
|
+** used for the X-th loop.</dd>
|
|
**
|
|
** [[SQLITE_SCANSTAT_EXPLAIN]] <dt>SQLITE_SCANSTAT_EXPLAIN</dt>
|
|
** <dd>^The "const char *" variable pointed to by the V parameter will be set
|
|
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
|
|
-** description for the X-th loop.
|
|
+** description for the X-th loop.</dd>
|
|
**
|
|
** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECTID</dt>
|
|
** <dd>^The "int" variable pointed to by the V parameter will be set to the
|
|
** id for the X-th query plan element. The id value is unique within the
|
|
** statement. The select-id is the same value as is output in the first
|
|
-** column of an [EXPLAIN QUERY PLAN] query.
|
|
+** column of an [EXPLAIN QUERY PLAN] query.</dd>
|
|
**
|
|
** [[SQLITE_SCANSTAT_PARENTID]] <dt>SQLITE_SCANSTAT_PARENTID</dt>
|
|
** <dd>The "int" variable pointed to by the V parameter will be set to the
|
|
-** the id of the parent of the current query element, if applicable, or
|
|
+** id of the parent of the current query element, if applicable, or
|
|
** to zero if the query element has no parent. This is the same value as
|
|
-** returned in the second column of an [EXPLAIN QUERY PLAN] query.
|
|
+** returned in the second column of an [EXPLAIN QUERY PLAN] query.</dd>
|
|
**
|
|
** [[SQLITE_SCANSTAT_NCYCLE]] <dt>SQLITE_SCANSTAT_NCYCLE</dt>
|
|
** <dd>The sqlite3_int64 output value is set to the number of cycles,
|
|
** according to the processor time-stamp counter, that elapsed while the
|
|
** query element was being processed. This value is not available for
|
|
** all query elements - if it is unavailable the output variable is
|
|
-** set to -1.
|
|
+** set to -1.</dd>
|
|
** </dl>
|
|
*/
|
|
#define SQLITE_SCANSTAT_NLOOP 0
|
|
@@ -10439,8 +10510,8 @@
|
|
** sqlite3_stmt_scanstatus_v2() with a zeroed flags parameter.
|
|
**
|
|
** Parameter "idx" identifies the specific query element to retrieve statistics
|
|
-** for. Query elements are numbered starting from zero. A value of -1 may be
|
|
-** to query for statistics regarding the entire query. ^If idx is out of range
|
|
+** for. Query elements are numbered starting from zero. A value of -1 may
|
|
+** retrieve statistics for the entire query. ^If idx is out of range
|
|
** - less than -1 or greater than or equal to the total number of query
|
|
** elements used to implement the statement - a non-zero value is returned and
|
|
** the variable that pOut points to is unchanged.
|
|
@@ -10483,7 +10554,7 @@
|
|
** METHOD: sqlite3
|
|
**
|
|
** ^If a write-transaction is open on [database connection] D when the
|
|
-** [sqlite3_db_cacheflush(D)] interface invoked, any dirty
|
|
+** [sqlite3_db_cacheflush(D)] interface is invoked, any dirty
|
|
** pages in the pager-cache that are not currently in use are written out
|
|
** to disk. A dirty page may be in use if a database cursor created by an
|
|
** active SQL statement is reading from it, or if it is page 1 of a database
|
|
@@ -10597,8 +10668,8 @@
|
|
** triggers; and so forth.
|
|
**
|
|
** When the [sqlite3_blob_write()] API is used to update a blob column,
|
|
-** the pre-update hook is invoked with SQLITE_DELETE. This is because the
|
|
-** in this case the new values are not available. In this case, when a
|
|
+** the pre-update hook is invoked with SQLITE_DELETE, because
|
|
+** the new values are not yet available. In this case, when a
|
|
** callback made with op==SQLITE_DELETE is actually a write using the
|
|
** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns
|
|
** the index of the column being written. In other cases, where the
|
|
@@ -10851,7 +10922,7 @@
|
|
** For an ordinary on-disk database file, the serialization is just a
|
|
** copy of the disk file. For an in-memory database or a "TEMP" database,
|
|
** the serialization is the same sequence of bytes which would be written
|
|
-** to disk if that database where backed up to disk.
|
|
+** to disk if that database were backed up to disk.
|
|
**
|
|
** The usual case is that sqlite3_serialize() copies the serialization of
|
|
** the database into memory obtained from [sqlite3_malloc64()] and returns
|
|
@@ -10860,7 +10931,7 @@
|
|
** contains the SQLITE_SERIALIZE_NOCOPY bit, then no memory allocations
|
|
** are made, and the sqlite3_serialize() function will return a pointer
|
|
** to the contiguous memory representation of the database that SQLite
|
|
-** is currently using for that database, or NULL if the no such contiguous
|
|
+** is currently using for that database, or NULL if no such contiguous
|
|
** memory representation of the database exists. A contiguous memory
|
|
** representation of the database will usually only exist if there has
|
|
** been a prior call to [sqlite3_deserialize(D,S,...)] with the same
|
|
@@ -10931,7 +11002,7 @@
|
|
** database is currently in a read transaction or is involved in a backup
|
|
** operation.
|
|
**
|
|
-** It is not possible to deserialized into the TEMP database. If the
|
|
+** It is not possible to deserialize into the TEMP database. If the
|
|
** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the
|
|
** function returns SQLITE_ERROR.
|
|
**
|
|
@@ -10953,7 +11024,7 @@
|
|
sqlite3 *db, /* The database connection */
|
|
const char *zSchema, /* Which DB to reopen with the deserialization */
|
|
unsigned char *pData, /* The serialized database content */
|
|
- sqlite3_int64 szDb, /* Number bytes in the deserialization */
|
|
+ sqlite3_int64 szDb, /* Number of bytes in the deserialization */
|
|
sqlite3_int64 szBuf, /* Total size of buffer pData[] */
|
|
unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */
|
|
);
|
|
@@ -10961,7 +11032,7 @@
|
|
/*
|
|
** CAPI3REF: Flags for sqlite3_deserialize()
|
|
**
|
|
-** The following are allowed values for 6th argument (the F argument) to
|
|
+** The following are allowed values for the 6th argument (the F argument) to
|
|
** the [sqlite3_deserialize(D,S,P,N,M,F)] interface.
|
|
**
|
|
** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization
|
|
@@ -11486,9 +11557,10 @@
|
|
** is inserted while a session object is enabled, then later deleted while
|
|
** the same session object is disabled, no INSERT record will appear in the
|
|
** changeset, even though the delete took place while the session was disabled.
|
|
-** Or, if one field of a row is updated while a session is disabled, and
|
|
-** another field of the same row is updated while the session is enabled, the
|
|
-** resulting changeset will contain an UPDATE change that updates both fields.
|
|
+** Or, if one field of a row is updated while a session is enabled, and
|
|
+** then another field of the same row is updated while the session is disabled,
|
|
+** the resulting changeset will contain an UPDATE change that updates both
|
|
+** fields.
|
|
*/
|
|
SQLITE_API int sqlite3session_changeset(
|
|
sqlite3_session *pSession, /* Session object */
|
|
@@ -11560,8 +11632,9 @@
|
|
** database zFrom the contents of the two compatible tables would be
|
|
** identical.
|
|
**
|
|
-** It an error if database zFrom does not exist or does not contain the
|
|
-** required compatible table.
|
|
+** Unless the call to this function is a no-op as described above, it is an
|
|
+** error if database zFrom does not exist or does not contain the required
|
|
+** compatible table.
|
|
**
|
|
** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite
|
|
** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
|
|
@@ -11696,7 +11769,7 @@
|
|
** The following flags may passed via the 4th parameter to
|
|
** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]:
|
|
**
|
|
-** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd>
|
|
+** <dt>SQLITE_CHANGESETSTART_INVERT <dd>
|
|
** Invert the changeset while iterating through it. This is equivalent to
|
|
** inverting a changeset using sqlite3changeset_invert() before applying it.
|
|
** It is an error to specify this flag with a patchset.
|
|
@@ -12011,19 +12084,6 @@
|
|
void **ppOut /* OUT: Buffer containing output changeset */
|
|
);
|
|
|
|
-
|
|
-/*
|
|
-** CAPI3REF: Upgrade the Schema of a Changeset/Patchset
|
|
-*/
|
|
-SQLITE_API int sqlite3changeset_upgrade(
|
|
- sqlite3 *db,
|
|
- const char *zDb,
|
|
- int nIn, const void *pIn, /* Input changeset */
|
|
- int *pnOut, void **ppOut /* OUT: Inverse of input */
|
|
-);
|
|
-
|
|
-
|
|
-
|
|
/*
|
|
** CAPI3REF: Changegroup Handle
|
|
**
|