diff --git a/.ruby-version b/.ruby-version
index be94e6f..15a2799 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-3.2.2
+3.3.0
diff --git a/.semaphore/ensure-bundle.sh b/.semaphore/ensure-bundle.sh
new file mode 100644
index 0000000..475c3a2
--- /dev/null
+++ b/.semaphore/ensure-bundle.sh
@@ -0,0 +1,18 @@
+# Ensure that the bundle is installed and cached
+#
+
+bundle config set --local deployment true
+bundle config set --local path vendor/bundle
+gem update --no-doc bundler
+
+gemfile_checksum=$(checksum Gemfile.lock)
+cache_key="${SEMAPHORE_AGENT_MACHINE_OS_IMAGE}-${RUBY_VERSION}-${gemfile_checksum}"
+
+if cache has_key "${cache_key}"; then
+ echo "Bundle for ${RUBY_VERSION} and Gemfile.lock found in cache"
+ cache restore "${cache_key}"
+else
+ echo "Caching Bundle for ${RUBY_VERSION} and Gemfile.lock"
+ bundle install
+ cache store "${cache_key}" vendor/bundle
+fi
diff --git a/.semaphore/ensure-ruby-version.sh b/.semaphore/ensure-ruby-version.sh
new file mode 100644
index 0000000..5d3ce46
--- /dev/null
+++ b/.semaphore/ensure-ruby-version.sh
@@ -0,0 +1,14 @@
+# Ensure the correct Ruby version is installed and cached
+#
+cache_key="${SEMAPHORE_AGENT_MACHINE_OS_IMAGE}-${RUBY_VERSION}"
+
+if cache has_key "${cache_key}"; then
+ echo "Ruby ${RUBY_VERSION} found in cache"
+ cache restore "${cache_key}"
+ sem-version ruby "${RUBY_VERSION}" -f
+else
+ echo "Installing Ruby $RUBY_VERSION"
+ sem-version ruby "${RUBY_VERSION}" -f
+ cache store "${cache_key}" "${HOME}/.rbenv/versions/${RUBY_VERSION}"
+fi
+
diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml
index 980da62..cf1bb55 100644
--- a/.semaphore/semaphore.yml
+++ b/.semaphore/semaphore.yml
@@ -1,9 +1,14 @@
version: v1.0
-name: libsql-ruby
+name: libsql
agent:
machine:
type: e1-standard-2
os_image: ubuntu2004
+
+auto_cancel:
+ running:
+ when: "branch != 'main'"
+
blocks:
- name: Run Linux Tests
dependencies: []
@@ -24,13 +29,11 @@ blocks:
values:
- 3.0.6
- 3.1.4
- - 3.2.2
+ - 3.2.3
+ - 3.3.0
commands:
- - sem-version ruby ${RUBY_VERSION} -f
- - bundle config set --local deployment true
- - bundle config set --local path vendor/bundle
- - gem update --no-doc bundler
- - bundle install
+ - source .semaphore/ensure-ruby-version.sh
+ - source .semaphore/ensure-bundle.sh
- mkdir -p tmp/test-results/
- export TEST_RESULTS_FILE=tmp/test-results/${RUBY_VERSION}.xml
- bundle exec rake test
@@ -41,7 +44,7 @@ blocks:
agent:
machine:
type: a1-standard-4
- os_image: macos-xcode13
+ os_image: macos-xcode14
prologue:
commands:
- checkout
@@ -53,13 +56,11 @@ blocks:
values:
- 3.0.6
- 3.1.4
- - 3.2.2
+ - 3.2.3
+ - 3.3.0
commands:
- - sem-version ruby ${RUBY_VERSION} -f
- - bundle config set --local deployment true
- - bundle config set --local path vendor/bundle
- - gem update --no-doc bundler
- - bundle install
+ - source .semaphore/ensure-ruby-version.sh
+ - source .semaphore/ensure-bundle.sh
- mkdir -p tmp/test-results/
- export TEST_RESULTS_FILE=tmp/test-results/${RUBY_VERSION}.xml
- bundle exec rake test
@@ -70,14 +71,14 @@ blocks:
task:
env_vars:
- name: RUBY_CC_VERSION
- value: 3.0.0:3.1.0:3.2.0
+ value: 3.0.0:3.1.0:3.2.0:3.3.0
agent:
machine:
type: e1-standard-2
os_image: ubuntu2004
containers:
- name: rake-compiler-dock
- image: "ghcr.io/rake-compiler/rake-compiler-dock-image:1.3.0-mri-x86-mingw32"
+ image: "ghcr.io/rake-compiler/rake-compiler-dock-image:1.4.0-mri-x86-mingw32"
jobs:
- name: build x86-mingw32 gem
commands:
@@ -93,14 +94,14 @@ blocks:
task:
env_vars:
- name: RUBY_CC_VERSION
- value: 3.0.0
+ value: 3.0.0:3.1.0:3.2.0:3.3.0
agent:
machine:
type: e1-standard-2
os_image: ubuntu2004
containers:
- name: rake-compiler-dock
- image: "ghcr.io/rake-compiler/rake-compiler-dock-image:1.3.0-mri-x64-mingw32"
+ image: "ghcr.io/rake-compiler/rake-compiler-dock-image:1.4.0-mri-x64-mingw32"
jobs:
- name: build x64-mingw32
commands:
@@ -116,14 +117,14 @@ blocks:
task:
env_vars:
- name: RUBY_CC_VERSION
- value: 3.0.0:3.1.0:3.2.0
+ value: 3.0.0:3.1.0:3.2.0:3.3.0
agent:
machine:
type: e1-standard-2
os_image: ubuntu2004
containers:
- name: rake-compiler-dock
- image: "ghcr.io/rake-compiler/rake-compiler-dock-image:1.3.0-mri-x64-mingw-ucrt"
+ image: "ghcr.io/rake-compiler/rake-compiler-dock-image:1.4.0-mri-x64-mingw-ucrt"
jobs:
- name: build x64-mingw-ucrt
commands:
diff --git a/Gemfile.lock b/Gemfile.lock
index 7c3b6e1..2fb111c 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -50,7 +50,7 @@ GEM
simplecov_json_formatter (~> 0.1)
simplecov-html (0.12.3)
simplecov_json_formatter (0.1.4)
- stringio (3.0.6)
+ stringio (3.1.0)
PLATFORMS
arm64-darwin-21
diff --git a/HISTORY.md b/HISTORY.md
index ca0d322..7229eb4 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,4 +1,7 @@
# Libsql Changelog
+## Version 0.2.0 - 2024-03-XX
+* Update to libsql 0.2.3 (from libsql-server-v0.24.2)
+* Update CI tooling
## Version 0.1.0 - 2023-05-03
* Use the the [amalgalite](https://github.com/copiousfreetime/amalgalite) codebase to bootstrap libsql.
diff --git a/Rakefile b/Rakefile
index cdc1f0e..30960d4 100644
--- a/Rakefile
+++ b/Rakefile
@@ -23,6 +23,14 @@ This.ruby_gemspec do |spec|
spec.license = "BSD-3-Clause"
end
+This.cross_platforms = %w[
+ x86-mingw32
+ x64-mingw-ucrt
+ x64-mingw32
+]
+
+
load 'tasks/default.rake'
load 'tasks/extension.rake'
load 'tasks/custom.rake'
+load 'tasks/semaphore.rake'
diff --git a/ext/libsql/c/sqlite3.c b/ext/libsql/c/sqlite3.c
index a5e8cf0..9dcbc2c 100644
--- a/ext/libsql/c/sqlite3.c
+++ b/ext/libsql/c/sqlite3.c
@@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.42.0. By combining all the individual C code files into this
+** version 3.44.0. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@@ -16,6 +16,64 @@
** if you want a wrapper to interface SQLite with your choice of programming
** language. The code for the "sqlite3" command-line shell is also in a
** separate file. This file contains only code for the core SQLite library.
+**
+** The content in this amalgamation comes from Fossil check-in
+** 17129ba1ff7f0daf37100ee82d507aef7827 with changes in files:
+**
+** .fossil-settings/empty-dirs
+** .fossil-settings/ignore-glob
+** LICENSE.md
+** Makefile.in
+** README.md
+** configure
+** configure.ac
+** ext/wasm/GNUmakefile
+** ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api
+** ext/wasm/api/sqlite3-api-oo1.js
+** ext/wasm/fiddle.make
+** ext/wasm/fiddle/fiddle-worker.js
+** ext/wasm/fiddle/fiddle.js
+** ext/wasm/fiddle/index.html
+** main.mk
+** src/alter.c
+** src/attach.c
+** src/bitvec.c
+** src/btree.c
+** src/btree.h
+** src/build.c
+** src/callback.c
+** src/func.c
+** src/insert.c
+** src/loadext.c
+** src/main.c
+** src/os_unix.c
+** src/os_win.c
+** src/pager.c
+** src/pager.h
+** src/parse.y
+** src/pcache.h
+** src/pragma.c
+** src/shell.c.in
+** src/sqlite.h.in
+** src/sqlite3ext.h
+** src/sqliteInt.h
+** src/status.c
+** src/test2.c
+** src/test3.c
+** src/test8.c
+** src/vdbe.c
+** src/vdbeInt.h
+** src/vdbeapi.c
+** src/vtab.c
+** src/wal.c
+** src/wal.h
+** src/wherecode.c
+** test/permutations.test
+** test/rowvaluevtab.test
+** tool/mkkeywordhash.c
+** tool/mksqlite3c.tcl
+** tool/mksqlite3h.tcl
+** manifest.uuid
*/
#define SQLITE_CORE 1
#define SQLITE_AMALGAMATION 1
@@ -50,11 +108,11 @@
** used on lines of code that actually
** implement parts of coverage testing.
**
-** OPTIMIZATION-IF-TRUE - This branch is allowed to alway be false
+** OPTIMIZATION-IF-TRUE - This branch is allowed to always be false
** and the correct answer is still obtained,
** though perhaps more slowly.
**
-** OPTIMIZATION-IF-FALSE - This branch is allowed to alway be true
+** OPTIMIZATION-IF-FALSE - This branch is allowed to always be true
** and the correct answer is still obtained,
** though perhaps more slowly.
**
@@ -75,6 +133,12 @@
# define SQLITE_TCLAPI
#endif
+// NOTICE: libSQL extension: disabled WAL also implies we don't want shared memory via mmap
+#ifdef SQLITE_OMIT_WAL
+# undef SQLITE_OMIT_SHARED_MEM
+# define SQLITE_OMIT_SHARED_MEM 1
+#endif
+
/*
** Include the header file used to customize the compiler options for MSVC.
** This should be done first so that it can successfully prevent spurious
@@ -123,6 +187,10 @@
#define SQLITE_4_BYTE_ALIGNED_MALLOC
#endif /* defined(_MSC_VER) && !defined(_WIN64) */
+#if !defined(HAVE_LOG2) && defined(_MSC_VER) && _MSC_VER<1800
+#define HAVE_LOG2 0
+#endif /* !defined(HAVE_LOG2) && defined(_MSC_VER) && _MSC_VER<1800 */
+
#endif /* SQLITE_MSVC_H */
/************** End of msvc.h ************************************************/
@@ -455,11 +523,11 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.42.0"
-#define SQLITE_VERSION_NUMBER 3042000
-#define SQLITE_SOURCE_ID "2023-03-11 23:21:21 dc9f025dc43cb8008e7d8d644175d8b2d084e602a1513803c40c513d1e99alt1"
+#define SQLITE_VERSION "3.44.0"
+#define SQLITE_VERSION_NUMBER 3044000
+#define SQLITE_SOURCE_ID "2023-11-01 11:23:50 17129ba1ff7f0daf37100ee82d507aef7827cf38de1866e2633096ae6ad8alt1"
-#define LIBSQL_VERSION "0.2.1"
+#define LIBSQL_VERSION "0.2.3"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -841,6 +909,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8))
+#define SQLITE_IOERR_IN_PAGE (SQLITE_IOERR | (34<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
@@ -1510,7 +1579,7 @@ struct sqlite3_io_methods {
** by clients within the current process, only within other processes.
**
**
[[SQLITE_FCNTL_CKSM_FILE]]
-** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use interally by the
+** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use internally by the
** [checksum VFS shim] only.
**
** [[SQLITE_FCNTL_RESET_CACHE]]
@@ -2459,7 +2528,7 @@ struct sqlite3_mem_methods {
** is stored in each sorted record and the required column values loaded
** from the database as records are returned in sorted order. The default
** value for this option is to never use this optimization. Specifying a
-** negative value for this option restores the default behaviour.
+** negative value for this option restores the default behavior.
** This option is only available if SQLite is compiled with the
** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option.
**
@@ -2475,28 +2544,28 @@ struct sqlite3_mem_methods {
** compile-time option is not set, then the default maximum is 1073741824.
**
*/
-#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
-#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
-#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
-#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */
-#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */
-#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
-#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
-#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
-#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
-#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */
-#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
-/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
-#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
-#define SQLITE_CONFIG_PCACHE 14 /* no-op */
-#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */
-#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
-#define SQLITE_CONFIG_URI 17 /* int */
-#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */
-#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
+#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
+#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
+#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */
+#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */
+#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
+#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
+#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
+#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
+#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */
+#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
+/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
+#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
+#define SQLITE_CONFIG_PCACHE 14 /* no-op */
+#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */
+#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
+#define SQLITE_CONFIG_URI 17 /* int */
+#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
-#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
-#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
+#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
+#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
@@ -2634,7 +2703,7 @@ struct sqlite3_mem_methods {
** database handle, SQLite checks if this will mean that there are now no
** connections at all to the database. If so, it performs a checkpoint
** operation before closing the connection. This option may be used to
-** override this behaviour. The first parameter passed to this operation
+** override this behavior. The first parameter passed to this operation
** is an integer - positive to disable checkpoints-on-close, or zero (the
** default) to enable them, and negative to leave the setting unchanged.
** The second parameter is a pointer to an integer
@@ -2731,7 +2800,7 @@ struct sqlite3_mem_methods {
**
**
** [[SQLITE_DBCONFIG_DQS_DML]]
-** SQLITE_DBCONFIG_DQS_DML
+** SQLITE_DBCONFIG_DQS_DML
** The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DML statements
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
@@ -2740,7 +2809,7 @@ struct sqlite3_mem_methods {
**
**
** [[SQLITE_DBCONFIG_DQS_DDL]]
-** SQLITE_DBCONFIG_DQS_DDL
+** SQLITE_DBCONFIG_DQS_DDL
** The SQLITE_DBCONFIG_DQS option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DDL statements,
** such as CREATE TABLE and CREATE INDEX. The
@@ -2749,7 +2818,7 @@ struct sqlite3_mem_methods {
**
**
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
-** SQLITE_DBCONFIG_TRUSTED_SCHEMA
+** SQLITE_DBCONFIG_TRUSTED_SCHEMA
** The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
** assume that database schemas are untainted by malicious content.
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
@@ -2769,7 +2838,7 @@ struct sqlite3_mem_methods {
**
**
** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
-** SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
+** SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
** The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
** the legacy file format flag. When activated, this flag causes all newly
** created database file to have a schema format version number (the 4-byte
@@ -2778,7 +2847,7 @@ struct sqlite3_mem_methods {
** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting,
** newly created databases are generally not understandable by SQLite versions
** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there
-** is now scarcely any need to generated database files that are compatible
+** is now scarcely any need to generate database files that are compatible
** all the way back to version 3.0.0, and so this setting is of little
** practical use, but is provided so that SQLite can continue to claim the
** ability to generate new database files that are compatible with version
@@ -2787,27 +2856,39 @@ struct sqlite3_mem_methods {
** the [VACUUM] command will fail with an obscure error when attempting to
** process a table with generated columns and a descending index. This is
** not considered a bug since SQLite versions 3.3.0 and earlier do not support
-** either generated columns or decending indexes.
+** either generated columns or descending indexes.
**
**
** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]]
-** SQLITE_DBCONFIG_STMT_SCANSTATUS
+** SQLITE_DBCONFIG_STMT_SCANSTATUS
** The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in
** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears
** a flag that enables collection of the sqlite3_stmt_scanstatus_v2()
** statistics. For statistics to be collected, the flag must be set on
** the database handle both when the SQL statement is prepared and when it
** is stepped. The flag is set (collection of statistics is enabled)
-** by default.
+** by default. This option takes two arguments: an integer and a pointer to
+** an integer.. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the statement scanstatus option. If the second argument
+** is not NULL, then the value of the statement scanstatus setting after
+** processing the first argument is written into the integer that the second
+** argument points to.
+**
**
** [[SQLITE_DBCONFIG_REVERSE_SCANORDER]]
-** SQLITE_DBCONFIG_REVERSE_SCANORDER
-** The SQLITE_DBCONFIG_REVERSE_SCANORDER option change the default order
+** SQLITE_DBCONFIG_REVERSE_SCANORDER
+** The SQLITE_DBCONFIG_REVERSE_SCANORDER option changes the default order
** in which tables and indexes are scanned so that the scans start at the end
** and work toward the beginning rather than starting at the beginning and
-** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the
-** same as setting [PRAGMA reverse_unordered_selects]. This configuration option
-** is useful for application testing.
+** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the
+** same as setting [PRAGMA reverse_unordered_selects]. This option takes
+** two arguments which are an integer and a pointer to an integer. The first
+** argument is 1, 0, or -1 to enable, disable, or leave unchanged the
+** reverse scan order flag, respectively. If the second argument is not NULL,
+** then 0 or 1 is written into the integer that the second argument points to
+** depending on if the reverse scan order flag is set after processing the
+** first argument.
+**
**
**
*/
@@ -2829,7 +2910,7 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
-#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1080 /* int int* */
+#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */
#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */
#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */
@@ -3056,6 +3137,7 @@ SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3*);
**
** ^The [sqlite3_is_interrupted(D)] interface can be used to determine whether
** or not an interrupt is currently in effect for [database connection] D.
+** It returns 1 if an interrupt is currently in effect, or 0 otherwise.
*/
SQLITE_API void sqlite3_interrupt(sqlite3*);
SQLITE_API int sqlite3_is_interrupted(sqlite3*);
@@ -3709,8 +3791,10 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
** M argument should be the bitwise OR-ed combination of
** zero or more [SQLITE_TRACE] constants.
**
-** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides
-** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2().
+** ^Each call to either sqlite3_trace(D,X,P) or sqlite3_trace_v2(D,M,X,P)
+** overrides (cancels) all prior calls to sqlite3_trace(D,X,P) or
+** sqlite3_trace_v2(D,M,X,P) for the [database connection] D. Each
+** database connection may have at most one trace callback.
**
** ^The X callback is invoked whenever any of the events identified by
** mask M occur. ^The integer return value from the callback is currently
@@ -4067,6 +4151,9 @@ SQLITE_API int sqlite3_open_v2(
int flags, /* Flags */
const char *zVfs /* Name of VFS module to use */
);
+
+typedef struct libsql_wal_manager libsql_wal_manager;
+
SQLITE_API int libsql_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
@@ -4075,6 +4162,28 @@ SQLITE_API int libsql_open(
const char *zWal /* Name of WAL module to use */
);
+/* deprecated, only works with zWal == NULL */
+SQLITE_API int libsql_open_v2(
+ const char *filename, /* Database filename (UTF-8) */
+ sqlite3 **ppDb, /* OUT: SQLite db handle */
+ int flags, /* Flags */
+ const char *zVfs, /* Name of VFS module to use, NULL for default */
+ const char *zWal, /* Name of WAL module to use */
+ void* pWalMethodsData /* User data, passed to the libsql_wal struct*/
+);
+
+SQLITE_API int libsql_open_v3(
+ const char *filename, /* Database filename (UTF-8) */
+ sqlite3 **ppDb, /* OUT: SQLite db handle */
+ int flags, /* Flags */
+ const char *zVfs, /* Name of VFS module to use, NULL for default */
+ libsql_wal_manager wal_manager /* wal_manager instance, in charge of instanciating a wal */
+);
+
+typedef struct sqlite3_wal sqlite3_wal;
+SQLITE_API int sqlite3_wal_backfilled(sqlite3_wal *pWal);
+SQLITE_API unsigned int sqlite3_wal_frame_page_no(sqlite3_wal *pWal, unsigned int iFrame);
+
SQLITE_API LIBSQL_API int libsql_try_initialize_wasm_func_table(sqlite3 *db);
/*
@@ -4088,7 +4197,7 @@ SQLITE_API LIBSQL_API int libsql_try_initialize_wasm_func_table(sqlite3 *db);
** as F) must be one of:
**
** - A database filename pointer created by the SQLite core and
-** passed into the xOpen() method of a VFS implemention, or
+** passed into the xOpen() method of a VFS implementation, or
**
- A filename obtained from [sqlite3_db_filename()], or
**
- A new filename constructed using [sqlite3_create_filename()].
**
@@ -4201,7 +4310,7 @@ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*);
/*
** CAPI3REF: Create and Destroy VFS Filenames
**
-** These interfces are provided for use by [VFS shim] implementations and
+** These interfaces are provided for use by [VFS shim] implementations and
** are not useful outside of that context.
**
** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
@@ -4281,6 +4390,7 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename);
**
** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
** text that describes the error, as either UTF-8 or UTF-16 respectively.
+** (See how SQLite handles [invalid UTF] for exceptions to this rule.)
** ^(Memory to hold the error message string is managed internally.
** The application does not need to worry about freeing the result.
** However, the error string might be overwritten or deallocated by
@@ -4748,6 +4858,41 @@ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
*/
SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt);
+/*
+** CAPI3REF: Change The EXPLAIN Setting For A Prepared Statement
+** METHOD: sqlite3_stmt
+**
+** The sqlite3_stmt_explain(S,E) interface changes the EXPLAIN
+** setting for [prepared statement] S. If E is zero, then S becomes
+** a normal prepared statement. If E is 1, then S behaves as if
+** its SQL text began with "[EXPLAIN]". If E is 2, then S behaves as if
+** its SQL text began with "[EXPLAIN QUERY PLAN]".
+**
+** Calling sqlite3_stmt_explain(S,E) might cause S to be reprepared.
+** SQLite tries to avoid a reprepare, but a reprepare might be necessary
+** on the first transition into EXPLAIN or EXPLAIN QUERY PLAN mode.
+**
+** Because of the potential need to reprepare, a call to
+** sqlite3_stmt_explain(S,E) will fail with SQLITE_ERROR if S cannot be
+** reprepared because it was created using [sqlite3_prepare()] instead of
+** the newer [sqlite3_prepare_v2()] or [sqlite3_prepare_v3()] interfaces and
+** hence has no saved SQL text with which to reprepare.
+**
+** Changing the explain setting for a prepared statement does not change
+** the original SQL text for the statement. Hence, if the SQL text originally
+** began with EXPLAIN or EXPLAIN QUERY PLAN, but sqlite3_stmt_explain(S,0)
+** is called to convert the statement into an ordinary statement, the EXPLAIN
+** or EXPLAIN QUERY PLAN keywords will still appear in the sqlite3_sql(S)
+** output, even though the statement now acts like a normal SQL statement.
+**
+** This routine returns SQLITE_OK if the explain mode is successfully
+** changed, or an error code if the explain mode could not be changed.
+** The explain mode cannot be changed while a statement is active.
+** Hence, it is good practice to call [sqlite3_reset(S)]
+** immediately prior to calling sqlite3_stmt_explain(S,E).
+*/
+SQLITE_API int sqlite3_stmt_explain(sqlite3_stmt *pStmt, int eMode);
+
/*
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
** METHOD: sqlite3_stmt
@@ -4911,7 +5056,7 @@ typedef struct sqlite3_context sqlite3_context;
** with it may be passed. ^It is called to dispose of the BLOB or string even
** if the call to the bind API fails, except the destructor is not called if
** the third parameter is a NULL pointer or the fourth parameter is negative.
-** ^ (2) The special constant, [SQLITE_STATIC], may be passsed to indicate that
+** ^ (2) The special constant, [SQLITE_STATIC], may be passed to indicate that
** the application remains responsible for disposing of the object. ^In this
** case, the object and the provided pointer to it must remain valid until
** either the prepared statement is finalized or the same SQL parameter is
@@ -5590,20 +5735,33 @@ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
** ^The [sqlite3_reset(S)] interface resets the [prepared statement] S
** back to the beginning of its program.
**
-** ^If the most recent call to [sqlite3_step(S)] for the
-** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE],
-** or if [sqlite3_step(S)] has never before been called on S,
-** then [sqlite3_reset(S)] returns [SQLITE_OK].
+** ^The return code from [sqlite3_reset(S)] indicates whether or not
+** the previous evaluation of prepared statement S completed successfully.
+** ^If [sqlite3_step(S)] has never before been called on S or if
+** [sqlite3_step(S)] has not been called since the previous call
+** to [sqlite3_reset(S)], then [sqlite3_reset(S)] will return
+** [SQLITE_OK].
**
** ^If the most recent call to [sqlite3_step(S)] for the
** [prepared statement] S indicated an error, then
** [sqlite3_reset(S)] returns an appropriate [error code].
+** ^The [sqlite3_reset(S)] interface might also return an [error code]
+** if there were no prior errors but the process of resetting
+** the prepared statement caused a new error. ^For example, if an
+** [INSERT] statement with a [RETURNING] clause is only stepped one time,
+** that one call to [sqlite3_step(S)] might return SQLITE_ROW but
+** the overall statement might still fail and the [sqlite3_reset(S)] call
+** might return SQLITE_BUSY if locking constraints prevent the
+** database change from committing. Therefore, it is important that
+** applications check the return code from [sqlite3_reset(S)] even if
+** no prior call to [sqlite3_step(S)] indicated a problem.
**
** ^The [sqlite3_reset(S)] interface does not change the values
** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
+
/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
@@ -5814,7 +5972,7 @@ SQLITE_API int sqlite3_create_window_function(
** [application-defined SQL function]
** that has side-effects or that could potentially leak sensitive information.
** This will prevent attacks in which an application is tricked
-** into using a database file that has had its schema surreptiously
+** into using a database file that has had its schema surreptitiously
** modified to invoke the application-defined function in ways that are
** harmful.
**
@@ -6158,32 +6316,32 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** METHOD: sqlite3_context
**
** These functions may be used by (non-aggregate) SQL functions to
-** associate metadata with argument values. If the same value is passed to
-** multiple invocations of the same SQL function during query execution, under
-** some circumstances the associated metadata may be preserved. An example
-** of where this might be useful is in a regular-expression matching
-** function. The compiled version of the regular expression can be stored as
-** metadata associated with the pattern string.
+** associate auxiliary data with argument values. If the same argument
+** value is passed to multiple invocations of the same SQL function during
+** query execution, under some circumstances the associated auxiliary data
+** might be preserved. An example of where this might be useful is in a
+** regular-expression matching function. The compiled version of the regular
+** expression can be stored as auxiliary data associated with the pattern string.
** Then as long as the pattern string remains the same,
** the compiled regular expression can be reused on multiple
** invocations of the same function.
**
-** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
+** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data
** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
** value to the application-defined function. ^N is zero for the left-most
-** function argument. ^If there is no metadata
+** function argument. ^If there is no auxiliary data
** associated with the function argument, the sqlite3_get_auxdata(C,N) interface
** returns a NULL pointer.
**
-** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
-** argument of the application-defined function. ^Subsequent
+** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the
+** N-th argument of the application-defined function. ^Subsequent
** calls to sqlite3_get_auxdata(C,N) return P from the most recent
-** sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or
-** NULL if the metadata has been discarded.
+** sqlite3_set_auxdata(C,N,P,X) call if the auxiliary data is still valid or
+** NULL if the auxiliary data has been discarded.
** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL,
** SQLite will invoke the destructor function X with parameter P exactly
-** once, when the metadata is discarded.
-** SQLite is free to discard the metadata at any time, including:
+** once, when the auxiliary data is discarded.
+** SQLite is free to discard the auxiliary data at any time, including:
** - ^(when the corresponding function parameter changes)^, or
**
- ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the
** SQL statement)^, or
@@ -6199,7 +6357,7 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** function implementation should not make any use of P after
** sqlite3_set_auxdata() has been called.
**
-** ^(In practice, metadata is preserved between function calls for
+** ^(In practice, auxiliary data is preserved between function calls for
** function parameters that are compile-time constants, including literal
** values and [parameters] and expressions composed from the same.)^
**
@@ -6209,10 +6367,67 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
**
** These routines must be called from the same thread in which
** the SQL function is running.
+**
+** See also: [sqlite3_get_clientdata()] and [sqlite3_set_clientdata()].
*/
SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
+/*
+** CAPI3REF: Database Connection Client Data
+** METHOD: sqlite3
+**
+** These functions are used to associate one or more named pointers
+** with a [database connection].
+** A call to sqlite3_set_clientdata(D,N,P,X) causes the pointer P
+** to be attached to [database connection] D using name N. Subsequent
+** calls to sqlite3_get_clientdata(D,N) will return a copy of pointer P
+** or a NULL pointer if there were no prior calls to
+** sqlite3_set_clientdata() with the same values of D and N.
+** Names are compared using strcmp() and are thus case sensitive.
+**
+** If P and X are both non-NULL, then the destructor X is invoked with
+** argument P on the first of the following occurrences:
+**
+** - An out-of-memory error occurs during the call to
+** sqlite3_set_clientdata() which attempts to register pointer P.
+**
- A subsequent call to sqlite3_set_clientdata(D,N,P,X) is made
+** with the same D and N parameters.
+**
- The database connection closes. SQLite does not make any guarantees
+** about the order in which destructors are called, only that all
+** destructors will be called exactly once at some point during the
+** database connection closing process.
+**
+**
+** SQLite does not do anything with client data other than invoke
+** destructors on the client data at the appropriate time. The intended
+** use for client data is to provide a mechanism for wrapper libraries
+** to store additional information about an SQLite database connection.
+**
+** There is no limit (other than available memory) on the number of different
+** client data pointers (with different names) that can be attached to a
+** single database connection. However, the implementation is optimized
+** for the case of having only one or two different client data names.
+** Applications and wrapper libraries are discouraged from using more than
+** one client data name each.
+**
+** There is no way to enumerate the client data pointers
+** associated with a database connection. The N parameter can be thought
+** of as a secret key such that only code that knows the secret key is able
+** to access the associated data.
+**
+** Security Warning: These interfaces should not be exposed in scripting
+** languages or in other circumstances where it might be possible for an
+** an attacker to invoke them. Any agent that can invoke these interfaces
+** can probably also take control of the process.
+**
+** Database connection client data is only available for SQLite
+** version 3.44.0 ([dateof:3.44.0]) and later.
+**
+** See also: [sqlite3_set_auxdata()] and [sqlite3_get_auxdata()].
+*/
+SQLITE_API void *sqlite3_get_clientdata(sqlite3*,const char*);
+SQLITE_API int sqlite3_set_clientdata(sqlite3*, const char*, void*, void(*)(void*));
/*
** CAPI3REF: Constants Defining Special Destructor Behavior
@@ -6585,6 +6800,13 @@ SQLITE_API void sqlite3_activate_cerod(
** of the default VFS is not implemented correctly, or not implemented at
** all, then the behavior of sqlite3_sleep() may deviate from the description
** in the previous paragraphs.
+**
+** If a negative argument is passed to sqlite3_sleep() the results vary by
+** VFS and operating system. Some system treat a negative argument as an
+** instruction to sleep forever. Others understand it to mean do not sleep
+** at all. ^In SQLite version 3.42.0 and later, a negative
+** argument passed into sqlite3_sleep() is changed to zero before it is relayed
+** down into the xSleep method of the VFS.
*/
SQLITE_API int sqlite3_sleep(int);
@@ -6838,7 +7060,7 @@ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema);
/*
-** CAPI3REF: Allowed return values from [sqlite3_txn_state()]
+** CAPI3REF: Allowed return values from sqlite3_txn_state()
** KEYWORDS: {transaction state}
**
** These constants define the current transaction state of a database file.
@@ -6970,7 +7192,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** ^Each call to the sqlite3_autovacuum_pages() interface overrides all
** previous invocations for that database connection. ^If the callback
** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer,
-** then the autovacuum steps callback is cancelled. The return value
+** then the autovacuum steps callback is canceled. The return value
** from sqlite3_autovacuum_pages() is normally SQLITE_OK, but might
** be some other error code if something goes wrong. The current
** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other
@@ -7489,8 +7711,14 @@ struct sqlite3_module {
/* The methods above are in versions 1 and 2 of the sqlite_module object.
** Those below are for version 3 and greater. */
int (*xShadowName)(const char*);
- /* The methods below relate to features contributed by the community and
- ** are available for version 700 and greater. */
+ /* The methods above are in versions 1 through 3 of the sqlite_module object.
+ ** Those below are for version 4 and greater. */
+ int (*xIntegrity)(sqlite3_vtab *pVTab, const char *zSchema,
+ const char *zTabName, int mFlags, char **pzErr);
+
+ // reserved for sqlite extension
+ void (*reserved[5])();
+ // following methods are added by libsql
int (*xPreparedSql)(sqlite3_vtab_cursor*, const char*);
};
@@ -7775,9 +8003,9 @@ SQLITE_API int sqlite3_drop_modules(
** freed by sqlite3_free() and the zErrMsg field will be zeroed.
*/
struct sqlite3_vtab {
- const sqlite3_module *pModule; /* The module for this virtual table */
- int nRef; /* Number of open cursors */
- char *zErrMsg; /* Error message from sqlite3_mprintf() */
+ const sqlite3_module *pModule; /* The module for this virtual table */
+ int nRef; /* Number of open cursors */
+ char *zErrMsg; /* Error message from sqlite3_mprintf() */
/* Virtual table implementations will typically add additional fields */
};
@@ -7979,7 +8207,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
** code is returned and the transaction rolled back.
**
** Calling this function with an argument that is not a NULL pointer or an
-** open blob handle results in undefined behaviour. ^Calling this routine
+** open blob handle results in undefined behavior. ^Calling this routine
** with a null pointer (such as would be returned by a failed call to
** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
** is passed a valid open blob handle, the values returned by the
@@ -8128,12 +8356,6 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** ^Unregister WAL methods with the libsql_wal_methods_unregister() interface.
*/
typedef struct libsql_wal_methods libsql_wal_methods;
-SQLITE_API libsql_wal_methods *libsql_wal_methods_find(const char *zName);
-SQLITE_API int libsql_wal_methods_register(libsql_wal_methods*);
-SQLITE_API int libsql_wal_methods_unregister(libsql_wal_methods*);
-
-SQLITE_API libsql_wal_methods *libsql_wal_methods_next(libsql_wal_methods *w);
-SQLITE_API const char *libsql_wal_methods_name(libsql_wal_methods *w);
/*
** CAPI3REF: Mutexes
@@ -8243,9 +8465,9 @@ SQLITE_API const char *libsql_wal_methods_name(libsql_wal_methods *w);
** is undefined if the mutex is not currently entered by the
** calling thread or is not currently allocated.
**
-** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or
-** sqlite3_mutex_leave() is a NULL pointer, then all three routines
-** behave as no-ops.
+** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(),
+** sqlite3_mutex_leave(), or sqlite3_mutex_free() is a NULL pointer,
+** then any of the four routines behaves as a no-op.
**
** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
*/
@@ -8487,6 +8709,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_PRNG_SAVE 5
#define SQLITE_TESTCTRL_PRNG_RESTORE 6
#define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */
+#define SQLITE_TESTCTRL_FK_NO_ACTION 7
#define SQLITE_TESTCTRL_BITVEC_TEST 8
#define SQLITE_TESTCTRL_FAULT_INSTALL 9
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
@@ -8515,7 +8738,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_TRACEFLAGS 31
#define SQLITE_TESTCTRL_TUNE 32
#define SQLITE_TESTCTRL_LOGEST 33
-#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */
+#define SQLITE_TESTCTRL_USELONGDOUBLE 34
+#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
/*
** CAPI3REF: SQL Keyword Checking
@@ -8838,6 +9062,10 @@ SQLITE_API int sqlite3_status64(
*/
SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
+#ifdef LIBSQL_CUSTOM_PAGER_CODEC
+SQLITE_API void *libsql_leak_pager(sqlite3*);
+#endif
+
/*
** CAPI3REF: Status Parameters for database connections
** KEYWORDS: {SQLITE_DBSTATUS options}
@@ -9983,7 +10211,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
** [[SQLITE_VTAB_DIRECTONLY]]- SQLITE_VTAB_DIRECTONLY
** - Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the
-** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** prohibits that virtual table from being used from within triggers and
** views.
**
@@ -9991,18 +10219,28 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
** [[SQLITE_VTAB_INNOCUOUS]]- SQLITE_VTAB_INNOCUOUS
** - Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
-** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** identify that virtual table as being safe to use from within triggers
** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
** virtual table can do no serious harm even if it is controlled by a
** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS
** flag unless absolutely necessary.
**
+**
+** [[SQLITE_VTAB_USES_ALL_SCHEMAS]]- SQLITE_VTAB_USES_ALL_SCHEMAS
+** - Calls of the form
+** [sqlite3_vtab_config](db,SQLITE_VTAB_USES_ALL_SCHEMA) from within the
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
+** instruct the query planner to begin at least a read transaction on
+** all schemas ("main", "temp", and any ATTACH-ed databases) whenever the
+** virtual table is used.
+**
**
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
#define SQLITE_VTAB_INNOCUOUS 2
#define SQLITE_VTAB_DIRECTONLY 3
+#define SQLITE_VTAB_USES_ALL_SCHEMAS 4
/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
@@ -10163,7 +10401,7 @@ SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info*);
** communicated to the xBestIndex method as a
** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use
** this constraint, it must set the corresponding
-** aConstraintUsage[].argvIndex to a postive integer. ^(Then, under
+** aConstraintUsage[].argvIndex to a positive integer. ^(Then, under
** the usual mode of handling IN operators, SQLite generates [bytecode]
** that invokes the [xFilter|xFilter() method] once for each value
** on the right-hand side of the IN operator.)^ Thus the virtual table
@@ -10592,7 +10830,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
** When the [sqlite3_blob_write()] API is used to update a blob column,
** the pre-update hook is invoked with SQLITE_DELETE. This is because the
** in this case the new values are not available. In this case, when a
-** callback made with op==SQLITE_DELETE is actuall a write using the
+** 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
** pre-update hook is being invoked for some other reason, including a
@@ -10621,6 +10859,22 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *);
#endif
+/*
+** CAPI3REF: The close hook.
+** METHOD: sqlite3
+**
+** ^The [libsql_close_hook()] interface registers a callback function
+** that is invoked prior to closing the database connection.
+** ^At most one close hook may be registered at a time on a single
+** [database connection]; each call to [libsql_close_hook()] overrides
+** the previous setting.
+** ^The close hook is disabled by invoking [libsql_close_hook()]
+** with a NULL pointer as the second parameter.
+** ^The third parameter to [libsql_close_hook()] is passed through as
+** the first parameter to callbacks.
+*/
+SQLITE_API void *libsql_close_hook(sqlite3 *db, void (*xClose)(void *pCtx, sqlite3 *db), void *arg);
+
/*
** CAPI3REF: Low-level system error code
** METHOD: sqlite3
@@ -10853,6 +11107,13 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c
** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy
** of the database exists.
**
+** After the call, if the SQLITE_SERIALIZE_NOCOPY bit had been set,
+** the returned buffer content will remain accessible and unchanged
+** until either the next write operation on the connection or when
+** the connection is closed, and applications must not modify the
+** buffer. If the bit had been clear, the returned buffer will not
+** be accessed by SQLite after the call.
+**
** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the
** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory
** allocation error occurs.
@@ -10901,6 +11162,9 @@ SQLITE_API unsigned char *sqlite3_serialize(
** SQLite will try to increase the buffer size using sqlite3_realloc64()
** if writes on the database cause it to grow larger than M bytes.
**
+** Applications must not modify the buffer P or invalidate it before
+** the database connection D is closed.
+**
** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the
** database is currently in a read transaction or is involved in a backup
** operation.
@@ -10909,6 +11173,13 @@ SQLITE_API unsigned char *sqlite3_serialize(
** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the
** function returns SQLITE_ERROR.
**
+** The deserialized database should not be in [WAL mode]. If the database
+** is in WAL mode, then any attempt to use the database file will result
+** in an [SQLITE_CANTOPEN] error. The application can set the
+** [file format version numbers] (bytes 18 and 19) of the input database P
+** to 0x01 prior to invoking sqlite3_deserialize(D,S,P,N,M,F) to force the
+** database file into rollback mode and work around this limitation.
+**
** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the
** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then
** [sqlite3_free()] is invoked on argument P prior to returning.
@@ -10961,8 +11232,9 @@ SQLITE_API int sqlite3_deserialize(
#if defined(__wasi__)
# undef SQLITE_WASI
# define SQLITE_WASI 1
-# undef SQLITE_OMIT_WAL
-# define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */
+// NOTICE: we do support WAL mode, we just don't support shared memory
+//# undef SQLITE_OMIT_WAL
+//# define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */
# ifndef SQLITE_OMIT_LOAD_EXTENSION
# define SQLITE_OMIT_LOAD_EXTENSION
# endif
@@ -11177,16 +11449,20 @@ SQLITE_API int sqlite3session_create(
SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
/*
-** CAPIREF: Conigure a Session Object
+** CAPI3REF: Configure a Session Object
** METHOD: sqlite3_session
**
** This method is used to configure a session object after it has been
-** created. At present the only valid value for the second parameter is
-** [SQLITE_SESSION_OBJCONFIG_SIZE].
+** created. At present the only valid values for the second parameter are
+** [SQLITE_SESSION_OBJCONFIG_SIZE] and [SQLITE_SESSION_OBJCONFIG_ROWID].
**
-** Arguments for sqlite3session_object_config()
+*/
+SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg);
+
+/*
+** CAPI3REF: Options for sqlite3session_object_config
**
-** The following values may passed as the the 4th parameter to
+** The following values may passed as the the 2nd parameter to
** sqlite3session_object_config().
**
** - SQLITE_SESSION_OBJCONFIG_SIZE
-
@@ -11202,12 +11478,21 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
**
** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
** the first table has been attached to the session object.
+**
+**
- SQLITE_SESSION_OBJCONFIG_ROWID
-
+** This option is used to set, clear or query the flag that enables
+** collection of data for tables with no explicit PRIMARY KEY.
+**
+** Normally, tables with no explicit PRIMARY KEY are simply ignored
+** by the sessions module. However, if this flag is set, it behaves
+** as if such tables have a column "_rowid_ INTEGER PRIMARY KEY" inserted
+** as their leftmost columns.
+**
+** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
+** the first table has been attached to the session object.
*/
-SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg);
-
-/*
-*/
-#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_ROWID 2
/*
** CAPI3REF: Enable Or Disable A Session Object
@@ -11968,6 +12253,18 @@ SQLITE_API int sqlite3changeset_concat(
);
+/*
+** CAPI3REF: Upgrade the Schema of a Changeset/Patchset
+*/
+SQLITE_API int sqlite3changeset_upgrade(
+ sqlite3 *db,
+ const char *zDb,
+ int nIn, const void *pIn, /* Input changeset */
+ int *pnOut, void **ppOut /* OUT: Inverse of input */
+);
+
+
+
/*
** CAPI3REF: Changegroup Handle
**
@@ -12014,6 +12311,38 @@ typedef struct sqlite3_changegroup sqlite3_changegroup;
*/
SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
+/*
+** CAPI3REF: Add a Schema to a Changegroup
+** METHOD: sqlite3_changegroup_schema
+**
+** This method may be used to optionally enforce the rule that the changesets
+** added to the changegroup handle must match the schema of database zDb
+** ("main", "temp", or the name of an attached database). If
+** sqlite3changegroup_add() is called to add a changeset that is not compatible
+** with the configured schema, SQLITE_SCHEMA is returned and the changegroup
+** object is left in an undefined state.
+**
+** A changeset schema is considered compatible with the database schema in
+** the same way as for sqlite3changeset_apply(). Specifically, for each
+** table in the changeset, there exists a database table with:
+**
+**
+** - The name identified by the changeset, and
+**
- at least as many columns as recorded in the changeset, and
+**
- the primary key columns in the same position as recorded in
+** the changeset.
+**
+**
+** The output of the changegroup object always has the same schema as the
+** database nominated using this function. In cases where changesets passed
+** to sqlite3changegroup_add() have fewer columns than the corresponding table
+** in the database schema, these are filled in using the default column
+** values from the database schema. This makes it possible to combined
+** changesets that have different numbers of columns for a single table
+** within a changegroup, provided that they are otherwise compatible.
+*/
+SQLITE_API int sqlite3changegroup_schema(sqlite3_changegroup*, sqlite3*, const char *zDb);
+
/*
** CAPI3REF: Add A Changeset To A Changegroup
** METHOD: sqlite3_changegroup
@@ -12082,13 +12411,18 @@ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
** If the new changeset contains changes to a table that is already present
** in the changegroup, then the number of columns and the position of the
** primary key columns for the table must be consistent. If this is not the
-** case, this function fails with SQLITE_SCHEMA. If the input changeset
-** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
-** returned. Or, if an out-of-memory condition occurs during processing, this
-** function returns SQLITE_NOMEM. In all cases, if an error occurs the state
-** of the final contents of the changegroup is undefined.
+** case, this function fails with SQLITE_SCHEMA. Except, if the changegroup
+** object has been configured with a database schema using the
+** sqlite3changegroup_schema() API, then it is possible to combine changesets
+** with different numbers of columns for a single table, provided that
+** they are otherwise compatible.
+**
+** If the input changeset appears to be corrupt and the corruption is
+** detected, SQLITE_CORRUPT is returned. Or, if an out-of-memory condition
+** occurs during processing, this function returns SQLITE_NOMEM.
**
-** If no error occurs, SQLITE_OK is returned.
+** In all cases, if an error occurs the state of the final contents of the
+** changegroup is undefined. If no error occurs, SQLITE_OK is returned.
*/
SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
@@ -12353,10 +12687,17 @@ SQLITE_API int sqlite3changeset_apply_v2(
** - an insert change if all fields of the conflicting row match
** the row being inserted.
**
+**
+** - SQLITE_CHANGESETAPPLY_FKNOACTION
-
+** If this flag it set, then all foreign key constraints in the target
+** database behave as if they were declared with "ON UPDATE NO ACTION ON
+** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL
+** or SET DEFAULT.
*/
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
#define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004
+#define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008
/*
** CAPI3REF: Constants Passed To The Conflict Handler
@@ -13097,7 +13438,7 @@ struct Fts5PhraseIter {
** See xPhraseFirstColumn above.
*/
struct Fts5ExtensionApi {
- int iVersion; /* Currently always set to 3 */
+ int iVersion; /* Currently always set to 2 */
void *(*xUserData)(Fts5Context*);
@@ -13326,8 +13667,8 @@ struct Fts5ExtensionApi {
** as separate queries of the FTS index are required for each synonym.
**
** When using methods (2) or (3), it is important that the tokenizer only
-** provide synonyms when tokenizing document text (method (2)) or query
-** text (method (3)), not both. Doing so will not cause any errors, but is
+** provide synonyms when tokenizing document text (method (3)) or query
+** text (method (2)), not both. Doing so will not cause any errors, but is
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
@@ -13375,7 +13716,7 @@ struct fts5_api {
int (*xCreateTokenizer)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_tokenizer *pTokenizer,
void (*xDestroy)(void*)
);
@@ -13384,7 +13725,7 @@ struct fts5_api {
int (*xFindTokenizer)(
fts5_api *pApi,
const char *zName,
- void **ppContext,
+ void **ppUserData,
fts5_tokenizer *pTokenizer
);
@@ -13392,7 +13733,7 @@ struct fts5_api {
int (*xCreateFunction)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
@@ -13440,7 +13781,7 @@ struct libsql_pghdr {
** private to pcache.c and should not be accessed by other modules.
** pCache is grouped with the public elements for efficiency.
*/
- short nRef; /* Number of users of this page */
+ unsigned long long nRef; /* Number of users of this page */
PgHdr *pDirtyNext; /* Next element in list of dirty pages */
PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */
/* NB: pDirtyNext and pDirtyPrev are undefined if the
@@ -13485,15 +13826,16 @@ typedef struct libsql_pghdr libsql_pghdr;
** There is one object of this type for each pager.
*/
typedef struct libsql_wal libsql_wal;
+typedef struct libsql_wal_manager libsql_wal_manager;
+/* Opaque types for wal method data */
+typedef struct wal_impl wal_impl;
+typedef struct wal_manager_impl wal_manager_impl;
typedef struct libsql_wal_methods {
int iVersion; /* Current version is 1, versioning is here for backward compatibility */
- /* Open and close a connection to a write-ahead log. */
- int (*xOpen)(sqlite3_vfs*, sqlite3_file* , const char*, int no_shm_mode, long long max_size, struct libsql_wal_methods*, libsql_wal**);
- int (*xClose)(libsql_wal*, sqlite3* db, int sync_flags, int nBuf, unsigned char *zBuf);
/* Set the limiting size of a WAL file. */
- void (*xLimit)(libsql_wal*, long long limit);
+ void (*xLimit)(wal_impl* pWal, long long limit);
/* Used by readers to open (lock) and close (unlock) a snapshot. A
** snapshot is like a read-transaction. It is the state of the database
@@ -13502,37 +13844,37 @@ typedef struct libsql_wal_methods {
** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the
** transaction and releases the lock.
*/
- int (*xBeginReadTransaction)(libsql_wal *, int *);
- void (*xEndReadTransaction)(libsql_wal *);
+ int (*xBeginReadTransaction)(wal_impl* pWal, int *);
+ void (*xEndReadTransaction)(wal_impl *);
/* Read a page from the write-ahead log, if it is present. */
- int (*xFindFrame)(libsql_wal *, unsigned int, unsigned int *);
- int (*xReadFrame)(libsql_wal *, unsigned int, int, unsigned char *);
+ int (*xFindFrame)(wal_impl* pWal, unsigned int, unsigned int *);
+ int (*xReadFrame)(wal_impl* pWal, unsigned int, int, unsigned char *);
/* If the WAL is not empty, return the size of the database. */
- unsigned int (*xDbsize)(libsql_wal *pWal);
+ unsigned int (*xDbsize)(wal_impl* pWal);
/* Obtain or release the WRITER lock. */
- int (*xBeginWriteTransaction)(libsql_wal *pWal);
- int (*xEndWriteTransaction)(libsql_wal *pWal);
+ int (*xBeginWriteTransaction)(wal_impl* pWal);
+ int (*xEndWriteTransaction)(wal_impl* pWal);
/* Undo any frames written (but not committed) to the log */
- int (*xUndo)(libsql_wal *pWal, int (*xUndo)(void *, unsigned int), void *pUndoCtx);
+ int (*xUndo)(wal_impl* pWal, int (*xUndo)(void *, unsigned int), void *pUndoCtx);
/* Return an integer that records the current (uncommitted) write
** position in the WAL */
- void (*xSavepoint)(libsql_wal *pWal, unsigned int *aWalData);
+ void (*xSavepoint)(wal_impl* pWal, unsigned int *aWalData);
/* Move the write position of the WAL back to iFrame. Called in
** response to a ROLLBACK TO command. */
- int (*xSavepointUndo)(libsql_wal *pWal, unsigned int *aWalData);
+ int (*xSavepointUndo)(wal_impl* pWal, unsigned int *aWalData);
/* Write a frame or frames to the log. */
- int (*xFrames)(libsql_wal *pWal, int, libsql_pghdr *, unsigned int, int, int);
+ int (*xFrames)(wal_impl* pWal, int, libsql_pghdr *, unsigned int, int, int, int*);
/* Copy pages from the log to the database file */
int (*xCheckpoint)(
- libsql_wal *pWal, /* Write-ahead log connection */
+ wal_impl* pWal, /* Write-ahead log connection */
sqlite3 *db, /* Check this handle's interrupt flag */
int eMode, /* One of PASSIVE, FULL and RESTART */
int (*xBusy)(void*), /* Function to call when busy */
@@ -13541,7 +13883,12 @@ typedef struct libsql_wal_methods {
int nBuf, /* Size of buffer nBuf */
unsigned char *zBuf, /* Temporary buffer to use */
int *pnLog, /* OUT: Number of frames in WAL */
- int *pnCkpt /* OUT: Number of backfilled frames in WAL */
+ int *pnCkpt, /* OUT: Number of backfilled frames in WAL */
+ /*
+ * Called for each page being inserted in the wal, and once if the whole checkpoint operation was successfull with pPage == NULL
+ */
+ int (*xCb)(void* pCbData, int mxSafeFrame, const unsigned char* pPage, int nPage, int page_no, int frame_no), /* called */
+ void* pCbData /* user data passed to xCb */
);
/* Return the value to pass to a sqlite3_wal_hook callback, the
@@ -13549,66 +13896,42 @@ typedef struct libsql_wal_methods {
** sqlite3WalCallback() was called. If no commits have occurred since
** the last call, then return 0.
*/
- int (*xCallback)(libsql_wal *pWal);
+ int (*xCallback)(wal_impl* pWal);
/* Tell the wal layer that an EXCLUSIVE lock has been obtained (or released)
** by the pager layer on the database file.
*/
- int (*xExclusiveMode)(libsql_wal *pWal, int op);
+ int (*xExclusiveMode)(wal_impl* pWal, int op);
/* Return true if the argument is non-NULL and the WAL module is using
** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
** WAL module is using shared-memory, return false.
*/
- int (*xHeapMemory)(libsql_wal *pWal);
+ int (*xHeapMemory)(wal_impl* pWal);
// Only needed with SQLITE_ENABLE_SNAPSHOT, but part of the ABI
- int (*xSnapshotGet)(libsql_wal *pWal, sqlite3_snapshot **ppSnapshot);
- void (*xSnapshotOpen)(libsql_wal *pWal, sqlite3_snapshot *pSnapshot);
- int (*xSnapshotRecover)(libsql_wal *pWal);
- int (*xSnapshotCheck)(libsql_wal *pWal, sqlite3_snapshot *pSnapshot);
- void (*xSnapshotUnlock)(libsql_wal *pWal);
+ int (*xSnapshotGet)(wal_impl* pWal, sqlite3_snapshot **ppSnapshot);
+ void (*xSnapshotOpen)(wal_impl* pWal, sqlite3_snapshot *pSnapshot);
+ int (*xSnapshotRecover)(wal_impl* pWal);
+ int (*xSnapshotCheck)(void* pWal, sqlite3_snapshot *pSnapshot);
+ void (*xSnapshotUnlock)(wal_impl* pWal);
// Only needed with SQLITE_ENABLE_ZIPVFS, but part of the ABI
/* If the WAL file is not empty, return the number of bytes of content
** stored in each frame (i.e. the db page-size when the WAL was created).
*/
- int (*xFramesize)(libsql_wal *pWal);
+ int (*xFramesize)(wal_impl* pWal);
/* Return the sqlite3_file object for the WAL file */
- sqlite3_file *(*xFile)(libsql_wal *pWal);
+ sqlite3_file *(*xFile)(wal_impl* pWal);
// Only needed with SQLITE_ENABLE_SETLK_TIMEOUT
- int (*xWriteLock)(libsql_wal *pWal, int bLock);
-
- void (*xDb)(libsql_wal *pWal, sqlite3 *db);
-
- /* Return the WAL pathname length based on the owning pager's pathname len.
- ** For WAL implementations not based on a single file, 0 should be returned. */
- int (*xPathnameLen)(int origPathname);
-
- /* Get the WAL pathname to given buffer. Assumes that the buffer can hold
- ** at least xPathnameLen bytes. For WAL implementations not based on a single file,
- ** this operation can safely be a no-op.
- ** */
- void (*xGetWalPathname)(char *buf, const char *orig, int orig_len);
-
- /*
- ** This optional callback gets called before the main database file which owns
- ** the WAL file is open. It is a good place for initialization routines, as WAL
- ** is otherwise open lazily.
- */
- int (*xPreMainDbOpen)(libsql_wal_methods *methods, const char *main_db_path);
-
- /* True if the implementation relies on shared memory routines (e.g. locks) */
- int bUsesShm;
+ int (*xWriteLock)(wal_impl* pWal, int bLock);
- const char *zName;
- struct libsql_wal_methods *pNext;
+ void (*xDb)(wal_impl* pWal, sqlite3 *db);
} libsql_wal_methods;
-libsql_wal_methods* libsql_wal_methods_find(const char *zName);
/* Object declarations */
typedef struct WalIndexHdr WalIndexHdr;
@@ -13643,11 +13966,29 @@ struct WalIndexHdr {
unsigned int aCksum[2]; /* Checksum over all prior fields */
};
+struct libsql_wal_manager {
+ /* True if the implementation relies on shared memory routines (e.g. locks) */
+ int bUsesShm;
+
+ /* Open and close a connection to a write-ahead log. */
+ int (*xOpen)(wal_manager_impl* pData, sqlite3_vfs*, sqlite3_file*, int no_shm_mode, long long max_size, const char* zMainDbFileName, libsql_wal* out_wal);
+ int (*xClose)(wal_manager_impl* pData, wal_impl* pWal, sqlite3* db, int sync_flags, int nBuf, unsigned char *zBuf);
+
+ /* destroy resources for this wal */
+ int (*xLogDestroy)(wal_manager_impl* pData, sqlite3_vfs *vfs, const char* zMainDbFileName);
+ /* returns whether this wal exists */
+ int (*xLogExists)(wal_manager_impl* pData, sqlite3_vfs *vfs, const char* zMainDbFileName, int* exist);
+ /* destructor */
+ void (*xDestroy)(wal_manager_impl* pData);
+
+ wal_manager_impl* pData;
+};
+
/*
** An open write-ahead log file is represented by an instance of the
** following object.
*/
-struct libsql_wal {
+typedef struct sqlite3_wal {
sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */
sqlite3_file *pDbFd; /* File handle for the database file */
sqlite3_file *pWalFd; /* File handle for WAL file */
@@ -13675,11 +14016,29 @@ struct libsql_wal {
unsigned char lockError; /* True if a locking error has occurred */
WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
sqlite3 *db;
- libsql_wal_methods *pMethods; /* Virtual methods for interacting with WAL */
- void *pMethodsData; /* Optional context for private use of libsql_wal_methods */
+} sqlite3_wal;
+
+struct libsql_wal {
+ libsql_wal_methods methods; /* virtual wal methods */
+ wal_impl* pData; /* methods receiver */
};
-typedef struct libsql_wal libsql_wal;
+typedef struct RefCountedWalManager {
+ int n;
+ libsql_wal_manager ref;
+ int is_static;
+} RefCountedWalManager;
+
+int make_ref_counted_wal_manager(libsql_wal_manager wal_manager, RefCountedWalManager **out);
+void destroy_wal_manager(RefCountedWalManager *p);
+RefCountedWalManager* clone_wal_manager(RefCountedWalManager *p);
+
+SQLITE_API int sqlite3_wal_backfilled(sqlite3_wal* pWal);
+SQLITE_API unsigned int sqlite3_wal_frame_page_no(sqlite3_wal *pWal, unsigned int iFrame);
+
+RefCountedWalManager *make_sqlite3_wal_manager_rc();
+
+SQLITE_API extern const libsql_wal_manager sqlite3_wal_manager;
#endif /* SQLITE_WAL_H */
@@ -13735,6 +14094,7 @@ SQLITE_API void libsql_free_wasm_module(void *module);
** Creates a new wasm engine
*/
SQLITE_API libsql_wasm_engine_t *libsql_wasm_engine_new();
+SQLITE_API void libsql_wasm_engine_free(libsql_wasm_engine_t *);
#endif //LIBSQL_WASM_BINDINGS_H
#endif //LIBSQL_ENABLE_WASM_RUNTIME
@@ -13834,7 +14194,7 @@ SQLITE_API libsql_wasm_engine_t *libsql_wasm_engine_new();
** level of recursion for each term. A stack overflow can result
** if the number of terms is too large. In practice, most SQL
** never has more than 3 or 4 terms. Use a value of 0 to disable
-** any limit on the number of terms in a compount SELECT.
+** any limit on the number of terms in a compound SELECT.
*/
#ifndef SQLITE_MAX_COMPOUND_SELECT
# define SQLITE_MAX_COMPOUND_SELECT 500
@@ -14041,15 +14401,22 @@ SQLITE_API libsql_wasm_engine_t *libsql_wasm_engine_new();
#endif
/*
-** A macro to hint to the compiler that a function should not be
+** Macros to hint to the compiler that a function should or should not be
** inlined.
*/
#if defined(__GNUC__)
# define SQLITE_NOINLINE __attribute__((noinline))
+# define SQLITE_INLINE __attribute__((always_inline)) inline
#elif defined(_MSC_VER) && _MSC_VER>=1310
# define SQLITE_NOINLINE __declspec(noinline)
+# define SQLITE_INLINE __forceinline
#else
# define SQLITE_NOINLINE
+# define SQLITE_INLINE
+#endif
+#if defined(SQLITE_COVERAGE_TEST) || defined(__STRICT_ANSI__)
+# undef SQLITE_INLINE
+# define SQLITE_INLINE
#endif
/*
@@ -14468,183 +14835,184 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
#define TK_DEFERRED 7
#define TK_IMMEDIATE 8
#define TK_EXCLUSIVE 9
-#define TK_COMMIT 10
-#define TK_END 11
-#define TK_ROLLBACK 12
-#define TK_SAVEPOINT 13
-#define TK_RELEASE 14
-#define TK_TO 15
-#define TK_TABLE 16
-#define TK_CREATE 17
-#define TK_IF 18
-#define TK_NOT 19
-#define TK_EXISTS 20
-#define TK_TEMP 21
-#define TK_LP 22
-#define TK_RP 23
-#define TK_AS 24
-#define TK_COMMA 25
-#define TK_WITHOUT 26
-#define TK_RANDOM 27
-#define TK_ABORT 28
-#define TK_ACTION 29
-#define TK_AFTER 30
-#define TK_ANALYZE 31
-#define TK_ASC 32
-#define TK_ATTACH 33
-#define TK_BEFORE 34
-#define TK_BY 35
-#define TK_CASCADE 36
-#define TK_CAST 37
-#define TK_CONFLICT 38
-#define TK_DATABASE 39
-#define TK_DESC 40
-#define TK_DETACH 41
-#define TK_EACH 42
-#define TK_FAIL 43
-#define TK_FUNCTION 44
-#define TK_LANGUAGE 45
-#define TK_OR 46
-#define TK_AND 47
-#define TK_IS 48
-#define TK_MATCH 49
-#define TK_LIKE_KW 50
-#define TK_BETWEEN 51
-#define TK_IN 52
-#define TK_ISNULL 53
-#define TK_NOTNULL 54
-#define TK_NE 55
-#define TK_EQ 56
-#define TK_GT 57
-#define TK_LE 58
-#define TK_LT 59
-#define TK_GE 60
-#define TK_ESCAPE 61
-#define TK_ID 62
-#define TK_COLUMNKW 63
-#define TK_DO 64
-#define TK_FOR 65
-#define TK_IGNORE 66
-#define TK_INITIALLY 67
-#define TK_INSTEAD 68
-#define TK_NO 69
-#define TK_KEY 70
-#define TK_OF 71
-#define TK_OFFSET 72
-#define TK_PRAGMA 73
-#define TK_RAISE 74
-#define TK_RECURSIVE 75
-#define TK_REPLACE 76
-#define TK_RESTRICT 77
-#define TK_ROW 78
-#define TK_ROWS 79
-#define TK_TRIGGER 80
-#define TK_VACUUM 81
-#define TK_VIEW 82
-#define TK_VIRTUAL 83
-#define TK_WITH 84
-#define TK_NULLS 85
-#define TK_FIRST 86
-#define TK_LAST 87
-#define TK_CURRENT 88
-#define TK_FOLLOWING 89
-#define TK_PARTITION 90
-#define TK_PRECEDING 91
-#define TK_RANGE 92
-#define TK_UNBOUNDED 93
-#define TK_EXCLUDE 94
-#define TK_GROUPS 95
-#define TK_OTHERS 96
-#define TK_TIES 97
-#define TK_GENERATED 98
-#define TK_ALWAYS 99
-#define TK_MATERIALIZED 100
-#define TK_REINDEX 101
-#define TK_RENAME 102
-#define TK_CTIME_KW 103
-#define TK_ANY 104
-#define TK_BITAND 105
-#define TK_BITOR 106
-#define TK_LSHIFT 107
-#define TK_RSHIFT 108
-#define TK_PLUS 109
-#define TK_MINUS 110
-#define TK_STAR 111
-#define TK_SLASH 112
-#define TK_REM 113
-#define TK_CONCAT 114
-#define TK_PTR 115
-#define TK_COLLATE 116
-#define TK_BITNOT 117
-#define TK_ON 118
-#define TK_INDEXED 119
-#define TK_STRING 120
-#define TK_JOIN_KW 121
-#define TK_CONSTRAINT 122
-#define TK_DEFAULT 123
-#define TK_NULL 124
-#define TK_PRIMARY 125
-#define TK_UNIQUE 126
-#define TK_CHECK 127
-#define TK_REFERENCES 128
-#define TK_AUTOINCR 129
-#define TK_INSERT 130
-#define TK_DELETE 131
-#define TK_UPDATE 132
-#define TK_SET 133
-#define TK_DEFERRABLE 134
-#define TK_FOREIGN 135
-#define TK_DROP 136
-#define TK_BLOB 137
-#define TK_UNION 138
-#define TK_ALL 139
-#define TK_EXCEPT 140
-#define TK_INTERSECT 141
-#define TK_SELECT 142
-#define TK_VALUES 143
-#define TK_DISTINCT 144
-#define TK_DOT 145
-#define TK_FROM 146
-#define TK_JOIN 147
-#define TK_USING 148
-#define TK_ORDER 149
-#define TK_GROUP 150
-#define TK_HAVING 151
-#define TK_LIMIT 152
-#define TK_WHERE 153
-#define TK_RETURNING 154
-#define TK_INTO 155
-#define TK_NOTHING 156
-#define TK_FLOAT 157
-#define TK_INTEGER 158
-#define TK_VARIABLE 159
-#define TK_CASE 160
-#define TK_WHEN 161
-#define TK_THEN 162
-#define TK_ELSE 163
-#define TK_INDEX 164
-#define TK_ALTER 165
-#define TK_ADD 166
-#define TK_WINDOW 167
-#define TK_OVER 168
-#define TK_FILTER 169
-#define TK_COLUMN 170
-#define TK_AGG_FUNCTION 171
-#define TK_AGG_COLUMN 172
-#define TK_TRUEFALSE 173
-#define TK_ISNOT 174
-#define TK_UMINUS 175
-#define TK_UPLUS 176
-#define TK_TRUTH 177
-#define TK_REGISTER 178
-#define TK_VECTOR 179
-#define TK_SELECT_COLUMN 180
-#define TK_IF_NULL_ROW 181
-#define TK_ASTERISK 182
-#define TK_SPAN 183
-#define TK_ERROR 184
-#define TK_SPACE 185
-#define TK_ILLEGAL 186
+#define TK_READONLY 10
+#define TK_COMMIT 11
+#define TK_END 12
+#define TK_ROLLBACK 13
+#define TK_SAVEPOINT 14
+#define TK_RELEASE 15
+#define TK_TO 16
+#define TK_TABLE 17
+#define TK_CREATE 18
+#define TK_IF 19
+#define TK_NOT 20
+#define TK_EXISTS 21
+#define TK_TEMP 22
+#define TK_LP 23
+#define TK_RP 24
+#define TK_AS 25
+#define TK_COMMA 26
+#define TK_WITHOUT 27
+#define TK_RANDOM 28
+#define TK_ABORT 29
+#define TK_ACTION 30
+#define TK_AFTER 31
+#define TK_ANALYZE 32
+#define TK_ASC 33
+#define TK_ATTACH 34
+#define TK_BEFORE 35
+#define TK_BY 36
+#define TK_CASCADE 37
+#define TK_CAST 38
+#define TK_CONFLICT 39
+#define TK_DATABASE 40
+#define TK_DESC 41
+#define TK_DETACH 42
+#define TK_EACH 43
+#define TK_FAIL 44
+#define TK_FUNCTION 45
+#define TK_LANGUAGE 46
+#define TK_OR 47
+#define TK_AND 48
+#define TK_IS 49
+#define TK_MATCH 50
+#define TK_LIKE_KW 51
+#define TK_BETWEEN 52
+#define TK_IN 53
+#define TK_ISNULL 54
+#define TK_NOTNULL 55
+#define TK_NE 56
+#define TK_EQ 57
+#define TK_GT 58
+#define TK_LE 59
+#define TK_LT 60
+#define TK_GE 61
+#define TK_ESCAPE 62
+#define TK_ID 63
+#define TK_COLUMNKW 64
+#define TK_DO 65
+#define TK_FOR 66
+#define TK_IGNORE 67
+#define TK_INITIALLY 68
+#define TK_INSTEAD 69
+#define TK_NO 70
+#define TK_KEY 71
+#define TK_OF 72
+#define TK_OFFSET 73
+#define TK_PRAGMA 74
+#define TK_RAISE 75
+#define TK_RECURSIVE 76
+#define TK_REPLACE 77
+#define TK_RESTRICT 78
+#define TK_ROW 79
+#define TK_ROWS 80
+#define TK_TRIGGER 81
+#define TK_VACUUM 82
+#define TK_VIEW 83
+#define TK_VIRTUAL 84
+#define TK_WITH 85
+#define TK_NULLS 86
+#define TK_FIRST 87
+#define TK_LAST 88
+#define TK_CURRENT 89
+#define TK_FOLLOWING 90
+#define TK_PARTITION 91
+#define TK_PRECEDING 92
+#define TK_RANGE 93
+#define TK_UNBOUNDED 94
+#define TK_EXCLUDE 95
+#define TK_GROUPS 96
+#define TK_OTHERS 97
+#define TK_TIES 98
+#define TK_GENERATED 99
+#define TK_ALWAYS 100
+#define TK_MATERIALIZED 101
+#define TK_REINDEX 102
+#define TK_RENAME 103
+#define TK_CTIME_KW 104
+#define TK_ANY 105
+#define TK_BITAND 106
+#define TK_BITOR 107
+#define TK_LSHIFT 108
+#define TK_RSHIFT 109
+#define TK_PLUS 110
+#define TK_MINUS 111
+#define TK_STAR 112
+#define TK_SLASH 113
+#define TK_REM 114
+#define TK_CONCAT 115
+#define TK_PTR 116
+#define TK_COLLATE 117
+#define TK_BITNOT 118
+#define TK_ON 119
+#define TK_INDEXED 120
+#define TK_STRING 121
+#define TK_JOIN_KW 122
+#define TK_CONSTRAINT 123
+#define TK_DEFAULT 124
+#define TK_NULL 125
+#define TK_PRIMARY 126
+#define TK_UNIQUE 127
+#define TK_CHECK 128
+#define TK_REFERENCES 129
+#define TK_AUTOINCR 130
+#define TK_INSERT 131
+#define TK_DELETE 132
+#define TK_UPDATE 133
+#define TK_SET 134
+#define TK_DEFERRABLE 135
+#define TK_FOREIGN 136
+#define TK_DROP 137
+#define TK_BLOB 138
+#define TK_UNION 139
+#define TK_ALL 140
+#define TK_EXCEPT 141
+#define TK_INTERSECT 142
+#define TK_SELECT 143
+#define TK_VALUES 144
+#define TK_DISTINCT 145
+#define TK_DOT 146
+#define TK_FROM 147
+#define TK_JOIN 148
+#define TK_USING 149
+#define TK_ORDER 150
+#define TK_GROUP 151
+#define TK_HAVING 152
+#define TK_LIMIT 153
+#define TK_WHERE 154
+#define TK_RETURNING 155
+#define TK_INTO 156
+#define TK_NOTHING 157
+#define TK_FLOAT 158
+#define TK_INTEGER 159
+#define TK_VARIABLE 160
+#define TK_CASE 161
+#define TK_WHEN 162
+#define TK_THEN 163
+#define TK_ELSE 164
+#define TK_INDEX 165
+#define TK_ALTER 166
+#define TK_ADD 167
+#define TK_WINDOW 168
+#define TK_OVER 169
+#define TK_FILTER 170
+#define TK_COLUMN 171
+#define TK_AGG_FUNCTION 172
+#define TK_AGG_COLUMN 173
+#define TK_TRUEFALSE 174
+#define TK_ISNOT 175
+#define TK_UMINUS 176
+#define TK_UPLUS 177
+#define TK_TRUTH 178
+#define TK_REGISTER 179
+#define TK_VECTOR 180
+#define TK_SELECT_COLUMN 181
+#define TK_IF_NULL_ROW 182
+#define TK_ASTERISK 183
+#define TK_SPAN 184
+#define TK_ERROR 185
+#define TK_SPACE 186
+#define TK_ILLEGAL 187
/************** End of parse.h ***********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
@@ -14932,8 +15300,31 @@ typedef INT16_TYPE LogEst;
** the end of buffer S. This macro returns true if P points to something
** contained within the buffer S.
*/
-#define SQLITE_WITHIN(P,S,E) (((uptr)(P)>=(uptr)(S))&&((uptr)(P)<(uptr)(E)))
+#define SQLITE_WITHIN(P,S,E) (((uptr)(P)>=(uptr)(S))&&((uptr)(P)<(uptr)(E)))
+/*
+** P is one byte past the end of a large buffer. Return true if a span of bytes
+** between S..E crosses the end of that buffer. In other words, return true
+** if the sub-buffer S..E-1 overflows the buffer whose last byte is P-1.
+**
+** S is the start of the span. E is one byte past the end of end of span.
+**
+** P
+** |-----------------| FALSE
+** |-------|
+** S E
+**
+** P
+** |-----------------|
+** |-------| TRUE
+** S E
+**
+** P
+** |-----------------|
+** |-------| FALSE
+** S E
+*/
+#define SQLITE_OVERFLOW(P,S,E) (((uptr)(S)<(uptr)(P))&&((uptr)(E)>(uptr)(P)))
/*
** Macros to determine whether the machine is big or little endian,
@@ -14943,16 +15334,33 @@ typedef INT16_TYPE LogEst;
** using C-preprocessor macros. If that is unsuccessful, or if
** -DSQLITE_BYTEORDER=0 is set, then byte-order is determined
** at run-time.
+**
+** If you are building SQLite on some obscure platform for which the
+** following ifdef magic does not work, you can always include either:
+**
+** -DSQLITE_BYTEORDER=1234
+**
+** or
+**
+** -DSQLITE_BYTEORDER=4321
+**
+** to cause the build to work for little-endian or big-endian processors,
+** respectively.
*/
-#ifndef SQLITE_BYTEORDER
-# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+#ifndef SQLITE_BYTEORDER /* Replicate changes at tag-20230904a */
+# if defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
+# define SQLITE_BYTEORDER 4321
+# elif defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
+# define SQLITE_BYTEORDER 1234
+# elif defined(__BIG_ENDIAN__) && __BIG_ENDIAN__==1
+# define SQLITE_BYTEORDER 4321
+# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \
defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64)
-# define SQLITE_BYTEORDER 1234
-# elif defined(sparc) || defined(__ppc__) || \
- defined(__ARMEB__) || defined(__AARCH64EB__)
-# define SQLITE_BYTEORDER 4321
+# define SQLITE_BYTEORDER 1234
+# elif defined(sparc) || defined(__ARMEB__) || defined(__AARCH64EB__)
+# define SQLITE_BYTEORDER 4321
# else
# define SQLITE_BYTEORDER 0
# endif
@@ -15167,7 +15575,7 @@ struct BusyHandler {
/*
** Name of table that holds the database schema.
**
-** The PREFERRED names are used whereever possible. But LEGACY is also
+** The PREFERRED names are used wherever possible. But LEGACY is also
** used for backwards compatibility.
**
** 1. Queries can use either the PREFERRED or the LEGACY names
@@ -15276,11 +15684,13 @@ typedef struct Column Column;
typedef struct Cte Cte;
typedef struct CteUse CteUse;
typedef struct Db Db;
+typedef struct DbClientData DbClientData;
typedef struct DbFixer DbFixer;
typedef struct Schema Schema;
typedef struct Expr Expr;
typedef struct ExprList ExprList;
typedef struct FKey FKey;
+typedef struct FpDecode FpDecode;
typedef struct FuncDestructor FuncDestructor;
typedef struct FuncDef FuncDef;
typedef struct FuncDefHash FuncDefHash;
@@ -15299,6 +15709,7 @@ typedef struct Parse Parse;
typedef struct ParseCleanup ParseCleanup;
typedef struct PreUpdate PreUpdate;
typedef struct PrintfArguments PrintfArguments;
+typedef struct RCStr RCStr;
typedef struct RenameToken RenameToken;
typedef struct Returning Returning;
typedef struct RowSet RowSet;
@@ -15814,7 +16225,7 @@ typedef struct libsql_wal_methods libsql_wal_methods;
/* Open and close a Pager connection. */
SQLITE_PRIVATE int sqlite3PagerOpen(
sqlite3_vfs*,
- libsql_wal_methods*,
+ RefCountedWalManager*,
Pager **ppPager,
const char*,
int,
@@ -15942,6 +16353,10 @@ SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*);
# define enable_simulated_io_errors()
#endif
+#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL)
+SQLITE_PRIVATE int sqlite3PagerWalSystemErrno(Pager*);
+#endif
+
#endif /* SQLITE_PAGER_H */
/************** End of pager.h ***********************************************/
@@ -15995,7 +16410,6 @@ typedef struct libsql_wal_methods libsql_wal_methods;
SQLITE_PRIVATE int sqlite3BtreeOpen(
sqlite3_vfs *pVfs, /* VFS to use with this b-tree */
- libsql_wal_methods *pWal,/* WAL methods to use with this b-tree */
const char *zFilename, /* Name of database file to open */
sqlite3 *db, /* Associated database connection */
Btree **ppBtree, /* Return open Btree* here */
@@ -16273,9 +16687,7 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int flags);
SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor*);
SQLITE_PRIVATE void sqlite3BtreeCursorPin(BtCursor*);
SQLITE_PRIVATE void sqlite3BtreeCursorUnpin(BtCursor*);
-#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor*);
-#endif
SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*);
@@ -16315,7 +16727,7 @@ SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*);
#endif
SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor*);
-SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3*, BtCursor*, i64*);
+SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3*, BtCursor*, i64*, i64*);
#ifdef SQLITE_TEST
SQLITE_PRIVATE int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
@@ -16565,8 +16977,8 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_If 16 /* jump */
#define OP_IfNot 17 /* jump */
#define OP_IsType 18 /* jump, synopsis: if typeof(P1.P3) in P5 goto P2 */
-#define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */
-#define OP_IfNullRow 20 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
+#define OP_IfNullRow 19 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
+#define OP_Not 20 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */
#define OP_SeekLT 21 /* jump, synopsis: key=r[P3@P4] */
#define OP_SeekLE 22 /* jump, synopsis: key=r[P3@P4] */
#define OP_SeekGE 23 /* jump, synopsis: key=r[P3@P4] */
@@ -16592,23 +17004,23 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_IdxGE 43 /* jump, synopsis: key=r[P3@P4] */
#define OP_RowSetRead 44 /* jump, synopsis: r[P3]=rowset(P1) */
#define OP_RowSetTest 45 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
-#define OP_Or 46 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
-#define OP_And 47 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
-#define OP_Program 48 /* jump */
+#define OP_Program 46 /* jump */
+#define OP_Or 47 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
+#define OP_And 48 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
#define OP_FkIfZero 49 /* jump, synopsis: if fkctr[P1]==0 goto P2 */
#define OP_IfPos 50 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
#define OP_IfNotZero 51 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
#define OP_DecrJumpZero 52 /* jump, synopsis: if (--r[P1])==0 goto P2 */
-#define OP_IsNull 53 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
-#define OP_NotNull 54 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
-#define OP_Ne 55 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
-#define OP_Eq 56 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */
-#define OP_Gt 57 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */
-#define OP_Le 58 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */
-#define OP_Lt 59 /* jump, same as TK_LT, synopsis: IF r[P3]=r[P1] */
-#define OP_ElseEq 61 /* jump, same as TK_ESCAPE */
-#define OP_IncrVacuum 62 /* jump */
+#define OP_IncrVacuum 53 /* jump */
+#define OP_IsNull 54 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
+#define OP_NotNull 55 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
+#define OP_Ne 56 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
+#define OP_Eq 57 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */
+#define OP_Gt 58 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */
+#define OP_Le 59 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */
+#define OP_Lt 60 /* jump, same as TK_LT, synopsis: IF r[P3]=r[P1] */
+#define OP_ElseEq 62 /* jump, same as TK_ESCAPE */
#define OP_VNext 63 /* jump */
#define OP_Filter 64 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */
#define OP_PureFunc 65 /* synopsis: r[P3]=func(r[P2@NP]) */
@@ -16651,23 +17063,23 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_OpenRead 102 /* synopsis: root=P2 iDb=P3 */
#define OP_OpenWrite 103 /* synopsis: root=P2 iDb=P3 */
#define OP_OpenDup 104
-#define OP_BitAnd 105 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
-#define OP_BitOr 106 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
-#define OP_ShiftLeft 107 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */
-#define OP_Add 109 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
-#define OP_Subtract 110 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
-#define OP_Multiply 111 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
-#define OP_Divide 112 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
-#define OP_Remainder 113 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
-#define OP_Concat 114 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
-#define OP_OpenAutoindex 115 /* synopsis: nColumn=P2 */
+#define OP_OpenAutoindex 105 /* synopsis: nColumn=P2 */
+#define OP_BitAnd 106 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
+#define OP_BitOr 107 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
+#define OP_ShiftLeft 108 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */
+#define OP_Add 110 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
+#define OP_Subtract 111 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
+#define OP_Multiply 112 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
+#define OP_Divide 113 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
+#define OP_Remainder 114 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
+#define OP_Concat 115 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
#define OP_OpenEphemeral 116 /* synopsis: nColumn=P2 */
-#define OP_BitNot 117 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */
-#define OP_SorterOpen 118
+#define OP_SorterOpen 117
+#define OP_BitNot 118 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */
#define OP_SequenceTest 119 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */
-#define OP_String8 120 /* same as TK_STRING, synopsis: r[P2]='P4' */
-#define OP_OpenPseudo 121 /* synopsis: P3 columns in r[P2] */
+#define OP_OpenPseudo 120 /* synopsis: P3 columns in r[P2] */
+#define OP_String8 121 /* same as TK_STRING, synopsis: r[P2]='P4' */
#define OP_Close 122
#define OP_ColumnsUsed 123
#define OP_SeekScan 124 /* synopsis: Scan-ahead up to P1 rows */
@@ -16703,8 +17115,8 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_DropIndex 154
#define OP_DropTrigger 155
#define OP_IntegrityCk 156
-#define OP_Real 157 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
-#define OP_RowSetAdd 158 /* synopsis: rowset(P1)=r[P2] */
+#define OP_RowSetAdd 157 /* synopsis: rowset(P1)=r[P2] */
+#define OP_Real 158 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
#define OP_Param 159
#define OP_FkCounter 160 /* synopsis: fkctr[P1]+=P2 */
#define OP_MemMax 161 /* synopsis: r[P1]=max(r[P1],r[P2]) */
@@ -16722,20 +17134,21 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_VCreate 173
#define OP_VDestroy 174
#define OP_VOpen 175
-#define OP_VInitIn 176 /* synopsis: r[P2]=ValueList(P1,P3) */
-#define OP_VPreparedSql 177
-#define OP_VColumn 178 /* synopsis: r[P3]=vcolumn(P2) */
-#define OP_VRename 179
-#define OP_Pagecount 180
-#define OP_MaxPgcnt 181
-#define OP_ClrSubtype 182 /* synopsis: r[P1].subtype = 0 */
-#define OP_FilterAdd 183 /* synopsis: filter(P1) += key(P3@P4) */
-#define OP_Trace 184
-#define OP_CursorHint 185
-#define OP_ReleaseReg 186 /* synopsis: release r[P1@P2] mask P3 */
-#define OP_Noop 187
-#define OP_Explain 188
-#define OP_Abortable 189
+#define OP_VCheck 176
+#define OP_VInitIn 177 /* synopsis: r[P2]=ValueList(P1,P3) */
+#define OP_VPreparedSql 178
+#define OP_VColumn 179 /* synopsis: r[P3]=vcolumn(P2) */
+#define OP_VRename 180
+#define OP_Pagecount 181
+#define OP_MaxPgcnt 182
+#define OP_ClrSubtype 183 /* synopsis: r[P1].subtype = 0 */
+#define OP_FilterAdd 184 /* synopsis: filter(P1) += key(P3@P4) */
+#define OP_Trace 185
+#define OP_CursorHint 186
+#define OP_ReleaseReg 187 /* synopsis: release r[P1@P2] mask P3 */
+#define OP_Noop 188
+#define OP_Explain 189
+#define OP_Abortable 190
/* Properties such as "out2" or "jump" that are specified in
** comments following the "case" for each opcode in the vdbe.c
@@ -16751,28 +17164,28 @@ typedef struct VdbeOpList VdbeOpList;
#define OPFLG_INITIALIZER {\
/* 0 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x41, 0x00,\
/* 8 */ 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01,\
-/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x49, 0x49, 0x49,\
+/* 16 */ 0x03, 0x03, 0x01, 0x01, 0x12, 0x49, 0x49, 0x49,\
/* 24 */ 0x49, 0x01, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,\
-/* 32 */ 0x41, 0x01, 0x01, 0x01, 0x41, 0x01, 0x41, 0x41,\
-/* 40 */ 0x41, 0x41, 0x41, 0x41, 0x23, 0x0b, 0x26, 0x26,\
-/* 48 */ 0x01, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x0b,\
-/* 56 */ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x01, 0x01, 0x41,\
+/* 32 */ 0x41, 0x01, 0x41, 0x41, 0x41, 0x01, 0x41, 0x41,\
+/* 40 */ 0x41, 0x41, 0x41, 0x41, 0x23, 0x0b, 0x01, 0x26,\
+/* 48 */ 0x26, 0x01, 0x03, 0x03, 0x03, 0x01, 0x03, 0x03,\
+/* 56 */ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x01, 0x41,\
/* 64 */ 0x01, 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10,\
/* 72 */ 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x00,\
/* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x02, 0x02,\
/* 88 */ 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20, 0x40, 0x00,\
/* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x40, 0x40, 0x00,\
-/* 104 */ 0x40, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\
-/* 112 */ 0x26, 0x26, 0x26, 0x40, 0x40, 0x12, 0x00, 0x00,\
-/* 120 */ 0x10, 0x00, 0x40, 0x00, 0x40, 0x40, 0x10, 0x00,\
-/* 128 */ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 104 */ 0x40, 0x40, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\
+/* 112 */ 0x26, 0x26, 0x26, 0x26, 0x40, 0x00, 0x12, 0x00,\
+/* 120 */ 0x00, 0x10, 0x40, 0x00, 0x40, 0x40, 0x10, 0x00,\
+/* 128 */ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,\
/* 136 */ 0x00, 0x50, 0x00, 0x40, 0x04, 0x04, 0x00, 0x40,\
/* 144 */ 0x50, 0x40, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00,\
-/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x10,\
+/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x10,\
/* 160 */ 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,\
/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,\
-/* 176 */ 0x50, 0x00, 0x40, 0x00, 0x10, 0x10, 0x02, 0x00,\
-/* 184 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}
+/* 176 */ 0x10, 0x50, 0x00, 0x40, 0x00, 0x10, 0x10, 0x02,\
+/* 184 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}
/* The resolve3P2Values() routine is able to run faster if it knows
** the value of the largest JUMP opcode. The smaller the maximum
@@ -16947,7 +17360,7 @@ SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
** The VdbeCoverage macros are used to set a coverage testing point
** for VDBE branch instructions. The coverage testing points are line
** numbers in the sqlite3.c source file. VDBE branch coverage testing
-** only works with an amalagmation build. That's ok since a VDBE branch
+** only works with an amalgamation build. That's ok since a VDBE branch
** coverage build designed for testing the test suite only. No application
** should ever ship with VDBE branch coverage measuring turned on.
**
@@ -16965,7 +17378,7 @@ SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
** // NULL option is not possible
**
** VdbeCoverageEqNe(v) // Previous OP_Jump is only interested
-** // in distingishing equal and not-equal.
+** // in distinguishing equal and not-equal.
**
** Every VDBE branch operation must be tagged with one of the macros above.
** If not, then when "make test" is run with -DSQLITE_VDBE_COVERAGE and
@@ -16975,7 +17388,7 @@ SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
** During testing, the test application will invoke
** sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE,...) to set a callback
** routine that is invoked as each bytecode branch is taken. The callback
-** contains the sqlite3.c source line number ov the VdbeCoverage macro and
+** contains the sqlite3.c source line number of the VdbeCoverage macro and
** flags to indicate whether or not the branch was taken. The test application
** is responsible for keeping track of this and reporting byte-code branches
** that are never taken.
@@ -17023,6 +17436,10 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatusCounters(Vdbe*, int, int, int);
SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, VdbeOp*);
#endif
+#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG)
+SQLITE_PRIVATE int sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr);
+#endif
+
#endif /* SQLITE_VDBE_H */
/************** End of vdbe.h ************************************************/
@@ -17078,7 +17495,7 @@ struct libsql_pghdr {
** private to pcache.c and should not be accessed by other modules.
** pCache is grouped with the public elements for efficiency.
*/
- short nRef; /* Number of users of this page */
+ unsigned long long nRef; /* Number of users of this page */
PgHdr *pDirtyNext; /* Next element in list of dirty pages */
PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */
/* NB: pDirtyNext and pDirtyPrev are undefined if the
@@ -17166,12 +17583,12 @@ SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *);
SQLITE_PRIVATE void sqlite3PcacheClear(PCache*);
/* Return the total number of outstanding page references */
-SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache*);
+SQLITE_PRIVATE i64 sqlite3PcacheRefCount(PCache*);
/* Increment the reference count of an existing page */
SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr*);
-SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr*);
+SQLITE_PRIVATE i64 sqlite3PcachePageRefcount(PgHdr*);
/* Return the total number of pages stored in the cache */
SQLITE_PRIVATE int sqlite3PcachePagecount(PCache*);
@@ -17328,7 +17745,7 @@ SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*);
/*
** Default synchronous levels.
**
-** Note that (for historcal reasons) the PAGER_SYNCHRONOUS_* macros differ
+** Note that (for historical reasons) the PAGER_SYNCHRONOUS_* macros differ
** from the SQLITE_DEFAULT_SYNCHRONOUS value by 1.
**
** PAGER_SYNCHRONOUS DEFAULT_SYNCHRONOUS
@@ -17367,7 +17784,7 @@ struct Db {
** An instance of the following structure stores a database schema.
**
** Most Schema objects are associated with a Btree. The exception is
-** the Schema for the TEMP databaes (sqlite3.aDb[1]) which is free-standing.
+** the Schema for the TEMP database (sqlite3.aDb[1]) which is free-standing.
** In shared cache mode, a single Schema object can be shared by multiple
** Btrees that refer to the same underlying BtShared object.
**
@@ -17478,7 +17895,7 @@ struct Lookaside {
LookasideSlot *pInit; /* List of buffers not previously used */
LookasideSlot *pFree; /* List of available buffers */
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
- LookasideSlot *pSmallInit; /* List of small buffers not prediously used */
+ LookasideSlot *pSmallInit; /* List of small buffers not previously used */
LookasideSlot *pSmallFree; /* List of available small buffers */
void *pMiddle; /* First byte past end of full-size buffers and
** the first byte of LOOKASIDE_SMALL buffers */
@@ -17495,7 +17912,7 @@ struct LookasideSlot {
#define EnableLookaside db->lookaside.bDisable--;\
db->lookaside.sz=db->lookaside.bDisable?0:db->lookaside.szTrue
-/* Size of the smaller allocations in two-size lookside */
+/* Size of the smaller allocations in two-size lookaside */
#ifdef SQLITE_OMIT_TWOSIZE_LOOKASIDE
# define LOOKASIDE_SMALL 0
#else
@@ -17703,6 +18120,7 @@ struct sqlite3 {
i64 nDeferredCons; /* Net deferred constraints this transaction. */
i64 nDeferredImmCons; /* Net deferred immediate constraints */
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
+ DbClientData *pDbData; /* sqlite3_set_clientdata() content */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
/* The following variables are all protected by the STATIC_MAIN
** mutex, not by sqlite3.mutex. They are used by code in notify.c.
@@ -17726,7 +18144,13 @@ struct sqlite3 {
#ifdef LIBSQL_ENABLE_WASM_RUNTIME
libsql_wasm_ctx wasm; /* WebAssembly runtime context */
#endif
- libsql_wal_methods* pWalMethods; /* Custom WAL methods */
+#ifndef SQLITE_OMIT_WAL
+ RefCountedWalManager *wal_manager;
+#endif
+ void *pCloseArg; /* First argument to xCloseCallback */
+ void (*xCloseCallback)( /* Registered using sqlite3_close_hook() */
+ void*, sqlite3*
+ );
};
/*
@@ -17789,6 +18213,7 @@ struct sqlite3 {
/* the count using a callback. */
#define SQLITE_CorruptRdOnly HI(0x00002) /* Prohibit writes due to error */
#define SQLITE_ReadUncommit HI(0x00004) /* READ UNCOMMITTED in shared-cache */
+#define SQLITE_FkNoAction HI(0x00008) /* Treat all FK as NO ACTION */
/* Flags used only if debugging */
#ifdef SQLITE_DEBUG
@@ -17846,6 +18271,7 @@ struct sqlite3 {
#define SQLITE_IndexedExpr 0x01000000 /* Pull exprs from index when able */
#define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */
#define SQLITE_NullUnusedCols 0x04000000 /* NULL unused columns in subqueries */
+#define SQLITE_OnePass 0x08000000 /* Single-pass DELETE and UPDATE */
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
/*
@@ -17928,6 +18354,7 @@ struct FuncDestructor {
** SQLITE_FUNC_ANYORDER == NC_OrderAgg == SF_OrderByReqd
** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG
** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG
+** SQLITE_FUNC_BYTELEN == OPFLAG_BYTELENARG
** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API
** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API
** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS -- opposite meanings!!!
@@ -17935,7 +18362,7 @@ struct FuncDestructor {
**
** Note that even though SQLITE_FUNC_UNSAFE and SQLITE_INNOCUOUS have the
** same bit value, their meanings are inverted. SQLITE_FUNC_UNSAFE is
-** used internally and if set means tha the function has side effects.
+** used internally and if set means that the function has side effects.
** SQLITE_INNOCUOUS is used by application code and means "not unsafe".
** See multiple instances of tag-20230109-1.
*/
@@ -17946,6 +18373,7 @@ struct FuncDestructor {
#define SQLITE_FUNC_NEEDCOLL 0x0020 /* sqlite3GetFuncCollSeq() might be called*/
#define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */
#define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */
+#define SQLITE_FUNC_BYTELEN 0x00c0 /* Built-in octet_length() function */
#define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */
/* 0x0200 -- available for reuse */
#define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
@@ -18317,6 +18745,7 @@ struct VTable {
sqlite3_vtab *pVtab; /* Pointer to vtab instance */
int nRef; /* Number of pointers to this structure */
u8 bConstraint; /* True if constraints are supported */
+ u8 bAllSchemas; /* True if might use any attached schema */
u8 eVtabRisk; /* Riskiness of allowing hacker access */
int iSavepoint; /* Depth of the SAVEPOINT stack */
VTable *pNext; /* Next in linked list (see above) */
@@ -18528,7 +18957,7 @@ struct FKey {
** foreign key.
**
** The OE_Default value is a place holder that means to use whatever
-** conflict resolution algorthm is required from context.
+** conflict resolution algorithm is required from context.
**
** The following symbolic values are used to record which type
** of conflict resolution action to take.
@@ -18701,6 +19130,7 @@ struct Index {
** expression, or a reference to a VIRTUAL column */
#ifdef SQLITE_ENABLE_STAT4
int nSample; /* Number of elements in aSample[] */
+ int mxSample; /* Number of slots allocated to aSample[] */
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */
IndexSample *aSample; /* Samples of the left-most key */
@@ -18803,6 +19233,9 @@ struct AggInfo {
FuncDef *pFunc; /* The aggregate function implementation */
int iDistinct; /* Ephemeral table used to enforce DISTINCT */
int iDistAddr; /* Address of OP_OpenEphemeral */
+ int iOBTab; /* Ephemeral table to implement ORDER BY */
+ u8 bOBPayload; /* iOBTab has payload columns separate from key */
+ u8 bOBUnique; /* Enforce uniqueness on iOBTab keys */
} *aFunc;
int nFunc; /* Number of entries in aFunc[] */
u32 selId; /* Select to which this AggInfo belongs */
@@ -18941,7 +19374,7 @@ struct Expr {
** TK_REGISTER: register number
** TK_TRIGGER: 1 -> new, 0 -> old
** EP_Unlikely: 134217728 times likelihood
- ** TK_IN: ephemerial table holding RHS
+ ** TK_IN: ephemeral table holding RHS
** TK_SELECT_COLUMN: Number of columns on the LHS
** TK_SELECT: 1st register of result vector */
ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid.
@@ -18987,7 +19420,7 @@ struct Expr {
#define EP_Reduced 0x004000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
#define EP_Win 0x008000 /* Contains window functions */
#define EP_TokenOnly 0x010000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
- /* 0x020000 // Available for reuse */
+#define EP_FullSize 0x020000 /* Expr structure must remain full sized */
#define EP_IfNullRow 0x040000 /* The TK_IF_NULL_ROW opcode */
#define EP_Unlikely 0x080000 /* unlikely() or likelihood() function */
#define EP_ConstFunc 0x100000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
@@ -19017,12 +19450,15 @@ struct Expr {
#define ExprClearProperty(E,P) (E)->flags&=~(P)
#define ExprAlwaysTrue(E) (((E)->flags&(EP_OuterON|EP_IsTrue))==EP_IsTrue)
#define ExprAlwaysFalse(E) (((E)->flags&(EP_OuterON|EP_IsFalse))==EP_IsFalse)
+#define ExprIsFullSize(E) (((E)->flags&(EP_Reduced|EP_TokenOnly))==0)
/* Macros used to ensure that the correct members of unions are accessed
** in Expr.
*/
#define ExprUseUToken(E) (((E)->flags&EP_IntValue)==0)
#define ExprUseUValue(E) (((E)->flags&EP_IntValue)!=0)
+#define ExprUseWOfst(E) (((E)->flags&(EP_InnerON|EP_OuterON))==0)
+#define ExprUseWJoin(E) (((E)->flags&(EP_InnerON|EP_OuterON))!=0)
#define ExprUseXList(E) (((E)->flags&EP_xIsSelect)==0)
#define ExprUseXSelect(E) (((E)->flags&EP_xIsSelect)!=0)
#define ExprUseYTab(E) (((E)->flags&(EP_WinFunc|EP_Subrtn))==0)
@@ -19132,6 +19568,7 @@ struct ExprList {
#define ENAME_NAME 0 /* The AS clause of a result set */
#define ENAME_SPAN 1 /* Complete text of the result set expression */
#define ENAME_TAB 2 /* "DB.TABLE.NAME" for the result set */
+#define ENAME_ROWID 3 /* "DB.TABLE._rowid_" for * expansion of rowid */
/*
** An instance of this structure can hold a simple list of identifiers,
@@ -19211,7 +19648,7 @@ struct SrcItem {
unsigned notCte :1; /* This item may not match a CTE */
unsigned isUsing :1; /* u3.pUsing is valid */
unsigned isOn :1; /* u3.pOn was once valid and non-NULL */
- unsigned isSynthUsing :1; /* u3.pUsing is synthensized from NATURAL */
+ unsigned isSynthUsing :1; /* u3.pUsing is synthesized from NATURAL */
unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */
} fg;
int iCursor; /* The VDBE cursor number used to access this table */
@@ -19352,7 +19789,7 @@ struct NameContext {
#define NC_HasAgg 0x000010 /* One or more aggregate functions seen */
#define NC_IdxExpr 0x000020 /* True if resolving columns of CREATE INDEX */
#define NC_SelfRef 0x00002e /* Combo: PartIdx, isCheck, GenCol, and IdxExpr */
-#define NC_VarSelect 0x000040 /* A correlated subquery has been seen */
+#define NC_Subquery 0x000040 /* A subquery has been seen */
#define NC_UEList 0x000080 /* True if uNC.pEList is used */
#define NC_UAggInfo 0x000100 /* True if uNC.pAggInfo is used */
#define NC_UUpsert 0x000200 /* True if uNC.pUpsert is used */
@@ -19723,6 +20160,9 @@ struct Parse {
u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */
+#endif
+#ifdef SQLITE_DEBUG
+ u8 ifNotExists; /* Might be true if IF NOT EXISTS. Assert()s only */
#endif
int nRangeReg; /* Size of the temporary register block */
int iRangeReg; /* First register in temporary register block */
@@ -19737,6 +20177,7 @@ struct Parse {
int *aLabel; /* Space to hold the labels */
ExprList *pConstExpr;/* Constant expressions */
IndexedExpr *pIdxEpr;/* List of expressions used by active indexes */
+ IndexedExpr *pIdxPartExpr; /* Exprs constrained by index WHERE clauses */
Token constraintName;/* Name of the constraint currently being parsed */
yDbMask writeMask; /* Start a write transaction on these databases */
yDbMask cookieMask; /* Bitmask of schema verified databases */
@@ -19744,6 +20185,9 @@ struct Parse {
int regRoot; /* Register holding root page number for new objects */
int nMaxArg; /* Max args passed to user function by sub-program */
int nSelect; /* Number of SELECT stmts. Counter for Select.selId */
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
+ u32 nProgressSteps; /* xProgress steps taken during sqlite3_prepare() */
+#endif
#ifndef SQLITE_OMIT_SHARED_CACHE
int nTableLock; /* Number of locks in aTableLock */
TableLock *aTableLock; /* Required table locks for shared-cache mode */
@@ -19757,12 +20201,9 @@ struct Parse {
int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */
Returning *pReturning; /* The RETURNING clause */
} u1;
- u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
u32 oldmask; /* Mask of old.* columns referenced */
u32 newmask; /* Mask of new.* columns referenced */
-#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- u32 nProgressSteps; /* xProgress steps taken during sqlite3_prepare() */
-#endif
+ LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
u8 bReturning; /* Coding a RETURNING trigger */
u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
@@ -19886,6 +20327,7 @@ struct AuthContext {
#define OPFLAG_ISNOOP 0x40 /* OP_Delete does pre-update-hook only */
#define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */
#define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */
+#define OPFLAG_BYTELENARG 0xc0 /* OP_Column only for octet_length() */
#define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */
#define OPFLAG_SEEKEQ 0x02 /* OP_Open** cursor uses EQ seek only */
#define OPFLAG_FORDELETE 0x08 /* OP_Open should use BTREE_FORDELETE */
@@ -20007,6 +20449,7 @@ struct Returning {
int iRetCur; /* Transient table holding RETURNING results */
int nRetCol; /* Number of in pReturnEL after expansion */
int iRetReg; /* Register array for holding a row of RETURNING */
+ char zName[40]; /* Name of trigger: "sqlite_returning_%p" */
};
/*
@@ -20028,6 +20471,25 @@ struct sqlite3_str {
#define isMalloced(X) (((X)->printfFlags & SQLITE_PRINTF_MALLOCED)!=0)
+/*
+** The following object is the header for an "RCStr" or "reference-counted
+** string". An RCStr is passed around and used like any other char*
+** that has been dynamically allocated. The important interface
+** differences:
+**
+** 1. RCStr strings are reference counted. They are deallocated
+** when the reference count reaches zero.
+**
+** 2. Use sqlite3RCStrUnref() to free an RCStr string rather than
+** sqlite3_free()
+**
+** 3. Make a (read-only) copy of a read-only RCStr string using
+** sqlite3RCStrRef().
+*/
+struct RCStr {
+ u64 nRCRef; /* Number of references */
+ /* Total structure size should be a multiple of 8 bytes for alignment */
+};
/*
** A pointer to this structure is used to communicate information
@@ -20054,7 +20516,7 @@ typedef struct {
/* Tuning parameters are set using SQLITE_TESTCTRL_TUNE and are controlled
** on debug-builds of the CLI using ".testctrl tune ID VALUE". Tuning
** parameters are for temporary use during development, to help find
-** optimial values for parameters in the query planner. The should not
+** optimal values for parameters in the query planner. The should not
** be used on trunk check-ins. They are a temporary mechanism available
** for transient development builds only.
**
@@ -20080,6 +20542,7 @@ struct Sqlite3Config {
u8 bUseCis; /* Use covering indices for full-scans */
u8 bSmallMalloc; /* Avoid large memory allocations if true */
u8 bExtraSchemaChecks; /* Verify type,name,tbl_name in schema */
+ u8 bUseLongDouble; /* Make use of long double */
int mxStrlen; /* Maximum string length */
int neverCorrupt; /* Database is always well-formed */
int szLookaside; /* Default lookaside buffer size */
@@ -20166,6 +20629,7 @@ struct Walker {
void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
int walkerDepth; /* Number of subqueries */
u16 eCode; /* A small processing code */
+ u16 mWFlags; /* Use-dependent flags */
union { /* Extra data for callback */
NameContext *pNC; /* Naming context */
int n; /* A counter */
@@ -20184,6 +20648,7 @@ struct Walker {
struct CoveringIndexCheck *pCovIdxCk; /* Check for covering index */
SrcItem *pSrcItem; /* A single FROM clause item */
DbFixer *pFix; /* See sqlite3FixSelect() */
+ Mem *aMem; /* See sqlite3BtreeCursorHint() */
} u;
};
@@ -20204,6 +20669,7 @@ struct DbFixer {
/* Forward declarations */
SQLITE_PRIVATE int sqlite3WalkExpr(Walker*, Expr*);
+SQLITE_PRIVATE int sqlite3WalkExprNN(Walker*, Expr*);
SQLITE_PRIVATE int sqlite3WalkExprList(Walker*, ExprList*);
SQLITE_PRIVATE int sqlite3WalkSelect(Walker*, Select*);
SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker*, Select*);
@@ -20284,6 +20750,16 @@ struct CteUse {
};
+/* Client data associated with sqlite3_set_clientdata() and
+** sqlite3_get_clientdata().
+*/
+struct DbClientData {
+ DbClientData *pNext; /* Next in a linked list */
+ void *pData; /* The data */
+ void (*xDestructor)(void*); /* Destructor. Might be NULL */
+ char zName[1]; /* Name of this client data. MUST BE LAST */
+};
+
#ifdef SQLITE_DEBUG
/*
** An instance of the TreeView object is used for printing the content of
@@ -20453,6 +20929,8 @@ SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno);
# define sqlite3Isxdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x08)
# define sqlite3Tolower(x) (sqlite3UpperToLower[(unsigned char)(x)])
# define sqlite3Isquote(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x80)
+# define sqlite3JsonId1(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x42)
+# define sqlite3JsonId2(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x46)
#else
# define sqlite3Toupper(x) toupper((unsigned char)(x))
# define sqlite3Isspace(x) isspace((unsigned char)(x))
@@ -20462,6 +20940,8 @@ SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno);
# define sqlite3Isxdigit(x) isxdigit((unsigned char)(x))
# define sqlite3Tolower(x) tolower((unsigned char)(x))
# define sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`')
+# define sqlite3JsonId1(x) (sqlite3IsIdChar(x)&&(x)<'0')
+# define sqlite3JsonId2(x) sqlite3IsIdChar(x)
#endif
SQLITE_PRIVATE int sqlite3IsIdChar(u8);
@@ -20581,6 +21061,20 @@ struct PrintfArguments {
sqlite3_value **apArg; /* The argument values */
};
+/*
+** An instance of this object receives the decoding of a floating point
+** value into an approximate decimal representation.
+*/
+struct FpDecode {
+ char sign; /* '+' or '-' */
+ char isSpecial; /* 1: Infinity 2: NaN */
+ int n; /* Significant digits in the decode */
+ int iDP; /* Location of the decimal point */
+ char *z; /* Start of significant digits */
+ char zBuf[24]; /* Storage for significant digits */
+};
+
+SQLITE_PRIVATE void sqlite3FpDecode(FpDecode*,double,int,int);
SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3*,const char*, ...);
SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
@@ -20655,6 +21149,10 @@ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse*,int);
SQLITE_PRIVATE int sqlite3GetTempRange(Parse*,int);
SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse*,int,int);
SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse*);
+SQLITE_PRIVATE void sqlite3TouchRegister(Parse*,int);
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_DEBUG)
+SQLITE_PRIVATE int sqlite3FirstAvailableRegister(Parse*,int);
+#endif
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse*,int,int);
#endif
@@ -20666,6 +21164,8 @@ SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*);
SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse*,Expr*, Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, const Token*, int);
+SQLITE_PRIVATE void sqlite3ExprAddFunctionOrderBy(Parse*,Expr*,ExprList*);
+SQLITE_PRIVATE void sqlite3ExprOrderByAggregateError(Parse*,Expr*);
SQLITE_PRIVATE void sqlite3ExprFunctionUsable(Parse*,const Expr*,const FuncDef*);
SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*);
@@ -20725,8 +21225,8 @@ SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*);
SQLITE_PRIVATE void sqlite3AddGenerated(Parse*,Expr*,Token*);
SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u32,Select*);
SQLITE_PRIVATE void sqlite3AddReturning(Parse*,ExprList*);
-SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,const char*,unsigned int*,
- sqlite3_vfs**,libsql_wal_methods**,char**,char **);
+SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*,
+ sqlite3_vfs**,char**,char **);
#define sqlite3CodecQueryParameters(A,B,C) 0
SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*);
@@ -20805,7 +21305,7 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList
Expr*,ExprList*,u32,Expr*);
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*);
SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*);
-SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int);
+SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, Trigger*);
SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*);
@@ -20867,7 +21367,7 @@ SQLITE_PRIVATE int sqlite3ExprCompare(const Parse*,const Expr*,const Expr*, int)
SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr*,Expr*,int);
SQLITE_PRIVATE int sqlite3ExprListCompare(const ExprList*,const ExprList*, int);
SQLITE_PRIVATE int sqlite3ExprImpliesExpr(const Parse*,const Expr*,const Expr*, int);
-SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr*,int);
+SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr*,int,int);
SQLITE_PRIVATE void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
@@ -20894,7 +21394,7 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int);
-SQLITE_PRIVATE int sqlite3ExprIsTableConstraint(Expr*,const SrcItem*);
+SQLITE_PRIVATE int sqlite3ExprIsSingleTableConstraint(Expr*,const SrcList*,int);
#ifdef SQLITE_ENABLE_CURSOR_HINTS
SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*);
#endif
@@ -20902,6 +21402,7 @@ SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr*, int*);
SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*);
SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
SQLITE_PRIVATE int sqlite3IsRowid(const char*);
+SQLITE_PRIVATE const char *sqlite3RowidAlias(Table *pTab);
SQLITE_PRIVATE void sqlite3GenerateRowDelete(
Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int);
SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int);
@@ -21016,6 +21517,7 @@ SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*);
SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*);
SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*);
SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
+
SQLITE_PRIVATE int sqlite3RealSameAsInt(double,sqlite3_int64);
SQLITE_PRIVATE i64 sqlite3RealToI64(double);
SQLITE_PRIVATE int sqlite3Int64ToText(i64,char*);
@@ -21120,6 +21622,7 @@ SQLITE_PRIVATE void sqlite3FileSuffix3(const char*, char*);
SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z,u8);
SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8);
+SQLITE_PRIVATE int sqlite3ValueIsOfClass(const sqlite3_value*, void(*)(void*));
SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8);
SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
void(*)(void*));
@@ -21159,6 +21662,7 @@ SQLITE_PRIVATE void sqlite3Reindex(Parse*, Token*, Token*);
SQLITE_PRIVATE void sqlite3AlterFunctions(void);
SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
SQLITE_PRIVATE void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*);
+void libsqlAlterAlterColumn(Parse*, SrcList*, Token*, Token*);
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*, int);
@@ -21171,7 +21675,8 @@ SQLITE_PRIVATE int sqlite3MatchEName(
const struct ExprList_item*,
const char*,
const char*,
- const char*
+ const char*,
+ int*
);
SQLITE_PRIVATE Bitmask sqlite3ExprColUsed(Expr*);
SQLITE_PRIVATE u8 sqlite3StrIHash(const char*);
@@ -21227,6 +21732,11 @@ SQLITE_PRIVATE void sqlite3OomClear(sqlite3*);
SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int);
SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *);
+SQLITE_PRIVATE char *sqlite3RCStrRef(char*);
+SQLITE_PRIVATE void sqlite3RCStrUnref(void*);
+SQLITE_PRIVATE char *sqlite3RCStrNew(u64);
+SQLITE_PRIVATE char *sqlite3RCStrResize(char*,u64);
+
SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum*, i64);
SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*);
@@ -21342,10 +21852,7 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *, VTable *);
SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
-#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
- && !defined(SQLITE_OMIT_VIRTUALTABLE)
-SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(sqlite3_index_info*);
-#endif
+SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(Parse*);
SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
@@ -21481,6 +21988,7 @@ SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse*, int);
#define sqlite3SelectExprHeight(x) 0
#define sqlite3ExprCheckHeight(x,y)
#endif
+SQLITE_PRIVATE void sqlite3ExprSetErrorOffset(Expr*,int);
SQLITE_PRIVATE u32 sqlite3Get4byte(const u8*);
SQLITE_PRIVATE void sqlite3Put4byte(u8*, u32);
@@ -21766,9 +22274,6 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
"4_BYTE_ALIGNED_MALLOC",
#endif
-#ifdef SQLITE_64BIT_STATS
- "64BIT_STATS",
-#endif
#ifdef SQLITE_ALLOW_COVERING_INDEX_SCAN
# if SQLITE_ALLOW_COVERING_INDEX_SCAN != 1
"ALLOW_COVERING_INDEX_SCAN=" CTIMEOPT_VAL(SQLITE_ALLOW_COVERING_INDEX_SCAN),
@@ -22064,6 +22569,9 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
"EXPLAIN_ESTIMATED_ROWS",
#endif
+#ifdef SQLITE_EXTRA_AUTOEXT
+ "EXTRA_AUTOEXT=" CTIMEOPT_VAL(SQLITE_EXTRA_AUTOEXT),
+#endif
#ifdef SQLITE_EXTRA_IFNULLROW
"EXTRA_IFNULLROW",
#endif
@@ -22105,6 +22613,9 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX
"INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX),
#endif
+#ifdef SQLITE_LEGACY_JSON_VALID
+ "LEGACY_JSON_VALID",
+#endif
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
"LIKE_DOESNT_MATCH_BLOBS",
#endif
@@ -22342,6 +22853,9 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
"OMIT_SCHEMA_VERSION_PRAGMAS",
#endif
+#ifdef SQLITE_OMIT_SEH
+ "OMIT_SEH",
+#endif
#ifdef SQLITE_OMIT_SHARED_CACHE
"OMIT_SHARED_CACHE",
#endif
@@ -22593,7 +23107,7 @@ SQLITE_PRIVATE const unsigned char *sqlite3aGTb = &sqlite3UpperToLower[256+12-OP
** isalnum() 0x06
** isxdigit() 0x08
** toupper() 0x20
-** SQLite identifier character 0x40
+** SQLite identifier character 0x40 $, _, or non-ascii
** Quote character 0x80
**
** Bit 0x20 is set if the mapped character requires translation to upper
@@ -22739,6 +23253,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
0, /* bSmallMalloc */
1, /* bExtraSchemaChecks */
+ sizeof(LONGDOUBLE_TYPE)>8, /* bUseLongDouble */
0x7ffffffe, /* mxStrlen */
0, /* neverCorrupt */
SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */
@@ -22968,6 +23483,9 @@ typedef struct VdbeSorter VdbeSorter;
/* Elements of the linked list at Vdbe.pAuxData */
typedef struct AuxData AuxData;
+/* A cache of large TEXT or BLOB values in a VdbeCursor */
+typedef struct VdbeTxtBlbCache VdbeTxtBlbCache;
+
/* Types of VDBE cursors */
#define CURTYPE_BTREE 0
#define CURTYPE_SORTER 1
@@ -22999,6 +23517,7 @@ struct VdbeCursor {
Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */
Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
Bool noReuse:1; /* OpenEphemeral may not reuse this cursor */
+ Bool colCache:1; /* pCache pointer is initialized and non-NULL */
u16 seekHit; /* See the OP_SeekHit and OP_IfNoHope opcodes */
union { /* pBtx for isEphermeral. pAltMap otherwise */
Btree *pBtx; /* Separate file holding temporary table */
@@ -23039,6 +23558,7 @@ struct VdbeCursor {
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
u64 maskUsed; /* Mask of columns used by this cursor */
#endif
+ VdbeTxtBlbCache *pCache; /* Cache of large TEXT or BLOB values */
/* 2*nField extra array elements allocated for aType[], beyond the one
** static element declared in the structure. nField total array slots for
@@ -23051,12 +23571,25 @@ struct VdbeCursor {
#define IsNullCursor(P) \
((P)->eCurType==CURTYPE_PSEUDO && (P)->nullRow && (P)->seekResult==0)
-
/*
** A value for VdbeCursor.cacheStatus that means the cache is always invalid.
*/
#define CACHE_STALE 0
+/*
+** Large TEXT or BLOB values can be slow to load, so we want to avoid
+** loading them more than once. For that reason, large TEXT and BLOB values
+** can be stored in a cache defined by this object, and attached to the
+** VdbeCursor using the pCache field.
+*/
+struct VdbeTxtBlbCache {
+ char *pCValue; /* A RCStr buffer to hold the value */
+ i64 iOffset; /* File offset of the row being cached */
+ int iCol; /* Column for which the cache is valid */
+ u32 cacheStatus; /* Vdbe.cacheCtr value */
+ u32 colCacheCtr; /* Column cache counter */
+};
+
/*
** When a sub-program is executed (OP_Program), a structure of this type
** is allocated to store the current value of the program counter, as
@@ -23377,16 +23910,18 @@ struct Vdbe {
u32 nWrite; /* Number of write operations that have occurred */
#endif
u16 nResColumn; /* Number of columns in one row of the result set */
+ u16 nResAlloc; /* Column slots allocated to aColName[] */
u8 errorAction; /* Recovery action to do in case of an error */
u8 minWriteFileFormat; /* Minimum file format for writable database files */
u8 prepFlags; /* SQLITE_PREPARE_* flags */
u8 eVdbeState; /* On of the VDBE_*_STATE values */
bft expired:2; /* 1: recompile VM immediately 2: when convenient */
- bft explain:2; /* True if EXPLAIN present on SQL command */
+ bft explain:2; /* 0: normal, 1: EXPLAIN, 2: EXPLAIN QUERY PLAN */
bft changeCntOn:1; /* True to update the change-counter */
bft usesStmtJournal:1; /* True if uses a statement journal */
bft readOnly:1; /* True for statements that do not write */
bft bIsReader:1; /* True for statements that read */
+ bft haveEqpOps:1; /* Bytecode supports EXPLAIN QUERY PLAN */
yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
yDbMask lockMask; /* Subset of btreeMask that requires a lock */
u32 aCounter[9]; /* Counters used by sqlite3_stmt_status() */
@@ -23434,7 +23969,7 @@ struct PreUpdate {
i64 iKey1; /* First key value passed to hook */
i64 iKey2; /* Second key value passed to hook */
Mem *aNew; /* Array of new.* values */
- Table *pTab; /* Schema object being upated */
+ Table *pTab; /* Schema object being updated */
Index *pPk; /* PK index if pTab is WITHOUT ROWID */
};
@@ -23524,6 +24059,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetZeroBlob(Mem*,int);
SQLITE_PRIVATE int sqlite3VdbeMemIsRowSet(const Mem*);
#endif
SQLITE_PRIVATE int sqlite3VdbeMemSetRowSet(Mem*);
+SQLITE_PRIVATE void sqlite3VdbeMemZeroTerminateIfAble(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, u8, u8);
SQLITE_PRIVATE int sqlite3IntFloatCompare(i64,double);
@@ -23805,6 +24341,24 @@ SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){
return db->lookaside.nSlot - (nInit+nFree);
}
+/*
+** Hacky, and will be gone once we move WAL encryption layer
+** entirely to virtual WAL.
+** Assumes the BTree locks are already held.
+*/
+#ifdef LIBSQL_CUSTOM_PAGER_CODEC
+void *libsql_leak_pager(sqlite3 *db) {
+ int i;
+ for(i=0; inDb; i++){
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ){
+ return sqlite3BtreePager(pBt);
+ }
+ }
+ return NULL;
+}
+#endif
+
/*
** Query status information for a single database connection
*/
@@ -24087,6 +24641,7 @@ struct DateTime {
char validTZ; /* True (1) if tz is valid */
char tzSet; /* Timezone was set explicitly */
char isError; /* An overflow has occurred */
+ char useSubsec; /* Display subsecond precision */
};
@@ -24119,8 +24674,8 @@ struct DateTime {
*/
static int getDigits(const char *zDate, const char *zFormat, ...){
/* The aMx[] array translates the 3rd character of each format
- ** spec into a max size: a b c d e f */
- static const u16 aMx[] = { 12, 14, 24, 31, 59, 9999 };
+ ** spec into a max size: a b c d e f */
+ static const u16 aMx[] = { 12, 14, 24, 31, 59, 14712 };
va_list ap;
int cnt = 0;
char nextC;
@@ -24401,6 +24956,11 @@ static int parseDateOrTime(
}else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8)>0 ){
setRawDateNumber(p, r);
return 0;
+ }else if( (sqlite3StrICmp(zDate,"subsec")==0
+ || sqlite3StrICmp(zDate,"subsecond")==0)
+ && sqlite3NotPureFunc(context) ){
+ p->useSubsec = 1;
+ return setDateTimeToCurrent(context, p);
}
return 1;
}
@@ -24456,17 +25016,14 @@ static void computeYMD(DateTime *p){
** Compute the Hour, Minute, and Seconds from the julian day number.
*/
static void computeHMS(DateTime *p){
- int s;
+ int day_ms, day_min; /* milliseconds, minutes into the day */
if( p->validHMS ) return;
computeJD(p);
- s = (int)((p->iJD + 43200000) % 86400000);
- p->s = s/1000.0;
- s = (int)p->s;
- p->s -= s;
- p->h = s/3600;
- s -= p->h*3600;
- p->m = s/60;
- p->s += s - p->m*60;
+ day_ms = (int)((p->iJD + 43200000) % 86400000);
+ p->s = (day_ms % 60000)/1000.0;
+ day_min = day_ms/60000;
+ p->m = day_min % 60;
+ p->h = day_min / 60;
p->rawS = 0;
p->validHMS = 1;
}
@@ -24645,6 +25202,25 @@ static const struct {
{ 4, "year", 14713.0, 31536000.0 },
};
+/*
+** If the DateTime p is raw number, try to figure out if it is
+** a julian day number of a unix timestamp. Set the p value
+** appropriately.
+*/
+static void autoAdjustDate(DateTime *p){
+ if( !p->rawS || p->validJD ){
+ p->rawS = 0;
+ }else if( p->s>=-21086676*(i64)10000 /* -4713-11-24 12:00:00 */
+ && p->s<=(25340230*(i64)10000)+799 /* 9999-12-31 23:59:59 */
+ ){
+ double r = p->s*1000.0 + 210866760000000.0;
+ clearYMD_HMS_TZ(p);
+ p->iJD = (sqlite3_int64)(r + 0.5);
+ p->validJD = 1;
+ p->rawS = 0;
+ }
+}
+
/*
** Process a modifier to a date-time stamp. The modifiers are
** as follows:
@@ -24688,19 +25264,8 @@ static int parseModifier(
*/
if( sqlite3_stricmp(z, "auto")==0 ){
if( idx>1 ) return 1; /* IMP: R-33611-57934 */
- if( !p->rawS || p->validJD ){
- rc = 0;
- p->rawS = 0;
- }else if( p->s>=-21086676*(i64)10000 /* -4713-11-24 12:00:00 */
- && p->s<=(25340230*(i64)10000)+799 /* 9999-12-31 23:59:59 */
- ){
- r = p->s*1000.0 + 210866760000000.0;
- clearYMD_HMS_TZ(p);
- p->iJD = (sqlite3_int64)(r + 0.5);
- p->validJD = 1;
- p->rawS = 0;
- rc = 0;
- }
+ autoAdjustDate(p);
+ rc = 0;
}
break;
}
@@ -24815,8 +25380,22 @@ static int parseModifier(
**
** Move the date backwards to the beginning of the current day,
** or month or year.
+ **
+ ** subsecond
+ ** subsec
+ **
+ ** Show subsecond precision in the output of datetime() and
+ ** unixepoch() and strftime('%s').
*/
- if( sqlite3_strnicmp(z, "start of ", 9)!=0 ) break;
+ if( sqlite3_strnicmp(z, "start of ", 9)!=0 ){
+ if( sqlite3_stricmp(z, "subsec")==0
+ || sqlite3_stricmp(z, "subsecond")==0
+ ){
+ p->useSubsec = 1;
+ rc = 0;
+ }
+ break;
+ }
if( !p->validJD && !p->validYMD && !p->validHMS ) break;
z += 9;
computeYMD(p);
@@ -24852,18 +25431,73 @@ static int parseModifier(
case '9': {
double rRounder;
int i;
- for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){}
+ int Y,M,D,h,m,x;
+ const char *z2 = z;
+ char z0 = z[0];
+ for(n=1; z[n]; n++){
+ if( z[n]==':' ) break;
+ if( sqlite3Isspace(z[n]) ) break;
+ if( z[n]=='-' ){
+ if( n==5 && getDigits(&z[1], "40f", &Y)==1 ) break;
+ if( n==6 && getDigits(&z[1], "50f", &Y)==1 ) break;
+ }
+ }
if( sqlite3AtoF(z, &r, n, SQLITE_UTF8)<=0 ){
- rc = 1;
+ assert( rc==1 );
break;
}
- if( z[n]==':' ){
+ if( z[n]=='-' ){
+ /* A modifier of the form (+|-)YYYY-MM-DD adds or subtracts the
+ ** specified number of years, months, and days. MM is limited to
+ ** the range 0-11 and DD is limited to 0-30.
+ */
+ if( z0!='+' && z0!='-' ) break; /* Must start with +/- */
+ if( n==5 ){
+ if( getDigits(&z[1], "40f-20a-20d", &Y, &M, &D)!=3 ) break;
+ }else{
+ assert( n==6 );
+ if( getDigits(&z[1], "50f-20a-20d", &Y, &M, &D)!=3 ) break;
+ z++;
+ }
+ if( M>=12 ) break; /* M range 0..11 */
+ if( D>=31 ) break; /* D range 0..30 */
+ computeYMD_HMS(p);
+ p->validJD = 0;
+ if( z0=='-' ){
+ p->Y -= Y;
+ p->M -= M;
+ D = -D;
+ }else{
+ p->Y += Y;
+ p->M += M;
+ }
+ x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
+ p->Y += x;
+ p->M -= x*12;
+ computeJD(p);
+ p->validHMS = 0;
+ p->validYMD = 0;
+ p->iJD += (i64)D*86400000;
+ if( z[11]==0 ){
+ rc = 0;
+ break;
+ }
+ if( sqlite3Isspace(z[11])
+ && getDigits(&z[12], "20c:20e", &h, &m)==2
+ ){
+ z2 = &z[12];
+ n = 2;
+ }else{
+ break;
+ }
+ }
+ if( z2[n]==':' ){
/* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
** specified number of hours, minutes, seconds, and fractional seconds
** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be
** omitted.
*/
- const char *z2 = z;
+
DateTime tx;
sqlite3_int64 day;
if( !sqlite3Isdigit(*z2) ) z2++;
@@ -24873,7 +25507,7 @@ static int parseModifier(
tx.iJD -= 43200000;
day = tx.iJD/86400000;
tx.iJD -= day*86400000;
- if( z[0]=='-' ) tx.iJD = -tx.iJD;
+ if( z0=='-' ) tx.iJD = -tx.iJD;
computeJD(p);
clearYMD_HMS_TZ(p);
p->iJD += tx.iJD;
@@ -24889,7 +25523,7 @@ static int parseModifier(
if( n>10 || n<3 ) break;
if( sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--;
computeJD(p);
- rc = 1;
+ assert( rc==1 );
rRounder = r<0 ? -0.5 : +0.5;
for(i=0; iM += (int)r;
@@ -25014,7 +25647,11 @@ static void unixepochFunc(
DateTime x;
if( isDate(context, argc, argv, &x)==0 ){
computeJD(&x);
- sqlite3_result_int64(context, x.iJD/1000 - 21086676*(i64)10000);
+ if( x.useSubsec ){
+ sqlite3_result_double(context, (x.iJD - 21086676*(i64)10000000)/1000.0);
+ }else{
+ sqlite3_result_int64(context, x.iJD/1000 - 21086676*(i64)10000);
+ }
}
}
@@ -25030,8 +25667,8 @@ static void datetimeFunc(
){
DateTime x;
if( isDate(context, argc, argv, &x)==0 ){
- int Y, s;
- char zBuf[24];
+ int Y, s, n;
+ char zBuf[32];
computeYMD_HMS(&x);
Y = x.Y;
if( Y<0 ) Y = -Y;
@@ -25052,15 +25689,28 @@ static void datetimeFunc(
zBuf[15] = '0' + (x.m/10)%10;
zBuf[16] = '0' + (x.m)%10;
zBuf[17] = ':';
- s = (int)x.s;
- zBuf[18] = '0' + (s/10)%10;
- zBuf[19] = '0' + (s)%10;
- zBuf[20] = 0;
+ if( x.useSubsec ){
+ s = (int)(1000.0*x.s + 0.5);
+ zBuf[18] = '0' + (s/10000)%10;
+ zBuf[19] = '0' + (s/1000)%10;
+ zBuf[20] = '.';
+ zBuf[21] = '0' + (s/100)%10;
+ zBuf[22] = '0' + (s/10)%10;
+ zBuf[23] = '0' + (s)%10;
+ zBuf[24] = 0;
+ n = 24;
+ }else{
+ s = (int)x.s;
+ zBuf[18] = '0' + (s/10)%10;
+ zBuf[19] = '0' + (s)%10;
+ zBuf[20] = 0;
+ n = 20;
+ }
if( x.Y<0 ){
zBuf[0] = '-';
- sqlite3_result_text(context, zBuf, 20, SQLITE_TRANSIENT);
+ sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT);
}else{
- sqlite3_result_text(context, &zBuf[1], 19, SQLITE_TRANSIENT);
+ sqlite3_result_text(context, &zBuf[1], n-1, SQLITE_TRANSIENT);
}
}
}
@@ -25077,7 +25727,7 @@ static void timeFunc(
){
DateTime x;
if( isDate(context, argc, argv, &x)==0 ){
- int s;
+ int s, n;
char zBuf[16];
computeHMS(&x);
zBuf[0] = '0' + (x.h/10)%10;
@@ -25086,11 +25736,24 @@ static void timeFunc(
zBuf[3] = '0' + (x.m/10)%10;
zBuf[4] = '0' + (x.m)%10;
zBuf[5] = ':';
- s = (int)x.s;
- zBuf[6] = '0' + (s/10)%10;
- zBuf[7] = '0' + (s)%10;
- zBuf[8] = 0;
- sqlite3_result_text(context, zBuf, 8, SQLITE_TRANSIENT);
+ if( x.useSubsec ){
+ s = (int)(1000.0*x.s + 0.5);
+ zBuf[6] = '0' + (s/10000)%10;
+ zBuf[7] = '0' + (s/1000)%10;
+ zBuf[8] = '.';
+ zBuf[9] = '0' + (s/100)%10;
+ zBuf[10] = '0' + (s/10)%10;
+ zBuf[11] = '0' + (s)%10;
+ zBuf[12] = 0;
+ n = 12;
+ }else{
+ s = (int)x.s;
+ zBuf[6] = '0' + (s/10)%10;
+ zBuf[7] = '0' + (s)%10;
+ zBuf[8] = 0;
+ n = 8;
+ }
+ sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT);
}
}
@@ -25145,7 +25808,7 @@ static void dateFunc(
** %M minute 00-59
** %s seconds since 1970-01-01
** %S seconds 00-59
-** %w day of week 0-6 sunday==0
+** %w day of week 0-6 Sunday==0
** %W week of year 00-53
** %Y year 0000-9999
** %% %
@@ -25171,13 +25834,16 @@ static void strftimeFunc(
computeJD(&x);
computeYMD_HMS(&x);
for(i=j=0; zFmt[i]; i++){
+ char cf;
if( zFmt[i]!='%' ) continue;
if( j12 ) h -= 12;
+ if( h==0 ) h = 12;
+ sqlite3_str_appendf(&sRes, cf=='I' ? "%02d" : "%2d", h);
break;
}
case 'W': /* Fall thru */
@@ -25199,7 +25878,7 @@ static void strftimeFunc(
y.D = 1;
computeJD(&y);
nDay = (int)((x.iJD-y.iJD+43200000)/86400000);
- if( zFmt[i]=='W' ){
+ if( cf=='W' ){
int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
wd = (int)(((x.iJD+43200000)/86400000)%7);
sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7);
@@ -25220,18 +25899,42 @@ static void strftimeFunc(
sqlite3_str_appendf(&sRes,"%02d",x.m);
break;
}
+ case 'p': /* Fall thru */
+ case 'P': {
+ if( x.h>=12 ){
+ sqlite3_str_append(&sRes, cf=='p' ? "PM" : "pm", 2);
+ }else{
+ sqlite3_str_append(&sRes, cf=='p' ? "AM" : "am", 2);
+ }
+ break;
+ }
+ case 'R': {
+ sqlite3_str_appendf(&sRes, "%02d:%02d", x.h, x.m);
+ break;
+ }
case 's': {
- i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
- sqlite3_str_appendf(&sRes,"%lld",iS);
+ if( x.useSubsec ){
+ sqlite3_str_appendf(&sRes,"%.3f",
+ (x.iJD - 21086676*(i64)10000000)/1000.0);
+ }else{
+ i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
+ sqlite3_str_appendf(&sRes,"%lld",iS);
+ }
break;
}
case 'S': {
sqlite3_str_appendf(&sRes,"%02d",(int)x.s);
break;
}
+ case 'T': {
+ sqlite3_str_appendf(&sRes,"%02d:%02d:%02d", x.h, x.m, (int)x.s);
+ break;
+ }
+ case 'u': /* Fall thru */
case 'w': {
- sqlite3_str_appendchar(&sRes, 1,
- (char)(((x.iJD+129600000)/86400000) % 7) + '0');
+ char c = (char)(((x.iJD+129600000)/86400000) % 7) + '0';
+ if( c=='0' && cf=='u' ) c = '7';
+ sqlite3_str_appendchar(&sRes, 1, c);
break;
}
case 'Y': {
@@ -25280,6 +25983,117 @@ static void cdateFunc(
dateFunc(context, 0, 0);
}
+/*
+** timediff(DATE1, DATE2)
+**
+** Return the amount of time that must be added to DATE2 in order to
+** convert it into DATE2. The time difference format is:
+**
+** +YYYY-MM-DD HH:MM:SS.SSS
+**
+** The initial "+" becomes "-" if DATE1 occurs before DATE2. For
+** date/time values A and B, the following invariant should hold:
+**
+** datetime(A) == (datetime(B, timediff(A,B))
+**
+** Both DATE arguments must be either a julian day number, or an
+** ISO-8601 string. The unix timestamps are not supported by this
+** routine.
+*/
+static void timediffFunc(
+ sqlite3_context *context,
+ int NotUsed1,
+ sqlite3_value **argv
+){
+ char sign;
+ int Y, M;
+ DateTime d1, d2;
+ sqlite3_str sRes;
+ UNUSED_PARAMETER(NotUsed1);
+ if( isDate(context, 1, &argv[0], &d1) ) return;
+ if( isDate(context, 1, &argv[1], &d2) ) return;
+ computeYMD_HMS(&d1);
+ computeYMD_HMS(&d2);
+ if( d1.iJD>=d2.iJD ){
+ sign = '+';
+ Y = d1.Y - d2.Y;
+ if( Y ){
+ d2.Y = d1.Y;
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ M = d1.M - d2.M;
+ if( M<0 ){
+ Y--;
+ M += 12;
+ }
+ if( M!=0 ){
+ d2.M = d1.M;
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ while( d1.iJDd2.iJD ){
+ M--;
+ if( M<0 ){
+ M = 11;
+ Y--;
+ }
+ d2.M++;
+ if( d2.M>12 ){
+ d2.M = 1;
+ d2.Y++;
+ }
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ d1.iJD = d2.iJD - d1.iJD;
+ d1.iJD += (u64)1486995408 * (u64)100000;
+ }
+ d1.validYMD = 0;
+ d1.validHMS = 0;
+ d1.validTZ = 0;
+ computeYMD_HMS(&d1);
+ sqlite3StrAccumInit(&sRes, 0, 0, 0, 100);
+ sqlite3_str_appendf(&sRes, "%c%04d-%02d-%02d %02d:%02d:%06.3f",
+ sign, Y, M, d1.D-1, d1.h, d1.m, d1.s);
+ sqlite3ResultStrAccum(context, &sRes);
+}
+
+
/*
** current_timestamp()
**
@@ -25354,6 +26168,7 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
PURE_DATE(time, -1, 0, 0, timeFunc ),
PURE_DATE(datetime, -1, 0, 0, datetimeFunc ),
PURE_DATE(strftime, -1, 0, 0, strftimeFunc ),
+ PURE_DATE(timediff, 2, 0, 0, timediffFunc ),
DFUNCTION(current_time, 0, 0, 0, ctimeFunc ),
DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
DFUNCTION(current_date, 0, 0, 0, cdateFunc ),
@@ -25507,7 +26322,7 @@ SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
/* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
** is using a regular VFS, it is called after the corresponding
** transaction has been committed. Injecting a fault at this point
- ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM
+ ** confuses the test scripts - the COMMIT command returns SQLITE_NOMEM
** but the transaction is committed anyway.
**
** The core must call OsFileControl() though, not OsFileControlHint(),
@@ -26128,7 +26943,7 @@ static void *sqlite3MemMalloc(int nByte){
** or sqlite3MemRealloc().
**
** For this low-level routine, we already know that pPrior!=0 since
-** cases where pPrior==0 will have been intecepted and dealt with
+** cases where pPrior==0 will have been intercepted and dealt with
** by higher-level routines.
*/
static void sqlite3MemFree(void *pPrior){
@@ -26216,7 +27031,7 @@ static int sqlite3MemInit(void *NotUsed){
return SQLITE_OK;
}
len = sizeof(cpuCount);
- /* One usually wants to use hw.acctivecpu for MT decisions, but not here */
+ /* One usually wants to use hw.activecpu for MT decisions, but not here */
sysctlbyname("hw.ncpu", &cpuCount, &len, NULL, 0);
if( cpuCount>1 ){
/* defer MT decisions to system malloc */
@@ -28208,7 +29023,7 @@ static void checkMutexFree(sqlite3_mutex *p){
assert( SQLITE_MUTEX_FAST<2 );
assert( SQLITE_MUTEX_WARNONCONTENTION<2 );
-#if SQLITE_ENABLE_API_ARMOR
+#ifdef SQLITE_ENABLE_API_ARMOR
if( ((CheckMutex*)p)->iType<2 )
#endif
{
@@ -28683,7 +29498,7 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
/*
** The sqlite3_mutex.id, sqlite3_mutex.nRef, and sqlite3_mutex.owner fields
-** are necessary under two condidtions: (1) Debug builds and (2) using
+** are necessary under two conditions: (1) Debug builds and (2) using
** home-grown mutexes. Encapsulate these conditions into a single #define.
*/
#if defined(SQLITE_DEBUG) || defined(SQLITE_HOMEGROWN_RECURSIVE_MUTEX)
@@ -28880,7 +29695,7 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
*/
static void pthreadMutexFree(sqlite3_mutex *p){
assert( p->nRef==0 );
-#if SQLITE_ENABLE_API_ARMOR
+#ifdef SQLITE_ENABLE_API_ARMOR
if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE )
#endif
{
@@ -29184,7 +29999,7 @@ struct sqlite3_mutex {
CRITICAL_SECTION mutex; /* Mutex controlling the lock */
int id; /* Mutex type */
#ifdef SQLITE_DEBUG
- volatile int nRef; /* Number of enterances */
+ volatile int nRef; /* Number of entrances */
volatile DWORD owner; /* Thread holding this mutex */
volatile LONG trace; /* True to trace changes */
#endif
@@ -30444,7 +31259,7 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
if( db->mallocFailed || rc ){
return apiHandleError(db, rc);
}
- return rc & db->errMask;
+ return 0;
}
/************** End of malloc.c **********************************************/
@@ -30556,57 +31371,6 @@ static const et_info fmtinfo[] = {
** %!S Like %S but prefer the zName over the zAlias
*/
-/* Floating point constants used for rounding */
-static const double arRound[] = {
- 5.0e-01, 5.0e-02, 5.0e-03, 5.0e-04, 5.0e-05,
- 5.0e-06, 5.0e-07, 5.0e-08, 5.0e-09, 5.0e-10,
-};
-
-/*
-** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point
-** conversions will work.
-*/
-#ifndef SQLITE_OMIT_FLOATING_POINT
-/*
-** "*val" is a double such that 0.1 <= *val < 10.0
-** Return the ascii code for the leading digit of *val, then
-** multiply "*val" by 10.0 to renormalize.
-**
-** Example:
-** input: *val = 3.14159
-** output: *val = 1.4159 function return = '3'
-**
-** The counter *cnt is incremented each time. After counter exceeds
-** 16 (the number of significant digits in a 64-bit float) '0' is
-** always returned.
-*/
-static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
- int digit;
- LONGDOUBLE_TYPE d;
- if( (*cnt)<=0 ) return '0';
- (*cnt)--;
- digit = (int)*val;
- d = digit;
- digit += '0';
- *val = (*val - d)*10.0;
- return (char)digit;
-}
-#endif /* SQLITE_OMIT_FLOATING_POINT */
-
-#ifndef SQLITE_OMIT_FLOATING_POINT
-/*
-** "*val" is a u64. *msd is a divisor used to extract the
-** most significant digit of *val. Extract that most significant
-** digit and return it.
-*/
-static char et_getdigit_int(u64 *val, u64 *msd){
- u64 x = (*val)/(*msd);
- *val -= x*(*msd);
- if( *msd>=10 ) *msd /= 10;
- return '0' + (char)(x & 15);
-}
-#endif /* SQLITE_OMIT_FLOATING_POINT */
-
/*
** Set the StrAccum object to an error mode.
*/
@@ -30698,20 +31462,15 @@ SQLITE_API void sqlite3_str_vappendf(
u8 bArgList; /* True for SQLITE_PRINTF_SQLFUNC */
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
sqlite_uint64 longvalue; /* Value for integer types */
- LONGDOUBLE_TYPE realvalue; /* Value for real types */
- sqlite_uint64 msd; /* Divisor to get most-significant-digit
- ** of longvalue */
+ double realvalue; /* Value for real types */
const et_info *infop; /* Pointer to the appropriate info structure */
char *zOut; /* Rendering buffer */
int nOut; /* Size of the rendering buffer */
char *zExtra = 0; /* Malloced memory used by some conversion */
-#ifndef SQLITE_OMIT_FLOATING_POINT
- int exp, e2; /* exponent of real numbers */
- int nsd; /* Number of significant digits returned */
- double rounder; /* Used for rounding floating point values */
+ int exp, e2; /* exponent of real numbers */
etByte flag_dp; /* True if decimal point should be shown */
etByte flag_rtz; /* True if trailing zeros should be removed */
-#endif
+
PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */
char buf[etBUFSIZE]; /* Conversion buffer */
@@ -30986,84 +31745,61 @@ SQLITE_API void sqlite3_str_vappendf(
break;
case etFLOAT:
case etEXP:
- case etGENERIC:
+ case etGENERIC: {
+ FpDecode s;
+ int iRound;
+ int j;
+
if( bArgList ){
realvalue = getDoubleArg(pArgList);
}else{
realvalue = va_arg(ap,double);
}
-#ifdef SQLITE_OMIT_FLOATING_POINT
- length = 0;
-#else
if( precision<0 ) precision = 6; /* Set default precision */
#ifdef SQLITE_FP_PRECISION_LIMIT
if( precision>SQLITE_FP_PRECISION_LIMIT ){
precision = SQLITE_FP_PRECISION_LIMIT;
}
#endif
- if( realvalue<0.0 ){
- realvalue = -realvalue;
- prefix = '-';
+ if( xtype==etFLOAT ){
+ iRound = -precision;
+ }else if( xtype==etGENERIC ){
+ iRound = precision;
}else{
- prefix = flag_prefix;
+ iRound = precision+1;
}
- exp = 0;
- if( xtype==etGENERIC && precision>0 ) precision--;
- testcase( precision>0xfff );
- if( realvalue<1.0e+16
- && realvalue==(LONGDOUBLE_TYPE)(longvalue = (u64)realvalue)
- ){
- /* Number is a pure integer that can be represented as u64 */
- for(msd=1; msd*10<=longvalue; msd *= 10, exp++){}
- if( exp>precision && xtype!=etFLOAT ){
- u64 rnd = msd/2;
- int kk = precision;
- while( kk-- > 0 ){ rnd /= 10; }
- longvalue += rnd;
- }
- }else{
- msd = 0;
- longvalue = 0; /* To prevent a compiler warning */
- idx = precision & 0xfff;
- rounder = arRound[idx%10];
- while( idx>=10 ){ rounder *= 1.0e-10; idx -= 10; }
- if( xtype==etFLOAT ){
- double rx = (double)realvalue;
- sqlite3_uint64 u;
- int ex;
- memcpy(&u, &rx, sizeof(u));
- ex = -1023 + (int)((u>>52)&0x7ff);
- if( precision+(ex/3) < 15 ) rounder += realvalue*3e-16;
- realvalue += rounder;
- }
- if( sqlite3IsNaN((double)realvalue) ){
- bufpt = "NaN";
- length = 3;
+ sqlite3FpDecode(&s, realvalue, iRound, flag_altform2 ? 26 : 16);
+ if( s.isSpecial ){
+ if( s.isSpecial==2 ){
+ bufpt = flag_zeropad ? "null" : "NaN";
+ length = sqlite3Strlen30(bufpt);
break;
- }
-
- /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
- if( ALWAYS(realvalue>0.0) ){
- LONGDOUBLE_TYPE scale = 1.0;
- while( realvalue>=1e100*scale && exp<=350){ scale*=1e100;exp+=100;}
- while( realvalue>=1e10*scale && exp<=350 ){ scale*=1e10; exp+=10; }
- while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; }
- realvalue /= scale;
- while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; }
- while( realvalue<1.0 ){ realvalue *= 10.0; exp--; }
- if( exp>350 ){
- bufpt = buf;
- buf[0] = prefix;
- memcpy(buf+(prefix!=0),"Inf",4);
- length = 3+(prefix!=0);
- break;
- }
- if( xtype!=etFLOAT ){
- realvalue += rounder;
- if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
+ }else if( flag_zeropad ){
+ s.z[0] = '9';
+ s.iDP = 1000;
+ s.n = 1;
+ }else{
+ memcpy(buf, "-Inf", 5);
+ bufpt = buf;
+ if( s.sign=='-' ){
+ /* no-op */
+ }else if( flag_prefix ){
+ buf[0] = flag_prefix;
+ }else{
+ bufpt++;
}
+ length = sqlite3Strlen30(bufpt);
+ break;
}
}
+ if( s.sign=='-' ){
+ prefix = '-';
+ }else{
+ prefix = flag_prefix;
+ }
+
+ exp = s.iDP-1;
+ if( xtype==etGENERIC && precision>0 ) precision--;
/*
** If the field type is etGENERIC, then convert to either etEXP
@@ -31083,13 +31819,13 @@ SQLITE_API void sqlite3_str_vappendf(
if( xtype==etEXP ){
e2 = 0;
}else{
- e2 = exp;
+ e2 = s.iDP - 1;
}
- nsd = 16 + flag_altform2*10;
bufpt = buf;
{
i64 szBufNeeded; /* Size of a temporary buffer needed */
szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+15;
+ if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3;
if( szBufNeeded > etBUFSIZE ){
bufpt = zExtra = printfTempBuf(pAccum, szBufNeeded);
if( bufpt==0 ) return;
@@ -31102,15 +31838,13 @@ SQLITE_API void sqlite3_str_vappendf(
*(bufpt++) = prefix;
}
/* Digits prior to the decimal point */
+ j = 0;
if( e2<0 ){
*(bufpt++) = '0';
- }else if( msd>0 ){
- for(; e2>=0; e2--){
- *(bufpt++) = et_getdigit_int(&longvalue,&msd);
- }
}else{
for(; e2>=0; e2--){
- *(bufpt++) = et_getdigit(&realvalue,&nsd);
+ *(bufpt++) = j1 ) *(bufpt++) = ',';
}
}
/* The decimal point */
@@ -31119,19 +31853,12 @@ SQLITE_API void sqlite3_str_vappendf(
}
/* "0" digits after the decimal point but before the first
** significant digit of the number */
- for(e2++; e2<0; precision--, e2++){
- assert( precision>0 );
+ for(e2++; e2<0 && precision>0; precision--, e2++){
*(bufpt++) = '0';
}
/* Significant digits after the decimal point */
- if( msd>0 ){
- while( (precision--)>0 ){
- *(bufpt++) = et_getdigit_int(&longvalue,&msd);
- }
- }else{
- while( (precision--)>0 ){
- *(bufpt++) = et_getdigit(&realvalue,&nsd);
- }
+ while( (precision--)>0 ){
+ *(bufpt++) = jcharset];
if( exp<0 ){
*(bufpt++) = '-'; exp = -exp;
@@ -31180,8 +31908,8 @@ SQLITE_API void sqlite3_str_vappendf(
while( nPad-- ) bufpt[i++] = '0';
length = width;
}
-#endif /* !defined(SQLITE_OMIT_FLOATING_POINT) */
break;
+ }
case etSIZE:
if( !bArgList ){
*(va_arg(ap,int*)) = pAccum->nChar;
@@ -31905,6 +32633,75 @@ SQLITE_API void sqlite3_str_appendf(StrAccum *p, const char *zFormat, ...){
va_end(ap);
}
+
+/*****************************************************************************
+** Reference counted string storage
+*****************************************************************************/
+
+/*
+** Increase the reference count of the string by one.
+**
+** The input parameter is returned.
+*/
+SQLITE_PRIVATE char *sqlite3RCStrRef(char *z){
+ RCStr *p = (RCStr*)z;
+ assert( p!=0 );
+ p--;
+ p->nRCRef++;
+ return z;
+}
+
+/*
+** Decrease the reference count by one. Free the string when the
+** reference count reaches zero.
+*/
+SQLITE_PRIVATE void sqlite3RCStrUnref(void *z){
+ RCStr *p = (RCStr*)z;
+ assert( p!=0 );
+ p--;
+ assert( p->nRCRef>0 );
+ if( p->nRCRef>=2 ){
+ p->nRCRef--;
+ }else{
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Create a new string that is capable of holding N bytes of text, not counting
+** the zero byte at the end. The string is uninitialized.
+**
+** The reference count is initially 1. Call sqlite3RCStrUnref() to free the
+** newly allocated string.
+**
+** This routine returns 0 on an OOM.
+*/
+SQLITE_PRIVATE char *sqlite3RCStrNew(u64 N){
+ RCStr *p = sqlite3_malloc64( N + sizeof(*p) + 1 );
+ if( p==0 ) return 0;
+ p->nRCRef = 1;
+ return (char*)&p[1];
+}
+
+/*
+** Change the size of the string so that it is able to hold N bytes.
+** The string might be reallocated, so return the new allocation.
+*/
+SQLITE_PRIVATE char *sqlite3RCStrResize(char *z, u64 N){
+ RCStr *p = (RCStr*)z;
+ RCStr *pNew;
+ assert( p!=0 );
+ p--;
+ assert( p->nRCRef==1 );
+ pNew = sqlite3_realloc64(p, N+sizeof(RCStr)+1);
+ if( pNew==0 ){
+ sqlite3_free(p);
+ return 0;
+ }else{
+ return (char*)&pNew[1];
+ }
+}
+
/************** End of printf.c **********************************************/
/************** Begin file treeview.c ****************************************/
/*
@@ -32321,6 +33118,7 @@ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u
sqlite3TreeViewItem(pView, "FILTER", 1);
sqlite3TreeViewExpr(pView, pWin->pFilter, 0);
sqlite3TreeViewPop(&pView);
+ if( pWin->eFrmType==TK_FILTER ) return;
}
sqlite3TreeViewPush(&pView, more);
if( pWin->zName ){
@@ -32330,7 +33128,7 @@ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u
}
if( pWin->zBase ) nElement++;
if( pWin->pOrderBy ) nElement++;
- if( pWin->eFrmType ) nElement++;
+ if( pWin->eFrmType!=0 && pWin->eFrmType!=TK_FILTER ) nElement++;
if( pWin->eExclude ) nElement++;
if( pWin->zBase ){
sqlite3TreeViewPush(&pView, (--nElement)>0);
@@ -32343,7 +33141,7 @@ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u
if( pWin->pOrderBy ){
sqlite3TreeViewExprList(pView, pWin->pOrderBy, (--nElement)>0, "ORDER-BY");
}
- if( pWin->eFrmType ){
+ if( pWin->eFrmType!=0 && pWin->eFrmType!=TK_FILTER ){
char zBuf[30];
const char *zFrmType = "ROWS";
if( pWin->eFrmType==TK_RANGE ) zFrmType = "RANGE";
@@ -32552,7 +33350,8 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
};
assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT );
assert( pExpr->pRight );
- assert( sqlite3ExprSkipCollate(pExpr->pRight)->op==TK_TRUEFALSE );
+ assert( sqlite3ExprSkipCollateAndLikely(pExpr->pRight)->op
+ == TK_TRUEFALSE );
x = (pExpr->op2==TK_ISNOT)*2 + sqlite3ExprTruthValue(pExpr->pRight);
zUniOp = azOp[x];
break;
@@ -32590,7 +33389,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
assert( ExprUseXList(pExpr) );
pFarg = pExpr->x.pList;
#ifndef SQLITE_OMIT_WINDOWFUNC
- pWin = ExprHasProperty(pExpr, EP_WinFunc) ? pExpr->y.pWin : 0;
+ pWin = IsWindowFunc(pExpr) ? pExpr->y.pWin : 0;
#else
pWin = 0;
#endif
@@ -32616,7 +33415,13 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
sqlite3TreeViewLine(pView, "FUNCTION %Q%s", pExpr->u.zToken, zFlgs);
}
if( pFarg ){
- sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0);
+ sqlite3TreeViewExprList(pView, pFarg, pWin!=0 || pExpr->pLeft, 0);
+ if( pExpr->pLeft ){
+ Expr *pOB = pExpr->pLeft;
+ assert( pOB->op==TK_ORDER );
+ assert( ExprUseXList(pOB) );
+ sqlite3TreeViewExprList(pView, pOB->x.pList, pWin!=0, "ORDERBY");
+ }
}
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pWin ){
@@ -32625,6 +33430,10 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
#endif
break;
}
+ case TK_ORDER: {
+ sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, "ORDERBY");
+ break;
+ }
#ifndef SQLITE_OMIT_SUBQUERY
case TK_EXISTS: {
assert( ExprUseXSelect(pExpr) );
@@ -34211,7 +35020,7 @@ SQLITE_PRIVATE void sqlite3UtfSelfTest(void){
/*
** Calls to sqlite3FaultSim() are used to simulate a failure during testing,
** or to bypass normal error detection during testing in order to let
-** execute proceed futher downstream.
+** execute proceed further downstream.
**
** In deployment, sqlite3FaultSim() *always* return SQLITE_OK (0). The
** sqlite3FaultSim() function only returns non-zero during testing.
@@ -34328,6 +35137,23 @@ SQLITE_PRIVATE void sqlite3ErrorClear(sqlite3 *db){
*/
SQLITE_PRIVATE void sqlite3SystemError(sqlite3 *db, int rc){
if( rc==SQLITE_IOERR_NOMEM ) return;
+#ifdef SQLITE_USE_SEH
+ if( rc==SQLITE_IOERR_IN_PAGE ){
+ int ii;
+ int iErr;
+ sqlite3BtreeEnterAll(db);
+ for(ii=0; iinDb; ii++){
+ if( db->aDb[ii].pBt ){
+ iErr = sqlite3PagerWalSystemErrno(sqlite3BtreePager(db->aDb[ii].pBt));
+ if( iErr ){
+ db->iSysErrno = iErr;
+ }
+ }
+ }
+ sqlite3BtreeLeaveAll(db);
+ return;
+ }
+#endif
rc &= 0xff;
if( rc==SQLITE_CANTOPEN || rc==SQLITE_IOERR ){
db->iSysErrno = sqlite3OsGetLastError(db->pVfs);
@@ -34372,12 +35198,16 @@ SQLITE_PRIVATE void sqlite3ProgressCheck(Parse *p){
p->rc = SQLITE_INTERRUPT;
}
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- if( db->xProgress && (++p->nProgressSteps)>=db->nProgressOps ){
- if( db->xProgress(db->pProgressArg) ){
- p->nErr++;
- p->rc = SQLITE_INTERRUPT;
+ if( db->xProgress ){
+ if( p->rc==SQLITE_INTERRUPT ){
+ p->nProgressSteps = 0;
+ }else if( (++p->nProgressSteps)>=db->nProgressOps ){
+ if( db->xProgress(db->pProgressArg) ){
+ p->nErr++;
+ p->rc = SQLITE_INTERRUPT;
+ }
+ p->nProgressSteps = 0;
}
- p->nProgressSteps = 0;
}
#endif
}
@@ -34573,43 +35403,40 @@ SQLITE_PRIVATE u8 sqlite3StrIHash(const char *z){
return h;
}
-/*
-** Compute 10 to the E-th power. Examples: E==1 results in 10.
-** E==2 results in 100. E==50 results in 1.0e50.
+/* Double-Double multiplication. (x[0],x[1]) *= (y,yy)
**
-** This routine only works for values of E between 1 and 341.
+** Reference:
+** T. J. Dekker, "A Floating-Point Technique for Extending the
+** Available Precision". 1971-07-26.
*/
-static LONGDOUBLE_TYPE sqlite3Pow10(int E){
-#if defined(_MSC_VER)
- static const LONGDOUBLE_TYPE x[] = {
- 1.0e+001L,
- 1.0e+002L,
- 1.0e+004L,
- 1.0e+008L,
- 1.0e+016L,
- 1.0e+032L,
- 1.0e+064L,
- 1.0e+128L,
- 1.0e+256L
- };
- LONGDOUBLE_TYPE r = 1.0;
- int i;
- assert( E>=0 && E<=307 );
- for(i=0; E!=0; i++, E >>=1){
- if( E & 1 ) r *= x[i];
- }
- return r;
-#else
- LONGDOUBLE_TYPE x = 10.0;
- LONGDOUBLE_TYPE r = 1.0;
- while(1){
- if( E & 1 ) r *= x;
- E >>= 1;
- if( E==0 ) break;
- x *= x;
- }
- return r;
-#endif
+static void dekkerMul2(volatile double *x, double y, double yy){
+ /*
+ ** The "volatile" keywords on parameter x[] and on local variables
+ ** below are needed force intermediate results to be truncated to
+ ** binary64 rather than be carried around in an extended-precision
+ ** format. The truncation is necessary for the Dekker algorithm to
+ ** work. Intel x86 floating point might omit the truncation without
+ ** the use of volatile.
+ */
+ volatile double tx, ty, p, q, c, cc;
+ double hx, hy;
+ u64 m;
+ memcpy(&m, (void*)&x[0], 8);
+ m &= 0xfffffffffc000000LL;
+ memcpy(&hx, &m, 8);
+ tx = x[0] - hx;
+ memcpy(&m, &y, 8);
+ m &= 0xfffffffffc000000LL;
+ memcpy(&hy, &m, 8);
+ ty = y - hy;
+ p = hx*hy;
+ q = hx*ty + tx*hy;
+ c = p+q;
+ cc = p - c + q + tx*ty;
+ cc = x[0]*yy + x[1]*y + cc;
+ x[0] = c + cc;
+ x[1] = c - x[0];
+ x[1] += cc;
}
/*
@@ -34650,12 +35477,11 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
const char *zEnd;
/* sign * significand * (10 ^ (esign * exponent)) */
int sign = 1; /* sign of significand */
- i64 s = 0; /* significand */
+ u64 s = 0; /* significand */
int d = 0; /* adjust exponent for shifting decimal point */
int esign = 1; /* sign of exponent */
int e = 0; /* exponent */
int eValid = 1; /* True exponent is either not used or is well-formed */
- double result;
int nDigit = 0; /* Number of digits processed */
int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */
@@ -34695,7 +35521,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
while( z=((LARGEST_INT64-9)/10) ){
+ if( s>=((LARGEST_UINT64-9)/10) ){
/* skip non-significant significand digits
** (increase exponent by d to shift decimal left) */
while( z0 ){ /*OPTIMIZATION-IF-TRUE*/
- if( esign>0 ){
- if( s>=(LARGEST_INT64/10) ) break; /*OPTIMIZATION-IF-FALSE*/
- s *= 10;
- }else{
- if( s%10!=0 ) break; /*OPTIMIZATION-IF-FALSE*/
- s /= 10;
- }
- e--;
- }
+ /* adjust exponent by d, and update sign */
+ e = (e*esign) + d;
- /* adjust the sign of significand */
- s = sign<0 ? -s : s;
+ /* Try to adjust the exponent to make it smaller */
+ while( e>0 && s<(LARGEST_UINT64/10) ){
+ s *= 10;
+ e--;
+ }
+ while( e<0 && (s%10)==0 ){
+ s /= 10;
+ e++;
+ }
- if( e==0 ){ /*OPTIMIZATION-IF-TRUE*/
- result = (double)s;
+ if( e==0 ){
+ *pResult = s;
+ }else if( sqlite3Config.bUseLongDouble ){
+ LONGDOUBLE_TYPE r = (LONGDOUBLE_TYPE)s;
+ if( e>0 ){
+ while( e>=100 ){ e-=100; r *= 1.0e+100L; }
+ while( e>=10 ){ e-=10; r *= 1.0e+10L; }
+ while( e>=1 ){ e-=1; r *= 1.0e+01L; }
}else{
- /* attempt to handle extremely small/large numbers better */
- if( e>307 ){ /*OPTIMIZATION-IF-TRUE*/
- if( e<342 ){ /*OPTIMIZATION-IF-TRUE*/
- LONGDOUBLE_TYPE scale = sqlite3Pow10(e-308);
- if( esign<0 ){
- result = s / scale;
- result /= 1.0e+308;
- }else{
- result = s * scale;
- result *= 1.0e+308;
- }
- }else{ assert( e>=342 );
- if( esign<0 ){
- result = 0.0*s;
- }else{
+ while( e<=-100 ){ e+=100; r *= 1.0e-100L; }
+ while( e<=-10 ){ e+=10; r *= 1.0e-10L; }
+ while( e<=-1 ){ e+=1; r *= 1.0e-01L; }
+ }
+ assert( r>=0.0 );
+ if( r>+1.7976931348623157081452742373e+308L ){
#ifdef INFINITY
- result = INFINITY*s;
+ *pResult = +INFINITY;
#else
- result = 1e308*1e308*s; /* Infinity */
+ *pResult = 1.0e308*10.0;
#endif
- }
- }
- }else{
- LONGDOUBLE_TYPE scale = sqlite3Pow10(e);
- if( esign<0 ){
- result = s / scale;
- }else{
- result = s * scale;
- }
+ }else{
+ *pResult = (double)r;
+ }
+ }else{
+ double rr[2];
+ u64 s2;
+ rr[0] = (double)s;
+ s2 = (u64)rr[0];
+ rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s);
+ if( e>0 ){
+ while( e>=100 ){
+ e -= 100;
+ dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
+ }
+ while( e>=10 ){
+ e -= 10;
+ dekkerMul2(rr, 1.0e+10, 0.0);
+ }
+ while( e>=1 ){
+ e -= 1;
+ dekkerMul2(rr, 1.0e+01, 0.0);
+ }
+ }else{
+ while( e<=-100 ){
+ e += 100;
+ dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
+ }
+ while( e<=-10 ){
+ e += 10;
+ dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
+ }
+ while( e<=-1 ){
+ e += 1;
+ dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
}
}
+ *pResult = rr[0]+rr[1];
+ if( sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300;
}
+ if( sign<0 ) *pResult = -*pResult;
+ assert( !sqlite3IsNaN(*pResult) );
- /* store the result */
- *pResult = result;
-
- /* return true if number and no extra non-whitespace chracters after */
+atof_return:
+ /* return true if number and no extra non-whitespace characters after */
if( z==zEnd && nDigit>0 && eValid && eType>0 ){
return eType;
}else if( eType>=2 && (eType==3 || eValid) && nDigit>0 ){
@@ -34857,13 +35693,15 @@ SQLITE_PRIVATE int sqlite3Int64ToText(i64 v, char *zOut){
}
i = sizeof(zTemp)-2;
zTemp[sizeof(zTemp)-1] = 0;
- do{
- zTemp[i--] = (x%10) + '0';
+ while( 1 /*exit-by-break*/ ){
+ zTemp[i] = (x%10) + '0';
x = x/10;
- }while( x );
- if( v<0 ) zTemp[i--] = '-';
- memcpy(zOut, &zTemp[i+1], sizeof(zTemp)-1-i);
- return sizeof(zTemp)-2-i;
+ if( x==0 ) break;
+ i--;
+ };
+ if( v<0 ) zTemp[--i] = '-';
+ memcpy(zOut, &zTemp[i], sizeof(zTemp)-i);
+ return sizeof(zTemp)-1-i;
}
/*
@@ -34956,7 +35794,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
/* This test and assignment is needed only to suppress UB warnings
** from clang and -fsanitize=undefined. This test and assignment make
** the code a little larger and slower, and no harm comes from omitting
- ** them, but we must appaise the undefined-behavior pharisees. */
+ ** them, but we must appease the undefined-behavior pharisees. */
*pNum = neg ? SMALLEST_INT64 : LARGEST_INT64;
}else if( neg ){
*pNum = -(i64)u;
@@ -35028,11 +35866,15 @@ SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
u = u*16 + sqlite3HexToInt(z[k]);
}
memcpy(pOut, &u, 8);
- return (z[k]==0 && k-i<=16) ? 0 : 2;
+ if( k-i>16 ) return 2;
+ if( z[k]!=0 ) return 1;
+ return 0;
}else
#endif /* SQLITE_OMIT_HEX_INTEGER */
{
- return sqlite3Atoi64(z, pOut, sqlite3Strlen30(z), SQLITE_UTF8);
+ int n = (int)(0x3fffffff&strspn(z,"+- \n\t0123456789"));
+ if( z[n] ) n++;
+ return sqlite3Atoi64(z, pOut, n, SQLITE_UTF8);
}
}
@@ -35064,7 +35906,7 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){
u32 u = 0;
zNum += 2;
while( zNum[0]=='0' ) zNum++;
- for(i=0; sqlite3Isxdigit(zNum[i]) && i<8; i++){
+ for(i=0; i<8 && sqlite3Isxdigit(zNum[i]); i++){
u = u*16 + sqlite3HexToInt(zNum[i]);
}
if( (u&0x80000000)==0 && sqlite3Isxdigit(zNum[i])==0 ){
@@ -35111,6 +35953,153 @@ SQLITE_PRIVATE int sqlite3Atoi(const char *z){
return x;
}
+/*
+** Decode a floating-point value into an approximate decimal
+** representation.
+**
+** Round the decimal representation to n significant digits if
+** n is positive. Or round to -n signficant digits after the
+** decimal point if n is negative. No rounding is performed if
+** n is zero.
+**
+** The significant digits of the decimal representation are
+** stored in p->z[] which is a often (but not always) a pointer
+** into the middle of p->zBuf[]. There are p->n significant digits.
+** The p->z[] array is *not* zero-terminated.
+*/
+SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){
+ int i;
+ u64 v;
+ int e, exp = 0;
+ p->isSpecial = 0;
+ p->z = p->zBuf;
+
+ /* Convert negative numbers to positive. Deal with Infinity, 0.0, and
+ ** NaN. */
+ if( r<0.0 ){
+ p->sign = '-';
+ r = -r;
+ }else if( r==0.0 ){
+ p->sign = '+';
+ p->n = 1;
+ p->iDP = 1;
+ p->z = "0";
+ return;
+ }else{
+ p->sign = '+';
+ }
+ memcpy(&v,&r,8);
+ e = v>>52;
+ if( (e&0x7ff)==0x7ff ){
+ p->isSpecial = 1 + (v!=0x7ff0000000000000LL);
+ p->n = 0;
+ p->iDP = 0;
+ return;
+ }
+
+ /* Multiply r by powers of ten until it lands somewhere in between
+ ** 1.0e+19 and 1.0e+17.
+ */
+ if( sqlite3Config.bUseLongDouble ){
+ LONGDOUBLE_TYPE rr = r;
+ if( rr>=1.0e+19 ){
+ while( rr>=1.0e+119L ){ exp+=100; rr *= 1.0e-100L; }
+ while( rr>=1.0e+29L ){ exp+=10; rr *= 1.0e-10L; }
+ while( rr>=1.0e+19L ){ exp++; rr *= 1.0e-1L; }
+ }else{
+ while( rr<1.0e-97L ){ exp-=100; rr *= 1.0e+100L; }
+ while( rr<1.0e+07L ){ exp-=10; rr *= 1.0e+10L; }
+ while( rr<1.0e+17L ){ exp--; rr *= 1.0e+1L; }
+ }
+ v = (u64)rr;
+ }else{
+ /* If high-precision floating point is not available using "long double",
+ ** then use Dekker-style double-double computation to increase the
+ ** precision.
+ **
+ ** The error terms on constants like 1.0e+100 computed using the
+ ** decimal extension, for example as follows:
+ **
+ ** SELECT decimal_exp(decimal_sub('1.0e+100',decimal(1.0e+100)));
+ */
+ double rr[2];
+ rr[0] = r;
+ rr[1] = 0.0;
+ if( rr[0]>9.223372036854774784e+18 ){
+ while( rr[0]>9.223372036854774784e+118 ){
+ exp += 100;
+ dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
+ }
+ while( rr[0]>9.223372036854774784e+28 ){
+ exp += 10;
+ dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
+ }
+ while( rr[0]>9.223372036854774784e+18 ){
+ exp += 1;
+ dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
+ }
+ }else{
+ while( rr[0]<9.223372036854774784e-83 ){
+ exp -= 100;
+ dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
+ }
+ while( rr[0]<9.223372036854774784e+07 ){
+ exp -= 10;
+ dekkerMul2(rr, 1.0e+10, 0.0);
+ }
+ while( rr[0]<9.22337203685477478e+17 ){
+ exp -= 1;
+ dekkerMul2(rr, 1.0e+01, 0.0);
+ }
+ }
+ v = rr[1]<0.0 ? (u64)rr[0]-(u64)(-rr[1]) : (u64)rr[0]+(u64)rr[1];
+ }
+
+
+ /* Extract significant digits. */
+ i = sizeof(p->zBuf)-1;
+ assert( v>0 );
+ while( v ){ p->zBuf[i--] = (v%10) + '0'; v /= 10; }
+ assert( i>=0 && izBuf)-1 );
+ p->n = sizeof(p->zBuf) - 1 - i;
+ assert( p->n>0 );
+ assert( p->nzBuf) );
+ p->iDP = p->n + exp;
+ if( iRound<0 ){
+ iRound = p->iDP - iRound;
+ if( iRound==0 && p->zBuf[i+1]>='5' ){
+ iRound = 1;
+ p->zBuf[i--] = '0';
+ p->n++;
+ p->iDP++;
+ }
+ }
+ if( iRound>0 && (iRoundn || p->n>mxRound) ){
+ char *z = &p->zBuf[i+1];
+ if( iRound>mxRound ) iRound = mxRound;
+ p->n = iRound;
+ if( z[iRound]>='5' ){
+ int j = iRound-1;
+ while( 1 /*exit-by-break*/ ){
+ z[j]++;
+ if( z[j]<='9' ) break;
+ z[j] = '0';
+ if( j==0 ){
+ p->z[i--] = '1';
+ p->n++;
+ p->iDP++;
+ break;
+ }else{
+ j--;
+ }
+ }
+ }
+ }
+ p->z = &p->zBuf[i+1];
+ assert( i+p->n < sizeof(p->zBuf) );
+ while( ALWAYS(p->n>0) && p->z[p->n-1]=='0' ){ p->n--; }
+}
+
/*
** Try to convert z into an unsigned 32-bit integer. Return true on
** success and false if there is an error.
@@ -35374,121 +36363,32 @@ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
** this function assumes the single-byte case has already been handled.
*/
SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
- u32 a,b;
+ u64 v64;
+ u8 n;
- /* The 1-byte case. Overwhelmingly the most common. Handled inline
- ** by the getVarin32() macro */
- a = *p;
- /* a: p0 (unmasked) */
-#ifndef getVarint32
- if (!(a&0x80))
- {
- /* Values between 0 and 127 */
- *v = a;
- return 1;
- }
-#endif
+ /* Assume that the single-byte case has already been handled by
+ ** the getVarint32() macro */
+ assert( (p[0] & 0x80)!=0 );
- /* The 2-byte case */
- p++;
- b = *p;
- /* b: p1 (unmasked) */
- if (!(b&0x80))
- {
- /* Values between 128 and 16383 */
- a &= 0x7f;
- a = a<<7;
- *v = a | b;
+ if( (p[1] & 0x80)==0 ){
+ /* This is the two-byte case */
+ *v = ((p[0]&0x7f)<<7) | p[1];
return 2;
}
-
- /* The 3-byte case */
- p++;
- a = a<<14;
- a |= *p;
- /* a: p0<<14 | p2 (unmasked) */
- if (!(a&0x80))
- {
- /* Values between 16384 and 2097151 */
- a &= (0x7f<<14)|(0x7f);
- b &= 0x7f;
- b = b<<7;
- *v = a | b;
+ if( (p[2] & 0x80)==0 ){
+ /* This is the three-byte case */
+ *v = ((p[0]&0x7f)<<14) | ((p[1]&0x7f)<<7) | p[2];
return 3;
}
-
- /* A 32-bit varint is used to store size information in btrees.
- ** Objects are rarely larger than 2MiB limit of a 3-byte varint.
- ** A 3-byte varint is sufficient, for example, to record the size
- ** of a 1048569-byte BLOB or string.
- **
- ** We only unroll the first 1-, 2-, and 3- byte cases. The very
- ** rare larger cases can be handled by the slower 64-bit varint
- ** routine.
- */
-#if 1
- {
- u64 v64;
- u8 n;
-
- n = sqlite3GetVarint(p-2, &v64);
- assert( n>3 && n<=9 );
- if( (v64 & SQLITE_MAX_U32)!=v64 ){
- *v = 0xffffffff;
- }else{
- *v = (u32)v64;
- }
- return n;
- }
-
-#else
- /* For following code (kept for historical record only) shows an
- ** unrolling for the 3- and 4-byte varint cases. This code is
- ** slightly faster, but it is also larger and much harder to test.
- */
- p++;
- b = b<<14;
- b |= *p;
- /* b: p1<<14 | p3 (unmasked) */
- if (!(b&0x80))
- {
- /* Values between 2097152 and 268435455 */
- b &= (0x7f<<14)|(0x7f);
- a &= (0x7f<<14)|(0x7f);
- a = a<<7;
- *v = a | b;
- return 4;
- }
-
- p++;
- a = a<<14;
- a |= *p;
- /* a: p0<<28 | p2<<14 | p4 (unmasked) */
- if (!(a&0x80))
- {
- /* Values between 268435456 and 34359738367 */
- a &= SLOT_4_2_0;
- b &= SLOT_4_2_0;
- b = b<<7;
- *v = a | b;
- return 5;
- }
-
- /* We can only reach this point when reading a corrupt database
- ** file. In that case we are not in any hurry. Use the (relatively
- ** slow) general-purpose sqlite3GetVarint() routine to extract the
- ** value. */
- {
- u64 v64;
- u8 n;
-
- p -= 4;
- n = sqlite3GetVarint(p, &v64);
- assert( n>5 && n<=9 );
+ /* four or more bytes */
+ n = sqlite3GetVarint(p, &v64);
+ assert( n>3 && n<=9 );
+ if( (v64 & SQLITE_MAX_U32)!=v64 ){
+ *v = 0xffffffff;
+ }else{
*v = (u32)v64;
- return n;
}
-#endif
+ return n;
}
/*
@@ -35639,7 +36539,7 @@ SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
}
/*
-** Attempt to add, substract, or multiply the 64-bit signed value iB against
+** Attempt to add, subtract, or multiply the 64-bit signed value iB against
** the other 64-bit signed integer at *pA and store the result in *pA.
** Return 0 on success. Or if the operation would have resulted in an
** overflow, leave *pA unchanged and return 1.
@@ -35952,7 +36852,7 @@ SQLITE_PRIVATE int sqlite3VListNameToNum(VList *pIn, const char *zName, int nNam
#define SQLITE_HWTIME_H
/*
-** The following routine only works on pentium-class (or newer) processors.
+** The following routine only works on Pentium-class (or newer) processors.
** It uses the RDTSC opcode to read the cycle count value out of the
** processor and returns that value. This can be used for high-res
** profiling.
@@ -36124,7 +37024,7 @@ static void insertElement(
}
-/* Resize the hash table so that it cantains "new_size" buckets.
+/* Resize the hash table so that it contains "new_size" buckets.
**
** The hash table might fail to resize if sqlite3_malloc() fails or
** if the new size is the same as the prior size.
@@ -36329,8 +37229,8 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 16 */ "If" OpHelp(""),
/* 17 */ "IfNot" OpHelp(""),
/* 18 */ "IsType" OpHelp("if typeof(P1.P3) in P5 goto P2"),
- /* 19 */ "Not" OpHelp("r[P2]= !r[P1]"),
- /* 20 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
+ /* 19 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
+ /* 20 */ "Not" OpHelp("r[P2]= !r[P1]"),
/* 21 */ "SeekLT" OpHelp("key=r[P3@P4]"),
/* 22 */ "SeekLE" OpHelp("key=r[P3@P4]"),
/* 23 */ "SeekGE" OpHelp("key=r[P3@P4]"),
@@ -36356,23 +37256,23 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 43 */ "IdxGE" OpHelp("key=r[P3@P4]"),
/* 44 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
/* 45 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
- /* 46 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
- /* 47 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
- /* 48 */ "Program" OpHelp(""),
+ /* 46 */ "Program" OpHelp(""),
+ /* 47 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
+ /* 48 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
/* 49 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
/* 50 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
/* 51 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
/* 52 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
- /* 53 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
- /* 54 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
- /* 55 */ "Ne" OpHelp("IF r[P3]!=r[P1]"),
- /* 56 */ "Eq" OpHelp("IF r[P3]==r[P1]"),
- /* 57 */ "Gt" OpHelp("IF r[P3]>r[P1]"),
- /* 58 */ "Le" OpHelp("IF r[P3]<=r[P1]"),
- /* 59 */ "Lt" OpHelp("IF r[P3]=r[P1]"),
- /* 61 */ "ElseEq" OpHelp(""),
- /* 62 */ "IncrVacuum" OpHelp(""),
+ /* 53 */ "IncrVacuum" OpHelp(""),
+ /* 54 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
+ /* 55 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
+ /* 56 */ "Ne" OpHelp("IF r[P3]!=r[P1]"),
+ /* 57 */ "Eq" OpHelp("IF r[P3]==r[P1]"),
+ /* 58 */ "Gt" OpHelp("IF r[P3]>r[P1]"),
+ /* 59 */ "Le" OpHelp("IF r[P3]<=r[P1]"),
+ /* 60 */ "Lt" OpHelp("IF r[P3]=r[P1]"),
+ /* 62 */ "ElseEq" OpHelp(""),
/* 63 */ "VNext" OpHelp(""),
/* 64 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"),
/* 65 */ "PureFunc" OpHelp("r[P3]=func(r[P2@NP])"),
@@ -36415,23 +37315,23 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 102 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
/* 103 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
/* 104 */ "OpenDup" OpHelp(""),
- /* 105 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
- /* 106 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
- /* 107 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"),
- /* 109 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"),
- /* 110 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"),
- /* 111 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
- /* 112 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
- /* 113 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
- /* 114 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
- /* 115 */ "OpenAutoindex" OpHelp("nColumn=P2"),
+ /* 105 */ "OpenAutoindex" OpHelp("nColumn=P2"),
+ /* 106 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
+ /* 107 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
+ /* 108 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"),
+ /* 110 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"),
+ /* 111 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"),
+ /* 112 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
+ /* 113 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
+ /* 114 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
+ /* 115 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
/* 116 */ "OpenEphemeral" OpHelp("nColumn=P2"),
- /* 117 */ "BitNot" OpHelp("r[P2]= ~r[P1]"),
- /* 118 */ "SorterOpen" OpHelp(""),
+ /* 117 */ "SorterOpen" OpHelp(""),
+ /* 118 */ "BitNot" OpHelp("r[P2]= ~r[P1]"),
/* 119 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
- /* 120 */ "String8" OpHelp("r[P2]='P4'"),
- /* 121 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
+ /* 120 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
+ /* 121 */ "String8" OpHelp("r[P2]='P4'"),
/* 122 */ "Close" OpHelp(""),
/* 123 */ "ColumnsUsed" OpHelp(""),
/* 124 */ "SeekScan" OpHelp("Scan-ahead up to P1 rows"),
@@ -36467,8 +37367,8 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 154 */ "DropIndex" OpHelp(""),
/* 155 */ "DropTrigger" OpHelp(""),
/* 156 */ "IntegrityCk" OpHelp(""),
- /* 157 */ "Real" OpHelp("r[P2]=P4"),
- /* 158 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
+ /* 157 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
+ /* 158 */ "Real" OpHelp("r[P2]=P4"),
/* 159 */ "Param" OpHelp(""),
/* 160 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
/* 161 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
@@ -36486,20 +37386,21 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 173 */ "VCreate" OpHelp(""),
/* 174 */ "VDestroy" OpHelp(""),
/* 175 */ "VOpen" OpHelp(""),
- /* 176 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"),
- /* 177 */ "VPreparedSql" OpHelp(""),
- /* 178 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
- /* 179 */ "VRename" OpHelp(""),
- /* 180 */ "Pagecount" OpHelp(""),
- /* 181 */ "MaxPgcnt" OpHelp(""),
- /* 182 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"),
- /* 183 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"),
- /* 184 */ "Trace" OpHelp(""),
- /* 185 */ "CursorHint" OpHelp(""),
- /* 186 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"),
- /* 187 */ "Noop" OpHelp(""),
- /* 188 */ "Explain" OpHelp(""),
- /* 189 */ "Abortable" OpHelp(""),
+ /* 176 */ "VCheck" OpHelp(""),
+ /* 177 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"),
+ /* 178 */ "VPreparedSql" OpHelp(""),
+ /* 179 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
+ /* 180 */ "VRename" OpHelp(""),
+ /* 181 */ "Pagecount" OpHelp(""),
+ /* 182 */ "MaxPgcnt" OpHelp(""),
+ /* 183 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"),
+ /* 184 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"),
+ /* 185 */ "Trace" OpHelp(""),
+ /* 186 */ "CursorHint" OpHelp(""),
+ /* 187 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"),
+ /* 188 */ "Noop" OpHelp(""),
+ /* 189 */ "Explain" OpHelp(""),
+ /* 190 */ "Abortable" OpHelp(""),
};
return azName[i];
}
@@ -37513,7 +38414,7 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){
** This source file is organized into divisions where the logic for various
** subfunctions is contained within the appropriate division. PLEASE
** KEEP THE STRUCTURE OF THIS FILE INTACT. New code should be placed
-** in the correct division and should be clearly labeled.
+** in the correct division and should be clearly labelled.
**
** The layout of divisions is as follows:
**
@@ -37563,7 +38464,7 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){
#endif
/* Use pread() and pwrite() if they are available */
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(__linux__)
# define HAVE_PREAD 1
# define HAVE_PWRITE 1
#endif
@@ -37586,7 +38487,7 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){
/* #include */
#include /* amalgamator: keep */
#include
-#if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \
+#if (!defined(SQLITE_OMIT_SHARED_MEM) || SQLITE_MAX_MMAP_SIZE>0) \
&& !defined(SQLITE_WASI)
# include
#endif
@@ -38026,7 +38927,7 @@ static struct unix_syscall {
#endif
#define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent)
-#if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \
+#if (!defined(SQLITE_OMIT_SHARED_MEM) || SQLITE_MAX_MMAP_SIZE>0) \
&& !defined(SQLITE_WASI)
{ "mmap", (sqlite3_syscall_ptr)mmap, 0 },
#else
@@ -38034,7 +38935,7 @@ static struct unix_syscall {
#endif
#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent)
-#if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \
+#if (!defined(SQLITE_OMIT_SHARED_MEM) || SQLITE_MAX_MMAP_SIZE>0) \
&& !defined(SQLITE_WASI)
{ "munmap", (sqlite3_syscall_ptr)munmap, 0 },
#else
@@ -38042,14 +38943,14 @@ static struct unix_syscall {
#endif
#define osMunmap ((int(*)(void*,size_t))aSyscall[23].pCurrent)
-#if HAVE_MREMAP && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
+#if HAVE_MREMAP && (!defined(SQLITE_OMIT_SHARED_MEM) || SQLITE_MAX_MMAP_SIZE>0)
{ "mremap", (sqlite3_syscall_ptr)mremap, 0 },
#else
{ "mremap", (sqlite3_syscall_ptr)0, 0 },
#endif
#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[24].pCurrent)
-#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
+#if !defined(SQLITE_OMIT_SHARED_MEM) || SQLITE_MAX_MMAP_SIZE>0
{ "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 },
#else
{ "getpagesize", (sqlite3_syscall_ptr)0, 0 },
@@ -38100,7 +39001,7 @@ static int robustFchown(int fd, uid_t uid, gid_t gid){
/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
-** "unix" VFSes. Return SQLITE_OK opon successfully updating the
+** "unix" VFSes. Return SQLITE_OK upon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
** system call named zName.
*/
@@ -38622,7 +39523,7 @@ static void vxworksReleaseFileId(struct vxworksFileId *pId){
** If you close a file descriptor that points to a file that has locks,
** all locks on that file that are owned by the current process are
** released. To work around this problem, each unixInodeInfo object
-** maintains a count of the number of pending locks on tha inode.
+** maintains a count of the number of pending locks on the inode.
** When an attempt is made to close an unixFile, if there are
** other unixFile open on the same inode that are holding locks, the call
** to close() the file descriptor is deferred until all of the locks clear.
@@ -38636,7 +39537,7 @@ static void vxworksReleaseFileId(struct vxworksFileId *pId){
** not posix compliant. Under LinuxThreads, a lock created by thread
** A cannot be modified or overridden by a different thread B.
** Only thread A can modify the lock. Locking behavior is correct
-** if the appliation uses the newer Native Posix Thread Library (NPTL)
+** if the application uses the newer Native Posix Thread Library (NPTL)
** on linux - with NPTL a lock created by thread A can override locks
** in thread B. But there is no way to know at compile-time which
** threading library is being used. So there is no way to know at
@@ -38838,7 +39739,7 @@ static void storeLastErrno(unixFile *pFile, int error){
}
/*
-** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
+** Close all file descriptors accumulated in the unixInodeInfo->pUnused list.
*/
static void closePendingFds(unixFile *pFile){
unixInodeInfo *pInode = pFile->pInode;
@@ -39201,7 +40102,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
** slightly in order to be compatible with Windows95 systems simultaneously
** accessing the same database file, in case that is ever required.
**
- ** Symbols defined in os.h indentify the 'pending byte' and the 'reserved
+ ** Symbols defined in os.h identify the 'pending byte' and the 'reserved
** byte', each single bytes at well known offsets, and the 'shared byte
** range', a range of 510 bytes at a well known offset.
**
@@ -39209,7 +40110,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
** byte'. If this is successful, 'shared byte range' is read-locked
** and the lock on the 'pending byte' released. (Legacy note: When
** SQLite was first developed, Windows95 systems were still very common,
- ** and Widnows95 lacks a shared-lock capability. So on Windows95, a
+ ** and Windows95 lacks a shared-lock capability. So on Windows95, a
** single randomly selected by from the 'shared byte range' is locked.
** Windows95 is now pretty much extinct, but this work-around for the
** lack of shared-locks on Windows95 lives on, for backwards
@@ -39230,7 +40131,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
** obtaining a write-lock on the 'pending byte'. This ensures that no new
** SHARED locks can be obtained, but existing SHARED locks are allowed to
** persist. If the call to this function fails to obtain the EXCLUSIVE
- ** lock in this case, it holds the PENDING lock intead. The client may
+ ** lock in this case, it holds the PENDING lock instead. The client may
** then re-attempt the EXCLUSIVE lock later on, after existing SHARED
** locks have cleared.
*/
@@ -39258,7 +40159,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
/* Make sure the locking sequence is correct.
** (1) We never move from unlocked to anything higher than shared lock.
- ** (2) SQLite never explicitly requests a pendig lock.
+ ** (2) SQLite never explicitly requests a pending lock.
** (3) A shared lock is always held when a reserve lock is requested.
*/
assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
@@ -40476,7 +41377,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){
/* Make sure the locking sequence is correct
** (1) We never move from unlocked to anything higher than shared lock.
- ** (2) SQLite never explicitly requests a pendig lock.
+ ** (2) SQLite never explicitly requests a pending lock.
** (3) A shared lock is always held when a reserve lock is requested.
*/
assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
@@ -40592,7 +41493,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){
if( !(failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST +
pInode->sharedByte, 1, 0)) ){
int failed2 = SQLITE_OK;
- /* now attemmpt to get the exclusive lock range */
+ /* now attempt to get the exclusive lock range */
failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST,
SHARED_SIZE, 1);
if( failed && (failed2 = afpSetLock(context->dbPath, pFile,
@@ -40641,9 +41542,6 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
unixInodeInfo *pInode;
afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
int skipShared = 0;
-#ifdef SQLITE_TEST
- int h = pFile->h;
-#endif
assert( pFile );
OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (afp)\n", pFile->h, eFileLock,
@@ -40659,9 +41557,6 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
assert( pInode->nShared!=0 );
if( pFile->eFileLock>SHARED_LOCK ){
assert( pInode->eFileLock==pFile->eFileLock );
- SimulateIOErrorBenign(1);
- SimulateIOError( h=(-1) )
- SimulateIOErrorBenign(0);
#ifdef SQLITE_DEBUG
/* When reducing a lock such that other processes can start
@@ -40710,9 +41605,6 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
unsigned long long sharedLockByte = SHARED_FIRST+pInode->sharedByte;
pInode->nShared--;
if( pInode->nShared==0 ){
- SimulateIOErrorBenign(1);
- SimulateIOError( h=(-1) )
- SimulateIOErrorBenign(0);
if( !skipShared ){
rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 0);
}
@@ -40813,12 +41705,6 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){
** Seek to the offset passed as the second argument, then read cnt
** bytes into pBuf. Return the number of bytes actually read.
**
-** NB: If you define USE_PREAD or USE_PREAD64, then it might also
-** be necessary to define _XOPEN_SOURCE to be 500. This varies from
-** one system to another. Since SQLite does not define USE_PREAD
-** in any form by default, we will not attempt to define _XOPEN_SOURCE.
-** See tickets #2741 and #2681.
-**
** To avoid stomping the errno value on a failed read the lastErrno value
** is set before returning.
*/
@@ -40893,7 +41779,7 @@ static int unixRead(
#endif
#if SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this read request as possible by transfering
+ /* Deal with as much of this read request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offsetmmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -41045,7 +41931,7 @@ static int unixWrite(
#endif
#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this write request as possible by transfering
+ /* Deal with as much of this write request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offsetmmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -41167,7 +42053,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
/* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
** no-op. But go ahead and call fstat() to validate the file
** descriptor as we need a method to provoke a failure during
- ** coverate testing.
+ ** coverage testing.
*/
#ifdef SQLITE_NO_SYNC
{
@@ -41489,7 +42375,7 @@ static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){
/* Forward declaration */
static int unixGetTempname(int nBuf, char *zBuf);
-#ifndef SQLITE_OMIT_WAL
+#ifndef SQLITE_OMIT_SHARED_MEM
static int unixFcntlExternalReader(unixFile*, int*);
#endif
@@ -41610,7 +42496,7 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
case SQLITE_FCNTL_EXTERNAL_READER: {
-#ifndef SQLITE_OMIT_WAL
+#ifndef SQLITE_OMIT_SHARED_MEM
return unixFcntlExternalReader((unixFile*)id, (int*)pArg);
#else
*(int*)pArg = 0;
@@ -41763,7 +42649,7 @@ static int unixDeviceCharacteristics(sqlite3_file *id){
return pFd->deviceCharacteristics;
}
-#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
+#if !defined(SQLITE_OMIT_SHARED_MEM) || SQLITE_MAX_MMAP_SIZE>0
/*
** Return the system page size.
@@ -41781,9 +42667,9 @@ static int unixGetpagesize(void){
#endif
}
-#endif /* !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 */
+#endif /* !defined(SQLITE_OMIT_SHARED_MEM) || SQLITE_MAX_MMAP_SIZE>0 */
-#ifndef SQLITE_OMIT_WAL
+#ifndef SQLITE_OMIT_SHARED_MEM
/*
** Object used to represent an shared memory buffer.
@@ -42649,7 +43535,7 @@ static int unixShmUnmap(
# define unixShmLock 0
# define unixShmBarrier 0
# define unixShmUnmap 0
-#endif /* #ifndef SQLITE_OMIT_WAL */
+#endif /* #ifndef SQLITE_OMIT_SHARED_MEM */
#if SQLITE_MAX_MMAP_SIZE>0
/*
@@ -44212,12 +45098,17 @@ static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
** than the argument.
*/
static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){
-#if OS_VXWORKS || _POSIX_C_SOURCE >= 199309L
+#if !defined(HAVE_NANOSLEEP) || HAVE_NANOSLEEP+0
struct timespec sp;
-
sp.tv_sec = microseconds / 1000000;
sp.tv_nsec = (microseconds % 1000000) * 1000;
+
+ /* Almost all modern unix systems support nanosleep(). But if you are
+ ** compiling for one of the rare exceptions, you can use
+ ** -DHAVE_NANOSLEEP=0 (perhaps in conjuction with -DHAVE_USLEEP if
+ ** usleep() is available) in order to bypass the use of nanosleep() */
nanosleep(&sp, NULL);
+
UNUSED_PARAMETER(NotUsed);
return microseconds;
#elif defined(HAVE_USLEEP) && HAVE_USLEEP
@@ -45606,7 +46497,7 @@ SQLITE_API int sqlite3_os_init(void){
#endif
unixBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
-#ifndef SQLITE_OMIT_WAL
+#ifndef SQLITE_OMIT_SHARED_MEM
/* Validate lock assumptions */
assert( SQLITE_SHM_NLOCK==8 ); /* Number of available locks */
assert( UNIX_SHM_BASE==120 ); /* Start of locking area */
@@ -45677,9 +46568,9 @@ SQLITE_API int sqlite3_os_end(void){
** Compiling and using WAL mode requires several APIs that are only
** available in Windows platforms based on the NT kernel.
*/
-#if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_WAL)
+#if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_SHARED_MEM)
# error "WAL mode requires support from the Windows NT kernel, compile\
- with SQLITE_OMIT_WAL."
+ with SQLITE_OMIT_SHARED_MEM."
#endif
#if !SQLITE_OS_WINNT && SQLITE_MAX_MMAP_SIZE>0
@@ -45837,7 +46728,7 @@ SQLITE_API int sqlite3_os_end(void){
** CE SDK; however, they are not present in the header file)?
*/
#if SQLITE_WIN32_FILEMAPPING_API && \
- (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
+ (!defined(SQLITE_OMIT_SHARED_MEM) || SQLITE_MAX_MMAP_SIZE>0)
/*
** Two of the file mapping APIs are different under WinRT. Figure out which
** set we need.
@@ -45884,7 +46775,7 @@ WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID);
# define FILE_ATTRIBUTE_MASK (0x0003FFF7)
#endif
-#ifndef SQLITE_OMIT_WAL
+#ifndef SQLITE_OMIT_SHARED_MEM
/* Forward references to structures used for WAL */
typedef struct winShm winShm; /* A connection to shared-memory */
typedef struct winShmNode winShmNode; /* A region of shared-memory */
@@ -45916,7 +46807,7 @@ struct winFile {
short sharedLockByte; /* Randomly chosen byte used as a shared lock */
u8 ctrlFlags; /* Flags. See WINFILE_* below */
DWORD lastErrno; /* The Windows errno from the last I/O error */
-#ifndef SQLITE_OMIT_WAL
+#ifndef SQLITE_OMIT_SHARED_MEM
winShm *pShm; /* Instance of shared memory on this file */
#endif
const char *zPath; /* Full pathname of this file */
@@ -46204,7 +47095,7 @@ static struct win_syscall {
LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent)
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \
- (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) && \
+ (!defined(SQLITE_OMIT_SHARED_MEM) || SQLITE_MAX_MMAP_SIZE>0) && \
SQLITE_WIN32_CREATEFILEMAPPINGA
{ "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 },
#else
@@ -46215,7 +47106,7 @@ static struct win_syscall {
DWORD,DWORD,DWORD,LPCSTR))aSyscall[6].pCurrent)
#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
- (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
+ (!defined(SQLITE_OMIT_SHARED_MEM) || SQLITE_MAX_MMAP_SIZE>0))
{ "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 },
#else
{ "CreateFileMappingW", (SYSCALL)0, 0 },
@@ -46555,7 +47446,7 @@ static struct win_syscall {
#endif
#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && \
- (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
+ (!defined(SQLITE_OMIT_SHARED_MEM) || SQLITE_MAX_MMAP_SIZE>0))
{ "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 },
#else
{ "MapViewOfFile", (SYSCALL)0, 0 },
@@ -46625,7 +47516,7 @@ static struct win_syscall {
#define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
LPOVERLAPPED))aSyscall[58].pCurrent)
-#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
+#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_SHARED_MEM) || SQLITE_MAX_MMAP_SIZE>0
{ "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 },
#else
{ "UnmapViewOfFile", (SYSCALL)0, 0 },
@@ -46688,7 +47579,7 @@ static struct win_syscall {
#define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \
FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[66].pCurrent)
-#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
+#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_SHARED_MEM) || SQLITE_MAX_MMAP_SIZE>0)
{ "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 },
#else
{ "MapViewOfFileFromApp", (SYSCALL)0, 0 },
@@ -46752,7 +47643,7 @@ static struct win_syscall {
#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[74].pCurrent)
-#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
+#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_SHARED_MEM) || SQLITE_MAX_MMAP_SIZE>0)
{ "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 },
#else
{ "CreateFileMappingFromApp", (SYSCALL)0, 0 },
@@ -46807,7 +47698,7 @@ static struct win_syscall {
/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
-** "win32" VFSes. Return SQLITE_OK opon successfully updating the
+** "win32" VFSes. Return SQLITE_OK upon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
** system call named zName.
*/
@@ -48314,7 +49205,7 @@ static int winClose(sqlite3_file *id){
winFile *pFile = (winFile*)id;
assert( id!=0 );
-#ifndef SQLITE_OMIT_WAL
+#ifndef SQLITE_OMIT_SHARED_MEM
assert( pFile->pShm==0 );
#endif
assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE );
@@ -48387,7 +49278,7 @@ static int winRead(
pFile->h, pBuf, amt, offset, pFile->locktype));
#if SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this read request as possible by transfering
+ /* Deal with as much of this read request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offsetmmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -48465,7 +49356,7 @@ static int winWrite(
pFile->h, pBuf, amt, offset, pFile->locktype));
#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this write request as possible by transfering
+ /* Deal with as much of this write request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offsetmmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -48575,7 +49466,7 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
** all references to memory-mapped content are closed. That is doable,
** but involves adding a few branches in the common write code path which
** could slow down normal operations slightly. Hence, we have decided for
- ** now to simply make trancations a no-op if there are pending reads. We
+ ** now to simply make transactions a no-op if there are pending reads. We
** can maybe revisit this decision in the future.
*/
return SQLITE_OK;
@@ -48634,7 +49525,7 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
#ifdef SQLITE_TEST
/*
** Count the number of fullsyncs and normal syncs. This is used to test
-** that syncs and fullsyncs are occuring at the right times.
+** that syncs and fullsyncs are occurring at the right times.
*/
SQLITE_API int sqlite3_sync_count = 0;
SQLITE_API int sqlite3_fullsync_count = 0;
@@ -48991,7 +49882,7 @@ static int winLock(sqlite3_file *id, int locktype){
*/
if( locktype==EXCLUSIVE_LOCK && res ){
assert( pFile->locktype>=SHARED_LOCK );
- res = winUnlockReadLock(pFile);
+ (void)winUnlockReadLock(pFile);
res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0,
SHARED_SIZE, 0);
if( res ){
@@ -49320,7 +50211,7 @@ static int winDeviceCharacteristics(sqlite3_file *id){
*/
static SYSTEM_INFO winSysInfo;
-#ifndef SQLITE_OMIT_WAL
+#ifndef SQLITE_OMIT_SHARED_MEM
/*
** Helper functions to obtain and relinquish the global mutex. The
@@ -50005,7 +50896,7 @@ static int winShmMap(
# define winShmLock 0
# define winShmBarrier 0
# define winShmUnmap 0
-#endif /* #ifndef SQLITE_OMIT_WAL */
+#endif /* #ifndef SQLITE_OMIT_SHARED_MEM */
/*
** Cleans up the mapped region of the specified file, if any.
@@ -50395,6 +51286,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
size_t i, j;
+ DWORD pid;
int nPre = sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX);
int nMax, nBuf, nDir, nLen;
char *zBuf;
@@ -50607,7 +51499,10 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
j = sqlite3Strlen30(zBuf);
sqlite3_randomness(15, &zBuf[j]);
+ pid = osGetCurrentProcessId();
for(i=0; i<15; i++, j++){
+ zBuf[j] += pid & 0xff;
+ pid >>= 8;
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
@@ -50845,7 +51740,7 @@ static int winOpen(
if( isReadWrite ){
int rc2, isRO = 0;
sqlite3BeginBenignMalloc();
- rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@@ -50862,7 +51757,7 @@ static int winOpen(
if( isReadWrite ){
int rc2, isRO = 0;
sqlite3BeginBenignMalloc();
- rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@@ -50882,7 +51777,7 @@ static int winOpen(
if( isReadWrite ){
int rc2, isRO = 0;
sqlite3BeginBenignMalloc();
- rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@@ -51105,6 +52000,13 @@ static int winAccess(
OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n",
zFilename, flags, pResOut));
+ if( zFilename==0 ){
+ *pResOut = 0;
+ OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
+ zFilename, pResOut, *pResOut));
+ return SQLITE_OK;
+ }
+
zConverted = winConvertFromUtf8Filename(zFilename);
if( zConverted==0 ){
OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
@@ -51818,7 +52720,7 @@ SQLITE_API int sqlite3_os_init(void){
sqlite3_vfs_register(&winLongPathNolockVfs, 0);
#endif
-#ifndef SQLITE_OMIT_WAL
+#ifndef SQLITE_OMIT_SHARED_MEM
winBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
#endif
@@ -51833,7 +52735,7 @@ SQLITE_API int sqlite3_os_end(void){
}
#endif
-#ifndef SQLITE_OMIT_WAL
+#ifndef SQLITE_OMIT_SHARED_MEM
winBigLock = 0;
#endif
@@ -52866,7 +53768,7 @@ SQLITE_PRIVATE int sqlite3MemdbInit(void){
** values between 1 and iDivisor. apSub[1] holds values between
** iDivisor+1 and 2*iDivisor. apSub[N] holds values between
** N*iDivisor+1 and (N+1)*iDivisor. Each subbitmap is normalized
-** to hold deal with values between 1 and iDivisor.
+** to deal with values between 1 and iDivisor.
*/
struct Bitvec {
u32 iSize; /* Maximum bit index. Max iSize is 4,294,967,296. */
@@ -52965,7 +53867,7 @@ SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec *p, u32 i){
h = BITVEC_HASH(i++);
/* if there wasn't a hash collision, and this doesn't */
/* completely fill the hash, then just add it without */
- /* worring about sub-dividing and re-hashing. */
+ /* worrying about sub-dividing and re-hashing. */
if( !p->u.aHash[h] ){
if (p->nSet<(BITVEC_NINT-1)) {
goto bitvec_set_end;
@@ -53232,7 +54134,7 @@ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){
struct PCache {
PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
PgHdr *pSynced; /* Last synced page in dirty page list */
- int nRefSum; /* Sum of ref counts over all pages */
+ i64 nRefSum; /* Sum of ref counts over all pages */
int szCache; /* Configured cache size */
int szSpill; /* Size before spilling occurs */
int szPage; /* Size of every page in this cache */
@@ -53261,11 +54163,15 @@ struct PCache {
PgHdr *pPg;
unsigned char *a;
int j;
- pPg = (PgHdr*)pLower->pExtra;
- printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
- a = (unsigned char *)pLower->pBuf;
- for(j=0; j<12; j++) printf("%02x", a[j]);
- printf(" ptr %p\n", pPg);
+ if( pLower==0 ){
+ printf("%3d: NULL\n", i);
+ }else{
+ pPg = (PgHdr*)pLower->pExtra;
+ printf("%3d: nRef %2lld flgs %02x data ", i, pPg->nRef, pPg->flags);
+ a = (unsigned char *)pLower->pBuf;
+ for(j=0; j<12; j++) printf("%02x", a[j]);
+ printf(" ptr %p\n", pPg);
+ }
}
static void pcacheDump(PCache *pCache){
int N;
@@ -53278,9 +54184,8 @@ struct PCache {
if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump;
for(i=1; i<=N; i++){
pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0);
- if( pLower==0 ) continue;
pcachePageTrace(i, pLower);
- if( ((PgHdr*)pLower)->pPage==0 ){
+ if( pLower && ((PgHdr*)pLower)->pPage==0 ){
sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0);
}
}
@@ -53295,7 +54200,7 @@ struct PCache {
** Return 1 if pPg is on the dirty list for pCache. Return 0 if not.
** This routine runs inside of assert() statements only.
*/
-#ifdef SQLITE_DEBUG
+#if defined(SQLITE_ENABLE_EXPENSIVE_ASSERT)
static int pageOnDirtyList(PCache *pCache, PgHdr *pPg){
PgHdr *p;
for(p=pCache->pDirty; p; p=p->pDirtyNext){
@@ -53303,6 +54208,16 @@ static int pageOnDirtyList(PCache *pCache, PgHdr *pPg){
}
return 0;
}
+static int pageNotOnDirtyList(PCache *pCache, PgHdr *pPg){
+ PgHdr *p;
+ for(p=pCache->pDirty; p; p=p->pDirtyNext){
+ if( p==pPg ) return 0;
+ }
+ return 1;
+}
+#else
+# define pageOnDirtyList(A,B) 1
+# define pageNotOnDirtyList(A,B) 1
#endif
/*
@@ -53323,7 +54238,7 @@ SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr *pPg){
assert( pCache!=0 ); /* Every page has an associated PCache */
if( pPg->flags & PGHDR_CLEAN ){
assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */
- assert( !pageOnDirtyList(pCache, pPg) );/* CLEAN pages not on dirty list */
+ assert( pageNotOnDirtyList(pCache, pPg) );/* CLEAN pages not on dirtylist */
}else{
assert( (pPg->flags & PGHDR_DIRTY)!=0 );/* If not CLEAN must be DIRTY */
assert( pPg->pDirtyNext==0 || pPg->pDirtyNext->pDirtyPrev==pPg );
@@ -53459,7 +54374,7 @@ static int numberOfCachePages(PCache *p){
return p->szCache;
}else{
i64 n;
- /* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the
+ /* IMPLEMENTATION-OF: R-59858-46238 If the argument N is negative, then the
** number of cache pages is adjusted to be a number of pages that would
** use approximately abs(N*1024) bytes of memory based on the current
** page size. */
@@ -53947,7 +54862,7 @@ static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
}
/*
-** Sort the list of pages in accending order by pgno. Pages are
+** Sort the list of pages in ascending order by pgno. Pages are
** connected by pDirty pointers. The pDirtyPrev pointers are
** corrupted by this sort.
**
@@ -54006,14 +54921,14 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
** This is not the total number of pages referenced, but the sum of the
** reference count for all pages.
*/
-SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache *pCache){
+SQLITE_PRIVATE i64 sqlite3PcacheRefCount(PCache *pCache){
return pCache->nRefSum;
}
/*
** Return the number of references to the page supplied as an argument.
*/
-SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){
+SQLITE_PRIVATE i64 sqlite3PcachePageRefcount(PgHdr *p){
return p->nRef;
}
@@ -54187,7 +55102,7 @@ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHd
** If N is positive, then N pages worth of memory are allocated using a single
** sqlite3Malloc() call and that memory is used for the first N pages allocated.
** Or if N is negative, then -1024*N bytes of memory are allocated and used
-** for as many pages as can be accomodated.
+** for as many pages as can be accommodated.
**
** Only one of (2) or (3) can be used. Once the memory available to (2) or
** (3) is exhausted, subsequent allocations fail over to the general-purpose
@@ -54221,7 +55136,7 @@ typedef struct PGroup PGroup;
** in memory directly after the associated page data, if the database is
** corrupt, code at the b-tree layer may overread the page buffer and
** read part of this structure before the corruption is detected. This
-** can cause a valgrind error if the unitialized gap is accessed. Using u16
+** can cause a valgrind error if the uninitialized gap is accessed. Using u16
** ensures there is no such gap, and therefore no bytes of uninitialized
** memory in the structure.
**
@@ -55441,7 +56356,7 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
** The TEST primitive includes a "batch" number. The TEST primitive
** will only see elements that were inserted before the last change
** in the batch number. In other words, if an INSERT occurs between
-** two TESTs where the TESTs have the same batch nubmer, then the
+** two TESTs where the TESTs have the same batch number, then the
** value added by the INSERT will not be visible to the second TEST.
** The initial batch number is zero, so if the very first TEST contains
** a non-zero batch number, it will see all prior INSERTs.
@@ -55960,15 +56875,16 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
** There is one object of this type for each pager.
*/
typedef struct libsql_wal libsql_wal;
+typedef struct libsql_wal_manager libsql_wal_manager;
+/* Opaque types for wal method data */
+typedef struct wal_impl wal_impl;
+typedef struct wal_manager_impl wal_manager_impl;
typedef struct libsql_wal_methods {
int iVersion; /* Current version is 1, versioning is here for backward compatibility */
- /* Open and close a connection to a write-ahead log. */
- int (*xOpen)(sqlite3_vfs*, sqlite3_file* , const char*, int no_shm_mode, long long max_size, struct libsql_wal_methods*, libsql_wal**);
- int (*xClose)(libsql_wal*, sqlite3* db, int sync_flags, int nBuf, unsigned char *zBuf);
/* Set the limiting size of a WAL file. */
- void (*xLimit)(libsql_wal*, long long limit);
+ void (*xLimit)(wal_impl* pWal, long long limit);
/* Used by readers to open (lock) and close (unlock) a snapshot. A
** snapshot is like a read-transaction. It is the state of the database
@@ -55977,37 +56893,37 @@ typedef struct libsql_wal_methods {
** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the
** transaction and releases the lock.
*/
- int (*xBeginReadTransaction)(libsql_wal *, int *);
- void (*xEndReadTransaction)(libsql_wal *);
+ int (*xBeginReadTransaction)(wal_impl* pWal, int *);
+ void (*xEndReadTransaction)(wal_impl *);
/* Read a page from the write-ahead log, if it is present. */
- int (*xFindFrame)(libsql_wal *, unsigned int, unsigned int *);
- int (*xReadFrame)(libsql_wal *, unsigned int, int, unsigned char *);
+ int (*xFindFrame)(wal_impl* pWal, unsigned int, unsigned int *);
+ int (*xReadFrame)(wal_impl* pWal, unsigned int, int, unsigned char *);
/* If the WAL is not empty, return the size of the database. */
- unsigned int (*xDbsize)(libsql_wal *pWal);
+ unsigned int (*xDbsize)(wal_impl* pWal);
/* Obtain or release the WRITER lock. */
- int (*xBeginWriteTransaction)(libsql_wal *pWal);
- int (*xEndWriteTransaction)(libsql_wal *pWal);
+ int (*xBeginWriteTransaction)(wal_impl* pWal);
+ int (*xEndWriteTransaction)(wal_impl* pWal);
/* Undo any frames written (but not committed) to the log */
- int (*xUndo)(libsql_wal *pWal, int (*xUndo)(void *, unsigned int), void *pUndoCtx);
+ int (*xUndo)(wal_impl* pWal, int (*xUndo)(void *, unsigned int), void *pUndoCtx);
/* Return an integer that records the current (uncommitted) write
** position in the WAL */
- void (*xSavepoint)(libsql_wal *pWal, unsigned int *aWalData);
+ void (*xSavepoint)(wal_impl* pWal, unsigned int *aWalData);
/* Move the write position of the WAL back to iFrame. Called in
** response to a ROLLBACK TO command. */
- int (*xSavepointUndo)(libsql_wal *pWal, unsigned int *aWalData);
+ int (*xSavepointUndo)(wal_impl* pWal, unsigned int *aWalData);
/* Write a frame or frames to the log. */
- int (*xFrames)(libsql_wal *pWal, int, libsql_pghdr *, unsigned int, int, int);
+ int (*xFrames)(wal_impl* pWal, int, libsql_pghdr *, unsigned int, int, int, int*);
/* Copy pages from the log to the database file */
int (*xCheckpoint)(
- libsql_wal *pWal, /* Write-ahead log connection */
+ wal_impl* pWal, /* Write-ahead log connection */
sqlite3 *db, /* Check this handle's interrupt flag */
int eMode, /* One of PASSIVE, FULL and RESTART */
int (*xBusy)(void*), /* Function to call when busy */
@@ -56016,7 +56932,12 @@ typedef struct libsql_wal_methods {
int nBuf, /* Size of buffer nBuf */
unsigned char *zBuf, /* Temporary buffer to use */
int *pnLog, /* OUT: Number of frames in WAL */
- int *pnCkpt /* OUT: Number of backfilled frames in WAL */
+ int *pnCkpt, /* OUT: Number of backfilled frames in WAL */
+ /*
+ * Called for each page being inserted in the wal, and once if the whole checkpoint operation was successfull with pPage == NULL
+ */
+ int (*xCb)(void* pCbData, int mxSafeFrame, const unsigned char* pPage, int nPage, int page_no, int frame_no), /* called */
+ void* pCbData /* user data passed to xCb */
);
/* Return the value to pass to a sqlite3_wal_hook callback, the
@@ -56024,66 +56945,42 @@ typedef struct libsql_wal_methods {
** sqlite3WalCallback() was called. If no commits have occurred since
** the last call, then return 0.
*/
- int (*xCallback)(libsql_wal *pWal);
+ int (*xCallback)(wal_impl* pWal);
/* Tell the wal layer that an EXCLUSIVE lock has been obtained (or released)
** by the pager layer on the database file.
*/
- int (*xExclusiveMode)(libsql_wal *pWal, int op);
+ int (*xExclusiveMode)(wal_impl* pWal, int op);
/* Return true if the argument is non-NULL and the WAL module is using
** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
** WAL module is using shared-memory, return false.
*/
- int (*xHeapMemory)(libsql_wal *pWal);
+ int (*xHeapMemory)(wal_impl* pWal);
// Only needed with SQLITE_ENABLE_SNAPSHOT, but part of the ABI
- int (*xSnapshotGet)(libsql_wal *pWal, sqlite3_snapshot **ppSnapshot);
- void (*xSnapshotOpen)(libsql_wal *pWal, sqlite3_snapshot *pSnapshot);
- int (*xSnapshotRecover)(libsql_wal *pWal);
- int (*xSnapshotCheck)(libsql_wal *pWal, sqlite3_snapshot *pSnapshot);
- void (*xSnapshotUnlock)(libsql_wal *pWal);
+ int (*xSnapshotGet)(wal_impl* pWal, sqlite3_snapshot **ppSnapshot);
+ void (*xSnapshotOpen)(wal_impl* pWal, sqlite3_snapshot *pSnapshot);
+ int (*xSnapshotRecover)(wal_impl* pWal);
+ int (*xSnapshotCheck)(void* pWal, sqlite3_snapshot *pSnapshot);
+ void (*xSnapshotUnlock)(wal_impl* pWal);
// Only needed with SQLITE_ENABLE_ZIPVFS, but part of the ABI
/* If the WAL file is not empty, return the number of bytes of content
** stored in each frame (i.e. the db page-size when the WAL was created).
*/
- int (*xFramesize)(libsql_wal *pWal);
+ int (*xFramesize)(wal_impl* pWal);
/* Return the sqlite3_file object for the WAL file */
- sqlite3_file *(*xFile)(libsql_wal *pWal);
+ sqlite3_file *(*xFile)(wal_impl* pWal);
// Only needed with SQLITE_ENABLE_SETLK_TIMEOUT
- int (*xWriteLock)(libsql_wal *pWal, int bLock);
-
- void (*xDb)(libsql_wal *pWal, sqlite3 *db);
+ int (*xWriteLock)(wal_impl* pWal, int bLock);
- /* Return the WAL pathname length based on the owning pager's pathname len.
- ** For WAL implementations not based on a single file, 0 should be returned. */
- int (*xPathnameLen)(int origPathname);
-
- /* Get the WAL pathname to given buffer. Assumes that the buffer can hold
- ** at least xPathnameLen bytes. For WAL implementations not based on a single file,
- ** this operation can safely be a no-op.
- ** */
- void (*xGetWalPathname)(char *buf, const char *orig, int orig_len);
-
- /*
- ** This optional callback gets called before the main database file which owns
- ** the WAL file is open. It is a good place for initialization routines, as WAL
- ** is otherwise open lazily.
- */
- int (*xPreMainDbOpen)(libsql_wal_methods *methods, const char *main_db_path);
-
- /* True if the implementation relies on shared memory routines (e.g. locks) */
- int bUsesShm;
-
- const char *zName;
- struct libsql_wal_methods *pNext;
+ void (*xDb)(wal_impl* pWal, sqlite3 *db);
} libsql_wal_methods;
-libsql_wal_methods* libsql_wal_methods_find(const char *zName);
/* Object declarations */
typedef struct WalIndexHdr WalIndexHdr;
@@ -56118,11 +57015,29 @@ struct WalIndexHdr {
unsigned int aCksum[2]; /* Checksum over all prior fields */
};
+struct libsql_wal_manager {
+ /* True if the implementation relies on shared memory routines (e.g. locks) */
+ int bUsesShm;
+
+ /* Open and close a connection to a write-ahead log. */
+ int (*xOpen)(wal_manager_impl* pData, sqlite3_vfs*, sqlite3_file*, int no_shm_mode, long long max_size, const char* zMainDbFileName, libsql_wal* out_wal);
+ int (*xClose)(wal_manager_impl* pData, wal_impl* pWal, sqlite3* db, int sync_flags, int nBuf, unsigned char *zBuf);
+
+ /* destroy resources for this wal */
+ int (*xLogDestroy)(wal_manager_impl* pData, sqlite3_vfs *vfs, const char* zMainDbFileName);
+ /* returns whether this wal exists */
+ int (*xLogExists)(wal_manager_impl* pData, sqlite3_vfs *vfs, const char* zMainDbFileName, int* exist);
+ /* destructor */
+ void (*xDestroy)(wal_manager_impl* pData);
+
+ wal_manager_impl* pData;
+};
+
/*
** An open write-ahead log file is represented by an instance of the
** following object.
*/
-struct libsql_wal {
+typedef struct sqlite3_wal {
sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */
sqlite3_file *pDbFd; /* File handle for the database file */
sqlite3_file *pWalFd; /* File handle for WAL file */
@@ -56150,11 +57065,29 @@ struct libsql_wal {
unsigned char lockError; /* True if a locking error has occurred */
WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
sqlite3 *db;
- libsql_wal_methods *pMethods; /* Virtual methods for interacting with WAL */
- void *pMethodsData; /* Optional context for private use of libsql_wal_methods */
+} sqlite3_wal;
+
+struct libsql_wal {
+ libsql_wal_methods methods; /* virtual wal methods */
+ wal_impl* pData; /* methods receiver */
};
-typedef struct libsql_wal libsql_wal;
+typedef struct RefCountedWalManager {
+ int n;
+ libsql_wal_manager ref;
+ int is_static;
+} RefCountedWalManager;
+
+int make_ref_counted_wal_manager(libsql_wal_manager wal_manager, RefCountedWalManager **out);
+void destroy_wal_manager(RefCountedWalManager *p);
+RefCountedWalManager* clone_wal_manager(RefCountedWalManager *p);
+
+SQLITE_API int sqlite3_wal_backfilled(sqlite3_wal* pWal);
+SQLITE_API unsigned int sqlite3_wal_frame_page_no(sqlite3_wal *pWal, unsigned int iFrame);
+
+RefCountedWalManager *make_sqlite3_wal_manager_rc();
+
+SQLITE_API extern const libsql_wal_manager sqlite3_wal_manager;
#endif /* SQLITE_WAL_H */
@@ -56440,7 +57373,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** outstanding transactions have been abandoned, the pager is able to
** transition back to OPEN state, discarding the contents of the
** page-cache and any other in-memory state at the same time. Everything
-** is reloaded from disk (and, if necessary, hot-journal rollback peformed)
+** is reloaded from disk (and, if necessary, hot-journal rollback performed)
** when a read-transaction is next opened on the pager (transitioning
** the pager into READER state). At that point the system has recovered
** from the error.
@@ -56553,7 +57486,6 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
*/
#define MAX_SECTOR_SIZE 0x10000
-
/*
** An instance of the following structure is allocated for each active
** savepoint and statement transaction in the system. All such structures
@@ -56836,12 +57768,45 @@ struct Pager {
char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */
PCache *pPCache; /* Pointer to page cache object */
#ifndef SQLITE_OMIT_WAL
- libsql_wal *pWal; /* Write-ahead log used by "journal_mode=wal" */
- libsql_wal_methods *pWalMethods; /* Virtual methods for interacting with WAL */
- char *zWal; /* File name for write-ahead log */
+ RefCountedWalManager* wal_manager;
+ libsql_wal *wal;
+ char *zWal; /* Name of the WAL file:
+ FIXME: to remove, and be handled by virtual WAL.
+ We leave it temporarily to keep sqlite3_filename_wal working
+ */
#endif
};
+
+/* libSQL extension: pager codec */
+
+#ifdef LIBSQL_CUSTOM_PAGER_CODEC
+int libsql_pager_has_codec_impl(struct Pager *_p);
+int libsql_pager_codec_impl(libsql_pghdr *hdr, void **ret);
+#endif
+
+int libsql_pager_has_codec(struct Pager *_p) {
+#ifdef LIBSQL_CUSTOM_PAGER_CODEC
+ return libsql_pager_has_codec_impl(_p);
+#else
+ return 0;
+#endif
+}
+
+int libsql_pager_codec(libsql_pghdr *hdr, void **ret) {
+ if (!ret) {
+ return SQLITE_MISUSE_BKPT;
+ }
+#ifdef LIBSQL_CUSTOM_PAGER_CODEC
+ return libsql_pager_codec_impl(hdr, ret);
+#else
+ *ret = hdr->pData;
+ return SQLITE_OK;
+#endif
+}
+/* end of libSQL extension: pager codec */
+
+
/*
** Indexes for use with Pager.aStat[]. The Pager.aStat[] array contains
** the values accessed by passing SQLITE_DBSTATUS_CACHE_HIT, CACHE_MISS
@@ -56955,11 +57920,12 @@ static const unsigned char aJournalMagic[] = {
SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
if( pPager->fd->pMethods==0 ) return 0;
if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0;
+ if( libsql_pager_has_codec(pPager) != 0 ) return 0;
#ifndef SQLITE_OMIT_WAL
- if( pPager->pWal ){
+ if( pagerUseWal(pPager) ){
u32 iRead = 0;
int rc;
- rc = pPager->pWalMethods->xFindFrame(pPager->pWal, pgno, &iRead);
+ rc = pPager->wal.xFindFrame(pPager->wal.pData, pgno, &iRead);
return (rc==SQLITE_OK && iRead==0);
}
#endif
@@ -56968,7 +57934,7 @@ SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
#endif
#ifndef SQLITE_OMIT_WAL
-# define pagerUseWal(x) ((x)->pWal!=0)
+# define pagerUseWal(x) ((x)->wal!=0) // check that methods have been initialized
#else
# define pagerUseWal(x) 0
# define pagerRollbackWal(x) 0
@@ -57188,7 +58154,7 @@ static void setGetterMethod(Pager *pPager){
if( pPager->errCode ){
pPager->xGet = getPageError;
#if SQLITE_MAX_MMAP_SIZE>0
- }else if( USEFETCH(pPager) ){
+ }else if( USEFETCH(pPager) && libsql_pager_has_codec(pPager) == 0 ){
pPager->xGet = getPageMMap;
#endif /* SQLITE_MAX_MMAP_SIZE>0 */
}else{
@@ -57632,9 +58598,32 @@ static int writeJournalHdr(Pager *pPager){
memset(zHeader, 0, sizeof(aJournalMagic)+4);
}
+
+
/* The random check-hash initializer */
- sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
+ if( pPager->journalMode!=PAGER_JOURNALMODE_MEMORY ){
+ sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
+ }
+#ifdef SQLITE_DEBUG
+ else{
+ /* The Pager.cksumInit variable is usually randomized above to protect
+ ** against there being existing records in the journal file. This is
+ ** dangerous, as following a crash they may be mistaken for records
+ ** written by the current transaction and rolled back into the database
+ ** file, causing corruption. The following assert statements verify
+ ** that this is not required in "journal_mode=memory" mode, as in that
+ ** case the journal file is always 0 bytes in size at this point.
+ ** It is advantageous to avoid the sqlite3_randomness() call if possible
+ ** as it takes the global PRNG mutex. */
+ i64 sz = 0;
+ sqlite3OsFileSize(pPager->jfd, &sz);
+ assert( sz==0 );
+ assert( pPager->journalOff==journalHdrOffset(pPager) );
+ assert( sqlite3JournalIsInMemory(pPager->jfd) );
+ }
+#endif
put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit);
+
/* The initial database size */
put32bits(&zHeader[sizeof(aJournalMagic)+8], pPager->dbOrigSize);
/* The assumed sector size for this process */
@@ -57814,7 +58803,7 @@ static int readJournalHdr(
** + 4 bytes: super-journal name checksum.
** + 8 bytes: aJournalMagic[].
**
-** The super-journal page checksum is the sum of the bytes in thesuper-journal
+** The super-journal page checksum is the sum of the bytes in the super-journal
** name, where each byte is interpreted as a signed 8-bit integer.
**
** If zSuper is a NULL pointer (occurs for a single database transaction),
@@ -57867,7 +58856,7 @@ static int writeSuperJournal(Pager *pPager, const char *zSuper){
}
pPager->journalOff += (nSuper+20);
- /* If the pager is in peristent-journal mode, then the physical
+ /* If the pager is in persistent-journal mode, then the physical
** journal-file may extend past the end of the super-journal name
** and 8 bytes of magic data just written to the file. This is
** dangerous because the code to rollback a hot-journal file
@@ -57971,7 +58960,7 @@ static void pager_unlock(Pager *pPager){
if( pagerUseWal(pPager) ){
assert( !isOpen(pPager->jfd) );
#ifndef SQLITE_OMIT_WAL
- pPager->pWalMethods->xEndReadTransaction(pPager->pWal);
+ pPager->wal->methods.xEndReadTransaction(pPager->wal->pData);
#endif
pPager->eState = PAGER_OPEN;
}else if( !pPager->exclusiveMode ){
@@ -58039,7 +59028,7 @@ static void pager_unlock(Pager *pPager){
/*
** This function is called whenever an IOERR or FULL error that requires
-** the pager to transition into the ERROR state may ahve occurred.
+** the pager to transition into the ERROR state may have occurred.
** The first argument is a pointer to the pager structure, the second
** the error-code about to be returned by a pager API function. The
** value returned is a copy of the second argument to this function.
@@ -58252,7 +59241,7 @@ static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){
** lock held on the database file.
*/
#ifndef SQLITE_OMIT_WAL
- rc2 = pPager->pWalMethods->xEndWriteTransaction(pPager->pWal);
+ rc2 = pPager->wal->methods.xEndWriteTransaction(pPager->wal->pData);
#endif
assert( rc2==SQLITE_OK );
}else if( rc==SQLITE_OK && bCommit && pPager->dbFileSize>pPager->dbSize ){
@@ -58274,7 +59263,7 @@ static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){
int should_unlock = !pPager->exclusiveMode;
#ifndef SQLITE_OMIT_WAL
if (should_unlock && pagerUseWal(pPager)) {
- should_unlock &= pPager->pWalMethods->xExclusiveMode(pPager->pWal, 0);
+ should_unlock &= pPager->wal->methods.xExclusiveMode(pPager->wal->pData, 0);
}
#endif
if( should_unlock ){
@@ -58286,6 +59275,9 @@ static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){
return (rc==SQLITE_OK?rc2:rc);
}
+/* Forward reference */
+static int pager_playback(Pager *pPager, int isHot);
+
/*
** Execute a rollback if a transaction is active and unlock the
** database file.
@@ -58314,13 +59306,28 @@ static void pagerUnlockAndRollback(Pager *pPager){
assert( pPager->eState==PAGER_READER );
pager_end_transaction(pPager, 0, 0);
}
+ }else if( pPager->eState==PAGER_ERROR
+ && pPager->journalMode==PAGER_JOURNALMODE_MEMORY
+ && isOpen(pPager->jfd)
+ ){
+ /* Special case for a ROLLBACK due to I/O error with an in-memory
+ ** journal: We have to rollback immediately, before the journal is
+ ** closed, because once it is closed, all content is forgotten. */
+ int errCode = pPager->errCode;
+ u8 eLock = pPager->eLock;
+ pPager->eState = PAGER_OPEN;
+ pPager->errCode = SQLITE_OK;
+ pPager->eLock = EXCLUSIVE_LOCK;
+ pager_playback(pPager, 1);
+ pPager->errCode = errCode;
+ pPager->eLock = eLock;
}
pager_unlock(pPager);
}
/*
** Parameter aData must point to a buffer of pPager->pageSize bytes
-** of data. Compute and return a checksum based ont the contents of the
+** of data. Compute and return a checksum based on the contents of the
** page of data and the current value of pPager->cksumInit.
**
** This is not a real checksum. It is really just the sum of the
@@ -58753,6 +59760,8 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
int rc = SQLITE_OK;
assert( pPager->eState!=PAGER_ERROR );
assert( pPager->eState!=PAGER_READER );
+ PAGERTRACE(("Truncate %d npage %u\n", PAGERID(pPager), nPage));
+
if( isOpen(pPager->fd)
&& (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
@@ -59124,11 +60133,11 @@ static int readDbPage(PgHdr *pPg){
assert( isOpen(pPager->fd) );
if( pagerUseWal(pPager) ){
- rc = pPager->pWalMethods->xFindFrame(pPager->pWal, pPg->pgno, &iFrame);
+ rc = pPager->wal->methods.xFindFrame(pPager->wal->pData, pPg->pgno, &iFrame);
if( rc ) return rc;
}
if( iFrame ){
- rc = pPager->pWalMethods->xReadFrame(pPager->pWal, iFrame,pPager->pageSize,pPg->pData);
+ rc = pPager->wal->methods.xReadFrame(pPager->wal->pData, iFrame,pPager->pageSize,pPg->pData);
}else
#endif
{
@@ -59251,7 +60260,7 @@ static int pagerRollbackWal(Pager *pPager){
** + Reload page content from the database (if refcount>0).
*/
pPager->dbSize = pPager->dbOrigSize;
- rc = pPager->pWalMethods->xUndo(pPager->pWal, pagerUndoCallback, (void *)pPager);
+ rc = pPager->wal->methods.xUndo(pPager->wal->pData, pagerUndoCallback, (void *)pPager);
pList = sqlite3PcacheDirtyList(pPager->pPCache);
while( pList && rc==SQLITE_OK ){
PgHdr *pNext = pList->pDirty;
@@ -59281,10 +60290,10 @@ static int pagerWalFrames(
int nList; /* Number of pages in pList */
PgHdr *p; /* For looping over pages */
- assert( pPager->pWal );
+ assert( pagerUseWal(pPager) );
assert( pList );
#ifdef SQLITE_DEBUG
- /* Verify that the page list is in accending order */
+ /* Verify that the page list is in ascending order */
for(p=pList; p && p->pDirty; p=p->pDirty){
assert( p->pgno < p->pDirty->pgno );
}
@@ -59311,8 +60320,8 @@ static int pagerWalFrames(
pPager->aStat[PAGER_STAT_WRITE] += nList;
if( pList->pgno==1 ) pager_write_changecounter(pList);
- rc = pPager->pWalMethods->xFrames(pPager->pWal,
- pPager->pageSize, pList, nTruncate, isCommit, pPager->walSyncFlags
+ rc = pPager->wal->methods.xFrames(pPager->wal->pData,
+ pPager->pageSize, pList, nTruncate, isCommit, pPager->walSyncFlags, NULL
);
if( rc==SQLITE_OK && pPager->pBackup ){
for(p=pList; p; p=p->pDirty){
@@ -59350,9 +60359,9 @@ static int pagerBeginReadTransaction(Pager *pPager){
** are in locking_mode=NORMAL and EndRead() was previously called,
** the duplicate call is harmless.
*/
- pPager->pWalMethods->xEndReadTransaction(pPager->pWal);
+ pPager->wal->methods.xEndReadTransaction(pPager->wal->pData);
- rc = pPager->pWalMethods->xBeginReadTransaction(pPager->pWal, &changed);
+ rc = pPager->wal->methods.xBeginReadTransaction(pPager->wal->pData, &changed);
if( rc!=SQLITE_OK || changed ){
pager_reset(pPager);
if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
@@ -59385,7 +60394,7 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
assert( isOpen(pPager->fd) );
assert( pPager->tempFile==0 );
#ifndef SQLITE_OMIT_WAL
- nPage = pagerUseWal(pPager) ? pPager->pWalMethods->xDbsize(pPager->pWal) : 0;
+ nPage = pagerUseWal(pPager) ? pPager->wal->methods.xDbsize(pPager->wal->pData) : 0;
#else
nPage = 0;
#endif
@@ -59419,7 +60428,7 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
#ifndef SQLITE_OMIT_WAL
/*
** Check if the *-wal file that corresponds to the database opened by pPager
-** exists if the database is not empy, or verify that the *-wal file does
+** exists if the database is not empty, or verify that the *-wal file does
** not exist (by deleting it) if the database file is empty.
**
** If the database is not empty and the *-wal file exists, open the pager
@@ -59442,9 +60451,7 @@ static int pagerOpenWalIfPresent(Pager *pPager){
if( !pPager->tempFile ){
int isWal; /* True if WAL file exists */
- rc = sqlite3OsAccess(
- pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal
- );
+ rc =pPager->wal_manager->ref.xLogExists(pPager->wal_manager->ref.pData, pPager->pVfs, pPager->zFilename, &isWal);
if( rc==SQLITE_OK ){
if( isWal ){
Pgno nPage; /* Size of the database file */
@@ -59452,7 +60459,7 @@ static int pagerOpenWalIfPresent(Pager *pPager){
rc = pagerPagecount(pPager, &nPage);
if( rc ) return rc;
if( nPage==0 ){
- rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
+ rc = pPager->wal_manager->ref.xLogDestroy(pPager->wal_manager->ref.pData, pPager->pVfs, pPager->zFilename);
}else{
testcase( sqlite3PcachePagecount(pPager->pPCache)==0 );
rc = sqlite3PagerOpenWal(pPager, 0);
@@ -59594,7 +60601,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
#ifndef SQLITE_OMIT_WAL
if( pagerUseWal(pPager) ){
- rc = pPager->pWalMethods->xSavepointUndo(pPager->pWal, pSavepoint->aWalData);
+ rc = pPager->wal->methods.xSavepointUndo(pPager->wal->pData, pSavepoint->aWalData);
}
#endif
for(ii=pSavepoint->iSubRec; rc==SQLITE_OK && iinSubRec; ii++){
@@ -60272,16 +61279,18 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
#ifndef SQLITE_OMIT_WAL
{
u8 *a = 0;
- assert( db || pPager->pWal==0 );
+ assert( db || !pagerUseWal(pPager) );
if( db && 0==(db->flags & SQLITE_NoCkptOnClose)
&& SQLITE_OK==databaseIsUnmoved(pPager)
){
a = pTmp;
}
if (pagerUseWal(pPager)) {
- pPager->pWalMethods->xClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,a);
+ pPager->wal_manager->ref.xClose(pPager->wal_manager->ref.pData, pPager->wal->pData, db, pPager->walSyncFlags, pPager->pageSize,a);
+ sqlite3_free(pPager->wal);
+ pPager->wal = NULL;
}
- pPager->pWal = 0;
+ destroy_wal_manager(pPager->wal_manager);
}
#endif
pager_reset(pPager);
@@ -60821,7 +61830,7 @@ SQLITE_PRIVATE int sqlite3PagerFlush(Pager *pPager){
*/
SQLITE_PRIVATE int sqlite3PagerOpen(
sqlite3_vfs *pVfs, /* The virtual file system to use */
- libsql_wal_methods *pWalMethods, /* WAL methods to use */
+ RefCountedWalManager *wal_manager, /* WAL methods to use */
Pager **ppPager, /* OUT: Return the Pager structure here */
const char *zFilename, /* Name of the database file to open */
int nExtra, /* Extra bytes append to each in-memory page */
@@ -60834,11 +61843,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
int rc = SQLITE_OK; /* Return code */
int tempFile = 0; /* True for temp files (incl. in-memory files) */
int memDb = 0; /* True if this is an in-memory file */
-#ifndef SQLITE_OMIT_DESERIALIZE
int memJM = 0; /* Memory journal mode */
-#else
-# define memJM 0
-#endif
int readOnly = 0; /* True if this is a read-only file */
int journalFileSize; /* Bytes to allocate for each journal fd */
char *zPathname = 0; /* Full path to database file */
@@ -60913,10 +61918,6 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
}
}
-#ifndef SQLITE_OMIT_WAL
- int nWalPathname = pWalMethods->xPathnameLen(nPathname);
-#endif
-
/* Allocate memory for the Pager structure, PCache object, the
** three file descriptors, the database file name and the journal
** file name. The layout in memory is as follows:
@@ -60961,19 +61962,18 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
** specific formatting and order of the various filenames, so if the format
** changes here, be sure to change it there as well.
*/
+ assert( SQLITE_PTRSIZE==sizeof(Pager*) );
pPtr = (u8 *)sqlite3MallocZero(
ROUND8(sizeof(*pPager)) + /* Pager structure */
ROUND8(pcacheSize) + /* PCache object */
ROUND8(pVfs->szOsFile) + /* The main db file */
journalFileSize * 2 + /* The two journal files */
- sizeof(pPager) + /* Space to hold a pointer */
+ SQLITE_PTRSIZE + /* Space to hold a pointer */
4 + /* Database prefix */
nPathname + 1 + /* database filename */
nUriByte + /* query parameters */
+ nPathname + 4 + 1 + /* WAL filename (FIXME: move to virtual WAL) */
nPathname + 8 + 1 + /* Journal filename */
-#ifndef SQLITE_OMIT_WAL
- nWalPathname + 1 + /* WAL filename */
-#endif
3 /* Terminator */
);
assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) );
@@ -60986,8 +61986,9 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
pPager->fd = (sqlite3_file*)pPtr; pPtr += ROUND8(pVfs->szOsFile);
pPager->sjfd = (sqlite3_file*)pPtr; pPtr += journalFileSize;
pPager->jfd = (sqlite3_file*)pPtr; pPtr += journalFileSize;
+ pPager->wal_manager = clone_wal_manager(wal_manager);
assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) );
- memcpy(pPtr, &pPager, sizeof(pPager)); pPtr += sizeof(pPager);
+ memcpy(pPtr, &pPager, SQLITE_PTRSIZE); pPtr += SQLITE_PTRSIZE;
/* Fill in the Pager.zFilename and pPager.zQueryParam fields */
pPtr += 4; /* Skip zero prefix */
@@ -61015,15 +62016,14 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
pPager->zJournal = 0;
}
+ /* Fill in Pager.zWal: FIXME: it will make sqlite3_filename_database work for regular WAL,
+ but those routines need to be rewritten to take virtual WAL into account. */
#ifndef SQLITE_OMIT_WAL
- pPager->pWalMethods = pWalMethods;
/* Fill in Pager.zWal */
- if( nWalPathname>0 ){
+ if( nPathname>0 ){
pPager->zWal = (char*)pPtr;
- pWalMethods->xGetWalPathname((char *)pPtr, zPathname, nPathname);
- pPtr += nWalPathname;
- pPtr[0] = '\0';
- pPtr++;
+ memcpy(pPtr, zPathname, nPathname); pPtr += nPathname;
+ memcpy(pPtr, "-wal", 4); pPtr += 4 + 1;
#ifdef SQLITE_ENABLE_8_3_NAMES
sqlite3FileSuffix3(zFilename, pPager->zWal);
pPtr = (u8*)(pPager->zWal + sqlite3Strlen30(pPager->zWal)+1);
@@ -61031,13 +62031,10 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
}else{
pPager->zWal = 0;
}
+#endif
- if (pWalMethods->xPreMainDbOpen) {
- int rc = pWalMethods->xPreMainDbOpen(pWalMethods, zPathname);
- if (rc != SQLITE_OK) {
- return rc;
- }
- }
+#ifndef SQLITE_OMIT_WAL
+ pPager->wal = NULL;
#endif
(void)pPtr; /* Suppress warning about unused pPtr value */
@@ -61051,9 +62048,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
int fout = 0; /* VFS flags returned by xOpen() */
rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout);
assert( !memDb );
-#ifndef SQLITE_OMIT_DESERIALIZE
pPager->memVfs = memJM = (fout&SQLITE_OPEN_MEMORY)!=0;
-#endif
readOnly = (fout&SQLITE_OPEN_READONLY)!=0;
/* If the file was successfully opened for read/write access,
@@ -61138,6 +62133,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
if( rc!=SQLITE_OK ){
sqlite3OsClose(pPager->fd);
sqlite3PageFree(pPager->pTmpSpace);
+ destroy_wal_manager(pPager->wal_manager);
sqlite3_free(pPager);
return rc;
}
@@ -61190,7 +62186,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
/*
** Return the sqlite3_file for the main database given the name
-** of the corresonding WAL or Journal name as passed into
+** of the corresponding WAL or Journal name as passed into
** xOpen.
*/
SQLITE_API sqlite3_file *sqlite3_database_file_object(const char *zName){
@@ -61538,7 +62534,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
*/
rc = pagerOpenWalIfPresent(pPager);
#ifndef SQLITE_OMIT_WAL
- assert( pPager->pWal==0 || rc==SQLITE_OK );
+ assert( !pagerUseWal(pPager) || rc==SQLITE_OK );
#endif
}
@@ -61693,6 +62689,10 @@ static int getPageNormal(
if( !isOpen(pPager->fd) || pPager->dbSizepPager->mxPgno ){
rc = SQLITE_FULL;
+ if( pgno<=pPager->dbSize ){
+ sqlite3PcacheRelease(pPg);
+ pPg = 0;
+ }
goto pager_acquire_err;
}
if( noContent ){
@@ -61771,7 +62771,7 @@ static int getPageMMap(
if( bMmapOk && pagerUseWal(pPager) ){
#ifndef SQLITE_OMIT_WAL
- rc = pPager->pWalMethods->xFindFrame(pPager->pWal, pgno, &iFrame);
+ rc = pPager->wal->methods.xFindFrame(pPager->wal->pData, pgno, &iFrame);
if( rc!=SQLITE_OK ){
*ppPage = 0;
return rc;
@@ -61830,8 +62830,20 @@ SQLITE_PRIVATE int sqlite3PagerGet(
DbPage **ppPage, /* Write a pointer to the page here */
int flags /* PAGER_GET_XXX flags */
){
- /* printf("PAGE %u\n", pgno); fflush(stdout); */
+#if 0 /* Trace page fetch by setting to 1 */
+ int rc;
+ printf("PAGE %u\n", pgno);
+ fflush(stdout);
+ rc = pPager->xGet(pPager, pgno, ppPage, flags);
+ if( rc ){
+ printf("PAGE %u failed with 0x%02x\n", pgno, rc);
+ fflush(stdout);
+ }
+ return rc;
+#else
+ /* Normal, high-speed version of sqlite3PagerGet() */
return pPager->xGet(pPager, pgno, ppPage, flags);
+#endif
}
/*
@@ -61859,10 +62871,12 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
/*
** Release a page reference.
**
-** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be
-** used if we know that the page being released is not the last page.
+** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be used
+** if we know that the page being released is not the last reference to page1.
** The btree layer always holds page1 open until the end, so these first
-** to routines can be used to release any page other than BtShared.pPage1.
+** two routines can be used to release any page other than BtShared.pPage1.
+** The assert() at tag-20230419-2 proves that this constraint is always
+** honored.
**
** Use sqlite3PagerUnrefPageOne() to release page1. This latter routine
** checks the total number of outstanding pages and if the number of
@@ -61878,7 +62892,7 @@ SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage *pPg){
sqlite3PcacheRelease(pPg);
}
/* Do not use this routine to release the last reference to page1 */
- assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
+ assert( sqlite3PcacheRefCount(pPager->pPCache)>0 ); /* tag-20230419-2 */
}
SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){
if( pPg ) sqlite3PagerUnrefNotNull(pPg);
@@ -62021,12 +63035,12 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory
/* If the pager is configured to use locking_mode=exclusive, and an
** exclusive lock on the database is not already held, obtain it now.
*/
- if( pPager->exclusiveMode && pPager->pWalMethods->xExclusiveMode(pPager->pWal, -1) ){
+ if( pPager->exclusiveMode && pPager->wal->methods.xExclusiveMode(pPager->wal->pData, -1) ){
rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
if( rc!=SQLITE_OK ){
return rc;
}
- (void)pPager->pWalMethods->xExclusiveMode(pPager->pWal, 1);
+ (void)pPager->wal->methods.xExclusiveMode(pPager->wal->pData, 1);
}
/* Grab the write lock on the log file. If successful, upgrade to
@@ -62034,7 +63048,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory
** The busy-handler is not invoked if another connection already
** holds the write-lock. If possible, the upper layer will call it.
*/
- rc = pPager->pWalMethods->xBeginWriteTransaction(pPager->pWal);
+ rc = pPager->wal->methods.xBeginWriteTransaction(pPager->wal->pData);
#endif
}else{
/* Obtain a RESERVED lock on the database file. If the exFlag parameter
@@ -62707,6 +63721,13 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
if( rc==SQLITE_OK ){
rc = pager_write_pagelist(pPager, pList);
+ if( rc==SQLITE_OK && pPager->dbSize>pPager->dbFileSize ){
+ char *pTmp = pPager->pTmpSpace;
+ int szPage = (int)pPager->pageSize;
+ memset(pTmp, 0, szPage);
+ rc = sqlite3OsWrite(pPager->fd, pTmp, szPage,
+ ((i64)pPager->dbSize*pPager->pageSize)-szPage);
+ }
if( rc==SQLITE_OK ){
rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
}
@@ -63037,7 +64058,7 @@ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){
}
if( pagerUseWal(pPager) ){
#ifndef SQLITE_OMIT_WAL
- pPager->pWalMethods->xSavepoint(pPager->pWal, aNew[ii].aWalData);
+ pPager->wal->methods.xSavepoint(pPager->wal->pData, aNew[ii].aWalData);
#endif
}
pPager->nSavepoint = ii+1;
@@ -63190,7 +64211,7 @@ SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){
** Return the WAL methods structure for the pager.
*/
SQLITE_PRIVATE libsql_wal_methods *sqlite3PagerWalMethods(Pager *pPager){
- return pPager->pWalMethods;
+ return &(pPager->wal->methods);
}
#endif
@@ -63211,7 +64232,7 @@ SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){
#if SQLITE_OMIT_WAL
return pPager->jfd;
#else
- return pPager->pWal ? pPager->pWalMethods->xFile(pPager->pWal) : pPager->jfd;
+ return pagerUseWal(pPager) ? pPager->wal->methods.xFile(pPager->wal->pData) : pPager->jfd;
#endif
}
@@ -63411,7 +64432,7 @@ SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *pPg){
static int pagerWalHeapMemory(Pager *pPager) {
#ifndef SQLITE_OMIT_WAL
if (pagerUseWal(pPager)) {
- return pPager->pWalMethods->xHeapMemory(pPager->pWal);
+ return pPager->wal->methods.xHeapMemory(pPager->wal->pData);
}
#endif
return 0;
@@ -63493,7 +64514,7 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
assert( pPager->eState!=PAGER_ERROR );
pPager->journalMode = (u8)eMode;
- /* When transistioning from TRUNCATE or PERSIST to any other journal
+ /* When transitioning from TRUNCATE or PERSIST to any other journal
** mode except WAL, unless the pager is in locking_mode=exclusive mode,
** delete the journal file.
*/
@@ -63538,7 +64559,7 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
}
assert( state==pPager->eState );
}
- }else if( eMode==PAGER_JOURNALMODE_OFF ){
+ }else if( eMode==PAGER_JOURNALMODE_OFF || eMode==PAGER_JOURNALMODE_MEMORY ){
sqlite3OsClose(pPager->jfd);
}
}
@@ -63576,7 +64597,9 @@ SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *pPager, i64 iLimit){
if( iLimit>=-1 ){
pPager->journalSizeLimit = iLimit;
#ifndef SQLITE_OMIT_WAL
- pPager->pWalMethods->xLimit(pPager->pWal, iLimit);
+ if (pagerUseWal(pPager)) {
+ pPager->wal->methods.xLimit(pPager->wal->pData, iLimit);
+ }
#endif
}
return pPager->journalSizeLimit;
@@ -63619,7 +64642,7 @@ SQLITE_PRIVATE int sqlite3PagerCheckpoint(
int *pnCkpt /* OUT: Final number of checkpointed frames */
){
int rc = SQLITE_OK;
- if( pPager->pWal==0 && pPager->journalMode==PAGER_JOURNALMODE_WAL ){
+ if( !pagerUseWal(pPager) && pPager->journalMode==PAGER_JOURNALMODE_WAL ){
/* This only happens when a database file is zero bytes in size opened and
** then "PRAGMA journal_mode=WAL" is run and then sqlite3_wal_checkpoint()
** is invoked without any intervening transactions. We need to start
@@ -63631,12 +64654,12 @@ SQLITE_PRIVATE int sqlite3PagerCheckpoint(
*/
sqlite3_exec(db, "PRAGMA table_list",0,0,0);
}
- if( pPager->pWal ){
- rc = pPager->pWalMethods->xCheckpoint(pPager->pWal, db, eMode,
+ if(pagerUseWal(pPager)){
+ rc = pPager->wal->methods.xCheckpoint(pPager->wal->pData, db, eMode,
(eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
pPager->pBusyHandlerArg,
pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
- pnLog, pnCkpt
+ pnLog, pnCkpt, NULL, NULL
);
}
return rc;
@@ -63644,7 +64667,7 @@ SQLITE_PRIVATE int sqlite3PagerCheckpoint(
SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
if (pagerUseWal(pPager)) {
- return pPager->pWalMethods->xCallback(pPager->pWal);
+ return pPager->wal->methods.xCallback(pPager->wal->pData);
}
return SQLITE_OK;
}
@@ -63656,7 +64679,7 @@ SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){
const sqlite3_io_methods *pMethods = pPager->fd->pMethods;
if( pPager->noLock ) return 0;
- return pPager->exclusiveMode || (pPager->pWalMethods->bUsesShm == 0) || (pMethods->iVersion>=2 && pMethods->xShmMap);
+ return pPager->exclusiveMode || (pPager->wal_manager->ref.bUsesShm == 0) || (pMethods->iVersion>=2 && pMethods->xShmMap);
}
/*
@@ -63665,13 +64688,15 @@ SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){
*/
static int pagerExclusiveLock(Pager *pPager){
int rc; /* Return code */
+ u8 eOrigLock; /* Original lock */
- assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK );
+ assert( pPager->eLock>=SHARED_LOCK );
+ eOrigLock = pPager->eLock;
rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
if( rc!=SQLITE_OK ){
/* If the attempt to grab the exclusive lock failed, release the
** pending lock that may have been obtained instead. */
- pagerUnlockDb(pPager, SHARED_LOCK);
+ pagerUnlockDb(pPager, eOrigLock);
}
return rc;
@@ -63686,7 +64711,7 @@ static int pagerExclusiveLock(Pager *pPager){
static int pagerOpenWal(Pager *pPager){
int rc = SQLITE_OK;
- assert( pPager->pWal==0 && pPager->tempFile==0 );
+ assert( !pagerUseWal(pPager) && pPager->tempFile==0 );
assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK );
/* If the pager is already in exclusive-mode, the WAL module will use
@@ -63701,11 +64726,23 @@ static int pagerOpenWal(Pager *pPager){
/* Open the connection to the log file. If this operation fails,
** (e.g. due to malloc() failure), return an error code.
*/
+
if( rc==SQLITE_OK ){
- rc = pPager->pWalMethods->xOpen(pPager->pVfs,
- pPager->fd, pPager->zWal, pPager->exclusiveMode,
- pPager->journalSizeLimit, pPager->pWalMethods, &pPager->pWal
- );
+ libsql_wal *wal = (libsql_wal*)sqlite3MallocZero(sizeof(libsql_wal));
+ if (!wal) {
+ rc = SQLITE_NOMEM;
+ }
+ if (rc == SQLITE_OK) {
+ rc = pPager->wal_manager->ref.xOpen(pPager->wal_manager->ref.pData, pPager->pVfs,
+ pPager->fd, pPager->exclusiveMode,
+ pPager->journalSizeLimit, pPager->zFilename, wal
+ );
+ if (rc == SQLITE_OK) {
+ pPager->wal = wal;
+ } else {
+ sqlite3_free(wal);
+ }
+ }
}
pagerFixMaplimit(pPager);
@@ -63738,9 +64775,9 @@ SQLITE_PRIVATE int sqlite3PagerOpenWal(
assert( pPager->eState==PAGER_OPEN || pbOpen );
assert( pPager->eState==PAGER_READER || !pbOpen );
assert( pbOpen==0 || *pbOpen==0 );
- assert( pbOpen!=0 || (!pPager->tempFile && !pPager->pWal) );
+ assert( pbOpen!=0 || (!pPager->tempFile && !pagerUseWal(pPager)) );
- if( !pPager->tempFile && !pPager->pWal ){
+ if( !pPager->tempFile && !pagerUseWal(pPager) ){
if( !sqlite3PagerWalSupported(pPager) ) return SQLITE_CANTOPEN;
/* Close any rollback journal previously open */
@@ -63776,13 +64813,11 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
** it may need to be checkpointed before the connection can switch to
** rollback mode. Open it now so this can happen.
*/
- if( !pPager->pWal ){
+ if( !pagerUseWal(pPager) ){
int logexists = 0;
rc = pagerLockDb(pPager, SHARED_LOCK);
if( rc==SQLITE_OK ){
- rc = sqlite3OsAccess(
- pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &logexists
- );
+ rc = pPager->wal_manager->ref.xLogExists(pPager->wal_manager->ref.pData, pPager->pVfs, pPager->zFilename, &logexists);
}
if( rc==SQLITE_OK && logexists ){
rc = pagerOpenWal(pPager);
@@ -63792,12 +64827,13 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
/* Checkpoint and close the log. Because an EXCLUSIVE lock is held on
** the database file, the log and log-summary files will be deleted.
*/
- if( rc==SQLITE_OK && pPager->pWal ){
+ if( rc==SQLITE_OK && pagerUseWal(pPager) ){
rc = pagerExclusiveLock(pPager);
if( rc==SQLITE_OK ){
- rc = pPager->pWalMethods->xClose(pPager->pWal, db, pPager->walSyncFlags,
+ rc = pPager->wal_manager->ref.xClose(pPager->wal_manager->ref.pData, pPager->wal->pData, db, pPager->walSyncFlags,
pPager->pageSize, (u8*)pPager->pTmpSpace);
- pPager->pWal = 0;
+ sqlite3_free(pPager->wal);
+ pPager->wal = NULL;
pagerFixMaplimit(pPager);
if( rc && !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK);
}
@@ -63838,8 +64874,8 @@ SQLITE_PRIVATE void sqlite3PagerWalDb(Pager *pPager, sqlite3 *db){
*/
SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot){
int rc = SQLITE_ERROR;
- if( pPager->pWal ){
- rc = pPager->pWalMethods->xSnapshotGet(pPager->pWal, ppSnapshot);
+ if( pagerUseWal(pPager) ){
+ rc = pPager->walxSnapshotGet(pPager->wal.pData, ppSnapshot);
}
return rc;
}
@@ -63854,8 +64890,8 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(
sqlite3_snapshot *pSnapshot
){
int rc = SQLITE_OK;
- if( pPager->pWal ){
- pPager->pWalMethods->xSnapshotOpen(pPager->pWal, pSnapshot);
+ if( pagerUseWal(pPager) ){
+ pPager->wal.xSnapshotOpen(pPager->wal.pData, pSnapshot);
}else{
rc = SQLITE_ERROR;
}
@@ -63868,8 +64904,8 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(
*/
SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager){
int rc;
- if( pPager->pWal ){
- rc = pPager->pWalMethods->xSnapshotRecover(pPager->pWal);
+ if( pagerUseWal(pPage) ){
+ rc = pPager->wal.xSnapshotRecover(pPager->wal.pData);
}else{
rc = SQLITE_ERROR;
}
@@ -63890,8 +64926,8 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager){
*/
SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot){
int rc;
- if( pPager->pWal ){
- rc = pPager->pWalMethods->xSnapshotCheck(pPager->pWal, pSnapshot);
+ if( pagerUseWal(pPager) ){
+ rc = pPager->wal.xSnapshotCheck(pPager->wal.pData, pSnapshot);
}else{
rc = SQLITE_ERROR;
}
@@ -63903,8 +64939,8 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pS
** sqlite3PagerSnapshotCheck().
*/
SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager){
- assert( pPager->pWal );
- pPager->pWalMethods->xSnapshotUnlock(pPager->pWal);
+ assert( pagerUseWal(pPager) );
+ pPager->wal.xSnapshotUnlock(pPager->wal.pData)
}
#endif /* SQLITE_ENABLE_SNAPSHOT */
@@ -63924,6 +64960,12 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
}
#endif
+#ifdef SQLITE_USE_SEH
+SQLITE_PRIVATE int sqlite3PagerWalSystemErrno(Pager *pPager){
+ return sqlite3WalSystemErrno(pPager->pWal);
+}
+#endif
+
#endif /* SQLITE_OMIT_DISKIO */
/************** End of pager.c ***********************************************/
@@ -64182,8 +65224,33 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
/* #include "wal.h" */
+int libsql_pager_codec(libsql_pghdr *p, void **ret);
+
typedef libsql_pghdr PgHdr;
-typedef libsql_wal Wal;
+typedef sqlite3_wal Wal;
+
+static int sqlite3WalCheckpoint(
+ Wal *pWal, /* Wal connection */
+ sqlite3 *db, /* Check this handle's interrupt flag */
+ int eMode, /* PASSIVE, FULL, RESTART, or TRUNCATE */
+ int (*xBusy)(void*), /* Function to call when busy */
+ void *pBusyArg, /* Context argument for xBusyHandler */
+ int sync_flags, /* Flags to sync db file with (or 0) */
+ int nBuf, /* Size of temporary buffer */
+ u8 *zBuf, /* Temporary buffer to use */
+ int *pnLog, /* OUT: Number of frames in WAL */
+ int *pnCkpt, /* OUT: Number of backfilled frames in WAL */
+ int (*xCb)(void*, int, const unsigned char*, int, int, int),
+ void *pCbData
+);
+static void sqlite3WalEndReadTransaction(Wal *pWal);
+static int sqlite3WalEndWriteTransaction(Wal *pWal);
+static int walFindFrame(
+ Wal *pWal, /* WAL handle */
+ Pgno pgno, /* Database page number to read data for */
+ u32 iLast, /* Last page in WAL for this reader */
+ u32 *piRead /* OUT: Frame number (or zero) */
+);
/*
** Trace output macros
@@ -64218,7 +65285,7 @@ SQLITE_PRIVATE int sqlite3WalTrace = 0;
**
** Technically, the various VFSes are free to implement these locks however
** they see fit. However, compatibility is encouraged so that VFSes can
-** interoperate. The standard implemention used on both unix and windows
+** interoperate. The standard implementation used on both unix and windows
** is for the index number to indicate a byte offset into the
** WalCkptInfo.aLock[] array in the wal-index header. In other words, all
** locks are on the shm file. The WALINDEX_LOCK_OFFSET constant (which
@@ -64260,7 +65327,7 @@ SQLITE_PRIVATE int sqlite3WalTrace = 0;
** the mxFrame for that reader. The value READMARK_NOT_USED (0xffffffff)
** for any aReadMark[] means that entry is unused. aReadMark[0] is
** a special case; its value is never used and it exists as a place-holder
-** to avoid having to offset aReadMark[] indexs by one. Readers holding
+** to avoid having to offset aReadMark[] indexes by one. Readers holding
** WAL_READ_LOCK(0) always ignore the entire WAL and read all content
** directly from the database.
**
@@ -64446,6 +65513,12 @@ struct WalIterator {
} aSegment[1]; /* One for every 32KB page in the wal-index */
};
+struct WalIteratorRev {
+ u32 current;
+ /* A sparse array of page no, where frames[frame_no] = page_no if frame_no is the most recent version of this page, page_no = 0 otherwise */
+ u32 *frames;
+};
+
/*
** 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
@@ -64470,6 +65543,28 @@ struct WalIterator {
sizeof(ht_slot)*HASHTABLE_NSLOT + HASHTABLE_NPAGE*sizeof(u32) \
)
+/*
+** Structured Exception Handling (SEH) is a Windows-specific technique
+** for catching exceptions raised while accessing memory-mapped files.
+**
+** The -DSQLITE_USE_SEH compile-time option means to use SEH to catch and
+** deal with system-level errors that arise during WAL -shm file processing.
+** Without this compile-time option, any system-level faults that appear
+** while accessing the memory-mapped -shm file will cause a process-wide
+** signal to be deliver, which will more than likely cause the entire
+** process to exit.
+*/
+#ifdef SQLITE_USE_SEH
+# error "SEH is not supported in libSQL due to virtual WAL backward compatibility!"
+#else
+# define SEH_TRY
+# define SEH_EXCEPT(X)
+# define SEH_INJECT_FAULT
+# define SEH_FREE_ON_ERROR(X,Y)
+# define SEH_SET_ON_ERROR(X,Y)
+#endif /* ifdef SQLITE_USE_SEH */
+
+
/*
** Obtain a pointer to the iPage'th page of the wal-index. The wal-index
** is broken into pages of WALINDEX_PGSZ bytes. Wal-index pages are
@@ -64542,6 +65637,7 @@ static int walIndexPage(
int iPage, /* The page we seek */
volatile u32 **ppPage /* Write the page pointer here */
){
+ SEH_INJECT_FAULT;
if( pWal->nWiData<=iPage || (*ppPage = pWal->apWiData[iPage])==0 ){
return walIndexPageRealloc(pWal, iPage, ppPage);
}
@@ -64553,6 +65649,7 @@ static int walIndexPage(
*/
static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
assert( pWal->nWiData>0 && pWal->apWiData[0] );
+ SEH_INJECT_FAULT;
return (volatile WalCkptInfo*)&(pWal->apWiData[0][sizeof(WalIndexHdr)/2]);
}
@@ -64561,6 +65658,7 @@ static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
*/
static volatile WalIndexHdr *walIndexHdr(Wal *pWal){
assert( pWal->nWiData>0 && pWal->apWiData[0] );
+ SEH_INJECT_FAULT;
return (volatile WalIndexHdr*)pWal->apWiData[0];
}
@@ -64606,19 +65704,40 @@ static void walChecksumBytes(
assert( nByte>=8 );
assert( (nByte&0x00000007)==0 );
assert( nByte<=65536 );
+ assert( nByte%4==0 );
- if( nativeCksum ){
+ if( !nativeCksum ){
do {
+ s1 += BYTESWAP32(aData[0]) + s2;
+ s2 += BYTESWAP32(aData[1]) + s1;
+ aData += 2;
+ }while( aDataapWiData[0][WALINDEX_HDR_SIZE/sizeof(u32) + iFrame - 1];
}
- return pWal->apWiData[iHash][(iFrame-1-HASHTABLE_NPAGE_ONE)%HASHTABLE_NPAGE];
+
+ volatile u32 *page;
+ int rc = walIndexPage(pWal, iHash, &page);
+ assert( rc==SQLITE_OK || iHash>0 );
+ if (rc != SQLITE_OK) {
+ return 0;
+ }
+ return page[(iFrame-1-HASHTABLE_NPAGE_ONE)%HASHTABLE_NPAGE];
}
/*
@@ -65169,6 +66296,7 @@ static int walIndexRecover(Wal *pWal){
/* Malloc a buffer to read frames into. */
szFrame = szPage + WAL_FRAME_HDRSIZE;
aFrame = (u8 *)sqlite3_malloc64(szFrame + WALINDEX_PGSZ);
+ SEH_FREE_ON_ERROR(0, aFrame);
if( !aFrame ){
rc = SQLITE_NOMEM_BKPT;
goto recovery_error;
@@ -65187,6 +66315,7 @@ static int walIndexRecover(Wal *pWal){
rc = walIndexPage(pWal, iPg, (volatile u32**)&aShare);
assert( aShare!=0 || rc!=SQLITE_OK );
if( aShare==0 ) break;
+ SEH_SET_ON_ERROR(iPg, aShare);
pWal->apWiData[iPg] = aPrivate;
for(iFrame=iFirst; iFrame<=iLast; iFrame++){
@@ -65214,6 +66343,7 @@ static int walIndexRecover(Wal *pWal){
}
}
pWal->apWiData[iPg] = aShare;
+ SEH_SET_ON_ERROR(0,0);
nHdr = (iPg==0 ? WALINDEX_HDR_SIZE : 0);
nHdr32 = nHdr / sizeof(u32);
#ifndef SQLITE_SAFER_WALINDEX_RECOVERY
@@ -65244,9 +66374,11 @@ static int walIndexRecover(Wal *pWal){
}
}
#endif
+ SEH_INJECT_FAULT;
if( iFrame<=iLast ) break;
}
+ SEH_FREE_ON_ERROR(aFrame, 0);
sqlite3_free(aFrame);
}
@@ -65274,6 +66406,7 @@ static int walIndexRecover(Wal *pWal){
}else{
pInfo->aReadMark[i] = READMARK_NOT_USED;
}
+ SEH_INJECT_FAULT;
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
}else if( rc!=SQLITE_BUSY ){
goto recovery_error;
@@ -65315,127 +66448,9 @@ static void walIndexClose(Wal *pWal, int isDelete){
}
}
-/*
-** Open a connection to the WAL file zWalName. The database file must
-** already be opened on connection pDbFd. The buffer that zWalName points
-** to must remain valid for the lifetime of the returned Wal* handle.
-**
-** Custom virtual methods may be provided via the pMethods parameter.
-**
-** A SHARED lock should be held on the database file when this function
-** is called. The purpose of this SHARED lock is to prevent any other
-** client from unlinking the WAL or wal-index file. If another process
-** were to do this just after this client opened one of these files, the
-** system would be badly broken.
-**
-** If the log file is successfully opened, SQLITE_OK is returned and
-** *ppWal is set to point to a new WAL handle. If an error occurs,
-** an SQLite error code is returned and *ppWal is left unmodified.
-*/
-static int sqlite3WalOpen(
- sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */
- sqlite3_file *pDbFd, /* The open database file */
- const char *zWalName, /* Name of the WAL file */
- int bNoShm, /* True to run in heap-memory mode */
- i64 mxWalSize, /* Truncate WAL to this size on reset */
- libsql_wal_methods* pMethods, /* Virtual methods for interacting with WAL */
- Wal **ppWal /* OUT: Allocated Wal handle */
-){
- int rc; /* Return Code */
- Wal *pRet; /* Object to allocate and return */
- int flags; /* Flags passed to OsOpen() */
-
- assert( zWalName && zWalName[0] );
- assert( pDbFd );
-
- /* Verify the values of various constants. Any changes to the values
- ** of these constants would result in an incompatible on-disk format
- ** for the -shm file. Any change that causes one of these asserts to
- ** fail is a backward compatibility problem, even if the change otherwise
- ** works.
- **
- ** This table also serves as a helpful cross-reference when trying to
- ** interpret hex dumps of the -shm file.
- */
- assert( 48 == sizeof(WalIndexHdr) );
- assert( 40 == sizeof(WalCkptInfo) );
- assert( 120 == WALINDEX_LOCK_OFFSET );
- assert( 136 == WALINDEX_HDR_SIZE );
- assert( 4096 == HASHTABLE_NPAGE );
- assert( 4062 == HASHTABLE_NPAGE_ONE );
- assert( 8192 == HASHTABLE_NSLOT );
- assert( 383 == HASHTABLE_HASH_1 );
- assert( 32768 == WALINDEX_PGSZ );
- assert( 8 == SQLITE_SHM_NLOCK );
- assert( 5 == WAL_NREADER );
- assert( 24 == WAL_FRAME_HDRSIZE );
- assert( 32 == WAL_HDRSIZE );
- assert( 120 == WALINDEX_LOCK_OFFSET + WAL_WRITE_LOCK );
- assert( 121 == WALINDEX_LOCK_OFFSET + WAL_CKPT_LOCK );
- assert( 122 == WALINDEX_LOCK_OFFSET + WAL_RECOVER_LOCK );
- assert( 123 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(0) );
- assert( 124 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(1) );
- assert( 125 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(2) );
- assert( 126 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(3) );
- assert( 127 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(4) );
-
- /* In the amalgamation, the os_unix.c and os_win.c source files come before
- ** this source file. Verify that the #defines of the locking byte offsets
- ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value.
- ** For that matter, if the lock offset ever changes from its initial design
- ** value of 120, we need to know that so there is an assert() to check it.
- */
-#ifdef WIN_SHM_BASE
- assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET );
-#endif
-#ifdef UNIX_SHM_BASE
- assert( UNIX_SHM_BASE==WALINDEX_LOCK_OFFSET );
-#endif
-
-
- /* Allocate an instance of struct Wal to return. */
- *ppWal = 0;
- pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile);
- if( !pRet ){
- return SQLITE_NOMEM_BKPT;
- }
-
- pRet->pVfs = pVfs;
- pRet->pWalFd = (sqlite3_file *)&pRet[1];
- pRet->pDbFd = pDbFd;
- pRet->readLock = -1;
- pRet->mxWalSize = mxWalSize;
- pRet->zWalName = zWalName;
- pRet->syncHeader = 1;
- pRet->padToSectorBoundary = 1;
- pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);
-
- /* Open file handle on the write-ahead log file. */
- flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
- rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags);
- if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){
- pRet->readOnly = WAL_RDONLY;
- }
-
- if( rc!=SQLITE_OK ){
- walIndexClose(pRet, 0);
- sqlite3OsClose(pRet->pWalFd);
- sqlite3_free(pRet);
- }else{
- int iDC = sqlite3OsDeviceCharacteristics(pDbFd);
- if( iDC & SQLITE_IOCAP_SEQUENTIAL ){ pRet->syncHeader = 0; }
- if( iDC & SQLITE_IOCAP_POWERSAFE_OVERWRITE ){
- pRet->padToSectorBoundary = 0;
- }
- *ppWal = pRet;
- WALTRACE(("WAL%d: opened\n", pRet));
- }
- pRet->pMethods = pMethods;
- return rc;
-}
/*
-** Change the size to which the WAL file is trucated on each reset.
+** Change the size to which the WAL file is truncated on each reset.
*/
static void sqlite3WalLimit(Wal *pWal, i64 iLimit){
if( pWal ) pWal->mxWalSize = iLimit;
@@ -65481,6 +66496,31 @@ static int walIteratorNext(
return (iRet==0xFFFFFFFF);
}
+/*
+** Return 0 on success. If there are no pages in the WAL with a page
+** number larger than *piPage, then return 1.
+*/
+static int walIteratorRevNext(
+ struct WalIteratorRev *p, /* Iterator */
+ u32 *piPage, /* OUT: The page number of the next page */
+ u32 *piFrame /* OUT: Wal frame index of next page */
+){
+ while (p->current > 0 && p->frames[p->current] == 0) {
+ p->current -= 1;
+ }
+
+ if (p->current == 0) {
+ return 1;
+ }
+
+ *piFrame = p->current;
+ *piPage = p->frames[p->current];
+
+ p->current--;
+
+ return 0;
+}
+
/*
** This function merges two sorted lists into a single sorted list.
**
@@ -65661,23 +66701,16 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
nByte = sizeof(WalIterator)
+ (nSegment-1)*sizeof(struct WalSegment)
+ iLast*sizeof(ht_slot);
- p = (WalIterator *)sqlite3_malloc64(nByte);
+ p = (WalIterator *)sqlite3_malloc64(nByte
+ + sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
+ );
if( !p ){
return SQLITE_NOMEM_BKPT;
}
memset(p, 0, nByte);
p->nSegment = nSegment;
-
- /* Allocate temporary space used by the merge-sort routine. This block
- ** of memory will be freed before this function returns.
- */
- aTmp = (ht_slot *)sqlite3_malloc64(
- sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
- );
- if( !aTmp ){
- rc = SQLITE_NOMEM_BKPT;
- }
-
+ aTmp = (ht_slot*)&(((u8*)p)[nByte]);
+ SEH_FREE_ON_ERROR(0, p);
for(i=walFramePage(nBackfill+1); rc==SQLITE_OK && iaSegment[i].aPgno = (u32 *)sLoc.aPgno;
}
}
- sqlite3_free(aTmp);
-
if( rc!=SQLITE_OK ){
+ SEH_FREE_ON_ERROR(p, 0);
walIteratorFree(p);
p = 0;
}
@@ -65715,6 +66747,51 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
return rc;
}
+static int walIteratorRevInit(Wal *pWal, u32 nBackfill, struct WalIteratorRev *p, u32 mxSafeFrame, int ignoreFrameIfNewerExist){
+ WalIterator *pIter;
+ u32 *frames;
+ u32 iFrame, iPageno;
+ int rc;
+
+ frames = (u32*)sqlite3MallocZero((pWal->hdr.mxFrame + 1) * sizeof(u32));
+ if (!frames) return SQLITE_NOMEM_BKPT;
+ rc = walIteratorInit(pWal, nBackfill, &pIter);
+ if (rc || !pIter) {
+ sqlite3_free(frames);
+ return rc;
+ }
+
+ while (walIteratorNext(pIter, &iPageno, &iFrame) == 0) {
+ /*
+ * If we get a page with a frame_no greater than mxSafeFrame, and ignoreFrameIfNewerExist is false,
+ * then we replace it with the latest page with frame_no <= mxSafeFrame.
+ */
+ if (iFrame > mxSafeFrame && !ignoreFrameIfNewerExist) {
+ rc = walFindFrame(pWal, iPageno, mxSafeFrame, &iFrame);
+ if( rc!=SQLITE_OK ) break;
+ if (iFrame == 0) {
+ continue;
+ }
+ }
+ frames[iFrame] = iPageno;
+ }
+ walIteratorFree(pIter);
+ if (rc != 0) {
+ sqlite3_free(frames);
+ return rc;
+ }
+
+ p->current = pWal->hdr.mxFrame;
+ p->frames = frames;
+
+ return SQLITE_OK;
+}
+
+static void walIteratorRevFree(struct WalIteratorRev *p) {
+ p->current = 0;
+ sqlite3_free(p->frames);
+}
+
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
/*
** Attempt to enable blocking locks. Blocking locks are enabled only if (a)
@@ -65805,7 +66882,7 @@ static void sqlite3WalDb(Wal *pWal, sqlite3 *db){
** lock is successfully obtained or the busy-handler returns 0.
*/
static int walBusyLock(
- Wal *pWal, /* WAL connection */
+ Wal *pWal, /* WAL connection */
int (*xBusy)(void*), /* Function to call when busy */
void *pBusyArg, /* Context argument for xBusyHandler */
int lockIdx, /* Offset of first byte to lock */
@@ -65903,11 +66980,13 @@ static int walCheckpoint(
int (*xBusy)(void*), /* Function to call when busy */
void *pBusyArg, /* Context argument for xBusyHandler */
int sync_flags, /* Flags for OsSync() (or 0) */
- u8 *zBuf /* Temporary buffer to use */
+ u8 *zBuf, /* Temporary buffer to use */
+ void *pCbData, /* User data passed to xCb */
+ int (*xCb)(void* pCbData, int mxSafeFrame, const unsigned char* pPage, int nPage, int pageNo, int frameNo) /* Checkpoint callback */
){
int rc = SQLITE_OK; /* Return code */
int szPage; /* Database page-size */
- WalIterator *pIter = 0; /* Wal iterator context */
+ struct WalIteratorRev pIter = { 0 }; /* Wal iterator context */
u32 iDbpage = 0; /* Next database page to write */
u32 iFrame = 0; /* Wal frame containing data for iDbpage */
u32 mxSafeFrame; /* Max frame that can be backfilled */
@@ -65933,13 +67012,13 @@ static int walCheckpoint(
mxSafeFrame = pWal->hdr.mxFrame;
mxPage = pWal->hdr.nPage;
for(i=1; iaReadMark+i);
+ u32 y = AtomicLoad(pInfo->aReadMark+i); SEH_INJECT_FAULT;
if( mxSafeFrame>y ){
assert( y<=pWal->hdr.mxFrame );
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
if( rc==SQLITE_OK ){
u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
- AtomicStore(pInfo->aReadMark+i, iMark);
+ AtomicStore(pInfo->aReadMark+i, iMark); SEH_INJECT_FAULT;
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
}else if( rc==SQLITE_BUSY ){
mxSafeFrame = y;
@@ -65952,16 +67031,13 @@ static int walCheckpoint(
/* Allocate the iterator */
if( pInfo->nBackfillnBackfill, &pIter);
- assert( rc==SQLITE_OK || pIter==0 );
+ rc = walIteratorRevInit(pWal, pInfo->nBackfill, &pIter, mxSafeFrame, xCb == NULL);
+ assert(rc == SQLITE_OK || pIter.frames == NULL);
}
- if( pIter
- && (rc = walBusyLock(pWal,xBusy,pBusyArg,WAL_READ_LOCK(0),1))==SQLITE_OK
- ){
+ if(( pIter.frames != NULL && (rc = walBusyLock(pWal,xBusy,pBusyArg,WAL_READ_LOCK(0),1))==SQLITE_OK)){
u32 nBackfill = pInfo->nBackfill;
-
- pInfo->nBackfillAttempted = mxSafeFrame;
+ pInfo->nBackfillAttempted = mxSafeFrame; SEH_INJECT_FAULT;
/* Sync the WAL to disk */
rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags));
@@ -65989,9 +67065,10 @@ static int walCheckpoint(
}
/* Iterate through the contents of the WAL, copying data to the db file */
- while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
+ while( rc==SQLITE_OK && 0==walIteratorRevNext(&pIter, &iDbpage, &iFrame) ){
i64 iOffset;
assert( walFramePgno(pWal, iFrame)==iDbpage );
+ SEH_INJECT_FAULT;
if( AtomicLoad(&db->u1.isInterrupted) ){
rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
break;
@@ -66007,12 +67084,19 @@ static int walCheckpoint(
testcase( IS_BIG_INT(iOffset) );
rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
if( rc!=SQLITE_OK ) break;
+ if (xCb) {
+ rc = (xCb)(pCbData, mxSafeFrame, zBuf, szPage, iDbpage, iFrame);
+ }
+ if( rc!=SQLITE_OK ) break;
}
sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_DONE, 0);
/* If work was actually accomplished... */
if( rc==SQLITE_OK ){
if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
+ if (xCb) {
+ rc = (xCb)(pCbData, mxSafeFrame, NULL, 0, 0, 0);
+ }
i64 szDb = pWal->hdr.nPage*(i64)szPage;
testcase( IS_BIG_INT(szDb) );
rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
@@ -66021,7 +67105,7 @@ static int walCheckpoint(
}
}
if( rc==SQLITE_OK ){
- AtomicStore(&pInfo->nBackfill, mxSafeFrame);
+ AtomicStore(&pInfo->nBackfill, mxSafeFrame); SEH_INJECT_FAULT;
}
}
@@ -66043,6 +67127,7 @@ static int walCheckpoint(
*/
if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
assert( pWal->writeLock );
+ SEH_INJECT_FAULT;
if( pInfo->nBackfillhdr.mxFrame ){
rc = SQLITE_BUSY;
}else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
@@ -66074,7 +67159,8 @@ static int walCheckpoint(
}
walcheckpoint_out:
- walIteratorFree(pIter);
+ SEH_FREE_ON_ERROR(pIter, 0);
+ walIteratorRevFree(&pIter);
return rc;
}
@@ -66096,11 +67182,18 @@ static void walLimitSize(Wal *pWal, i64 nMax){
}
}
+#ifdef SQLITE_USE_SEH
+# error "SEH is not supported in libSQL due to virtual WAL backward compatibility!"
+#else
+# define walAssertLockmask(x) 1
+#endif /* ifdef SQLITE_USE_SEH */
+
/*
** Close a connection to a log file.
*/
static int sqlite3WalClose(
- Wal *pWal, /* Wal to close */
+ wal_manager_impl *self,
+ Wal *pWal, /* Wal to close */
sqlite3 *db, /* For interrupt flag */
int sync_flags, /* Flags to pass to OsSync() (or 0) */
int nBuf,
@@ -66110,6 +67203,8 @@ static int sqlite3WalClose(
if( pWal ){
int isDelete = 0; /* True to unlink wal and wal-index files */
+ assert( walAssertLockmask(pWal) );
+
/* If an EXCLUSIVE lock can be obtained on the database file (using the
** ordinary, rollback-mode locking methods, this guarantees that the
** connection associated with this log file is the only connection to
@@ -66124,8 +67219,8 @@ static int sqlite3WalClose(
if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
}
- rc = pWal->pMethods->xCheckpoint(pWal, db,
- SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
+ rc = sqlite3WalCheckpoint(pWal, db,
+ SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0, NULL, NULL
);
if( rc==SQLITE_OK ){
int bPersist = -1;
@@ -66134,7 +67229,7 @@ static int sqlite3WalClose(
);
if( bPersist!=1 ){
/* Try to delete the WAL file if the checkpoint completed and
- ** fsyned (rc==SQLITE_OK) and if we are not in persistent-wal
+ ** fsynced (rc==SQLITE_OK) and if we are not in persistent-wal
** mode (!bPersist) */
isDelete = 1;
}else if( pWal->mxWalSize>=0 ){
@@ -66201,7 +67296,7 @@ static SQLITE_NO_TSAN int walIndexTryHdr(Wal *pWal, int *pChanged){
** give false-positive warnings about these accesses because the tools do not
** account for the double-read and the memory barrier. The use of mutexes
** here would be problematic as the memory being accessed is potentially
- ** shared among multiple processes and not all mutex implementions work
+ ** shared among multiple processes and not all mutex implementations work
** reliably in that environment.
*/
aHdr = walIndexHdr(pWal);
@@ -66515,7 +67610,7 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){
pWal->apWiData[i] = 0;
}
pWal->bShmUnreliable = 0;
- pWal->pMethods->xEndReadTransaction(pWal);
+ sqlite3WalEndReadTransaction(pWal);
*pChanged = 1;
}
return rc;
@@ -66652,6 +67747,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
assert( pWal->nWiData>0 );
assert( pWal->apWiData[0]!=0 );
pInfo = walCkptInfo(pWal);
+ SEH_INJECT_FAULT;
if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame
#ifdef SQLITE_ENABLE_SNAPSHOT
&& (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
@@ -66701,7 +67797,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
}
#endif
for(i=1; iaReadMark+i);
+ u32 thisMark = AtomicLoad(pInfo->aReadMark+i); SEH_INJECT_FAULT;
if( mxReadMark<=thisMark && thisMark<=mxFrame ){
assert( thisMark!=READMARK_NOT_USED );
mxReadMark = thisMark;
@@ -66767,7 +67863,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
** we can guarantee that the checkpointer that set nBackfill could not
** see any pages past pWal->hdr.mxFrame, this problem does not come up.
*/
- pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1;
+ pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1; SEH_INJECT_FAULT;
walShmBarrier(pWal);
if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark
|| memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
@@ -66782,6 +67878,54 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
}
#ifdef SQLITE_ENABLE_SNAPSHOT
+/*
+** This function does the work of sqlite3WalSnapshotRecover().
+*/
+static int walSnapshotRecover(
+ Wal *pWal, /* WAL handle */
+ void *pBuf1, /* Temp buffer pWal->szPage bytes in size */
+ void *pBuf2 /* Temp buffer pWal->szPage bytes in size */
+){
+ int szPage = (int)pWal->szPage;
+ int rc;
+ i64 szDb; /* Size of db file in bytes */
+
+ rc = sqlite3OsFileSize(pWal->pDbFd, &szDb);
+ if( rc==SQLITE_OK ){
+ volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
+ u32 i = pInfo->nBackfillAttempted;
+ for(i=pInfo->nBackfillAttempted; i>AtomicLoad(&pInfo->nBackfill); i--){
+ WalHashLoc sLoc; /* Hash table location */
+ u32 pgno; /* Page number in db file */
+ i64 iDbOff; /* Offset of db file entry */
+ i64 iWalOff; /* Offset of wal file entry */
+
+ rc = walHashGet(pWal, walFramePage(i), &sLoc);
+ if( rc!=SQLITE_OK ) break;
+ assert( i - sLoc.iZero - 1 >=0 );
+ pgno = sLoc.aPgno[i-sLoc.iZero-1];
+ iDbOff = (i64)(pgno-1) * szPage;
+
+ if( iDbOff+szPage<=szDb ){
+ iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE;
+ rc = sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff);
+
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff);
+ }
+
+ if( rc!=SQLITE_OK || 0==memcmp(pBuf1, pBuf2, szPage) ){
+ break;
+ }
+ }
+
+ pInfo->nBackfillAttempted = i-1;
+ }
+ }
+
+ return rc;
+}
+
/*
** Attempt to reduce the value of the WalCkptInfo.nBackfillAttempted
** variable so that older snapshots can be accessed. To do this, loop
@@ -66807,50 +67951,21 @@ static int sqlite3WalSnapshotRecover(Wal *pWal){
assert( pWal->readLock>=0 );
rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
if( rc==SQLITE_OK ){
- volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
- int szPage = (int)pWal->szPage;
- i64 szDb; /* Size of db file in bytes */
-
- rc = sqlite3OsFileSize(pWal->pDbFd, &szDb);
- if( rc==SQLITE_OK ){
- void *pBuf1 = sqlite3_malloc(szPage);
- void *pBuf2 = sqlite3_malloc(szPage);
- if( pBuf1==0 || pBuf2==0 ){
- rc = SQLITE_NOMEM;
- }else{
- u32 i = pInfo->nBackfillAttempted;
- for(i=pInfo->nBackfillAttempted; i>AtomicLoad(&pInfo->nBackfill); i--){
- WalHashLoc sLoc; /* Hash table location */
- u32 pgno; /* Page number in db file */
- i64 iDbOff; /* Offset of db file entry */
- i64 iWalOff; /* Offset of wal file entry */
-
- rc = walHashGet(pWal, walFramePage(i), &sLoc);
- if( rc!=SQLITE_OK ) break;
- assert( i - sLoc.iZero - 1 >=0 );
- pgno = sLoc.aPgno[i-sLoc.iZero-1];
- iDbOff = (i64)(pgno-1) * szPage;
-
- if( iDbOff+szPage<=szDb ){
- iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE;
- rc = sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff);
-
- if( rc==SQLITE_OK ){
- rc = sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff);
- }
-
- if( rc!=SQLITE_OK || 0==memcmp(pBuf1, pBuf2, szPage) ){
- break;
- }
- }
-
- pInfo->nBackfillAttempted = i-1;
- }
+ void *pBuf1 = sqlite3_malloc(pWal->szPage);
+ void *pBuf2 = sqlite3_malloc(pWal->szPage);
+ if( pBuf1==0 || pBuf2==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ pWal->ckptLock = 1;
+ SEH_TRY {
+ rc = walSnapshotRecover(pWal, pBuf1, pBuf2);
}
-
- sqlite3_free(pBuf1);
- sqlite3_free(pBuf2);
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
+ pWal->ckptLock = 0;
}
+
+ sqlite3_free(pBuf1);
+ sqlite3_free(pBuf2);
walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
}
@@ -66859,23 +67974,14 @@ static int sqlite3WalSnapshotRecover(Wal *pWal){
#endif /* SQLITE_ENABLE_SNAPSHOT */
/*
-** Begin a read transaction on the database.
-**
-** This routine used to be called sqlite3OpenSnapshot() and with good reason:
-** it takes a snapshot of the state of the WAL and wal-index for the current
-** instant in time. The current thread will continue to use this snapshot.
-** Other threads might append new content to the WAL and wal-index but
-** that extra content is ignored by the current thread.
-**
-** If the database contents have changes since the previous read
-** transaction, then *pChanged is set to 1 before returning. The
-** Pager layer will use this to know that its cache is stale and
-** needs to be flushed.
+** This function does the work of sqlite3WalBeginReadTransaction() (see
+** below). That function simply calls this one inside an SEH_TRY{...} block.
*/
-static int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
+static int walBeginReadTransaction(Wal *pWal, int *pChanged){
int rc; /* Return code */
int cnt = 0; /* Number of TryBeginRead attempts */
#ifdef SQLITE_ENABLE_SNAPSHOT
+ int ckptLock = 0;
int bChanged = 0;
WalIndexHdr *pSnapshot = pWal->pSnapshot;
#endif
@@ -66903,7 +68009,7 @@ static int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
if( rc!=SQLITE_OK ){
return rc;
}
- pWal->ckptLock = 1;
+ ckptLock = 1;
}
#endif
@@ -66967,21 +68073,43 @@ static int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
}
/* Release the shared CKPT lock obtained above. */
- if( pWal->ckptLock ){
+ if( ckptLock ){
assert( pSnapshot );
walUnlockShared(pWal, WAL_CKPT_LOCK);
- pWal->ckptLock = 0;
}
#endif
return rc;
}
+/*
+** Begin a read transaction on the database.
+**
+** This routine used to be called sqlite3OpenSnapshot() and with good reason:
+** it takes a snapshot of the state of the WAL and wal-index for the current
+** instant in time. The current thread will continue to use this snapshot.
+** Other threads might append new content to the WAL and wal-index but
+** that extra content is ignored by the current thread.
+**
+** If the database contents have changes since the previous read
+** transaction, then *pChanged is set to 1 before returning. The
+** Pager layer will use this to know that its cache is stale and
+** needs to be flushed.
+*/
+static int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
+ int rc;
+ SEH_TRY {
+ rc = walBeginReadTransaction(pWal, pChanged);
+ }
+ SEH_EXCEPT( rc = walHandleException(pWal); )
+ return rc;
+}
+
/*
** Finish with a read transaction. All this does is release the
** read-lock.
*/
static void sqlite3WalEndReadTransaction(Wal *pWal){
- pWal->pMethods->xEndWriteTransaction(pWal);
+ sqlite3WalEndWriteTransaction(pWal);
if( pWal->readLock>=0 ){
walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
pWal->readLock = -1;
@@ -66996,13 +68124,13 @@ static void sqlite3WalEndReadTransaction(Wal *pWal){
** Return SQLITE_OK if successful, or an error code if an error occurs. If an
** error does occur, the final value of *piRead is undefined.
*/
-static int sqlite3WalFindFrame(
+static int walFindFrame(
Wal *pWal, /* WAL handle */
Pgno pgno, /* Database page number to read data for */
+ u32 iLast, /* Last page in WAL for this reader */
u32 *piRead /* OUT: Frame number (or zero) */
){
u32 iRead = 0; /* If !=0, WAL frame to return data from */
- u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */
int iHash; /* Used to loop through N hash tables */
int iMinHash;
@@ -67059,6 +68187,7 @@ static int sqlite3WalFindFrame(
}
nCollide = HASHTABLE_NSLOT;
iKey = walHash(pgno);
+ SEH_INJECT_FAULT;
while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){
u32 iFrame = iH + sLoc.iZero;
if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH-1]==pgno ){
@@ -67095,6 +68224,30 @@ static int sqlite3WalFindFrame(
return SQLITE_OK;
}
+/*
+** Search the wal file for page pgno. If found, set *piRead to the frame that
+** contains the page. Otherwise, if pgno is not in the wal file, set *piRead
+** to zero.
+**
+** Return SQLITE_OK if successful, or an error code if an error occurs. If an
+** error does occur, the final value of *piRead is undefined.
+**
+** The difference between this function and walFindFrame() is that this
+** function wraps walFindFrame() in an SEH_TRY{...} block.
+*/
+SQLITE_PRIVATE int sqlite3WalFindFrame(
+ Wal *pWal, /* WAL handle */
+ Pgno pgno, /* Database page number to read data for */
+ u32 *piRead /* OUT: Frame number (or zero) */
+){
+ int rc;
+ SEH_TRY {
+ rc = walFindFrame(pWal, pgno, pWal->hdr.mxFrame, piRead);
+ }
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
+ return rc;
+}
+
/*
** Read the contents of frame iRead from the wal file into buffer pOut
** (which is nOut bytes in size). Return SQLITE_OK if successful, or an
@@ -67176,12 +68329,17 @@ static int sqlite3WalBeginWriteTransaction(Wal *pWal){
** time the read transaction on this connection was started, then
** the write is disallowed.
*/
- if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
+ SEH_TRY {
+ if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
+ rc = SQLITE_BUSY_SNAPSHOT;
+ }
+ }
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
+
+ if( rc!=SQLITE_OK ){
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
pWal->writeLock = 0;
- rc = SQLITE_BUSY_SNAPSHOT;
}
-
return rc;
}
@@ -67217,30 +68375,33 @@ static int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx)
Pgno iMax = pWal->hdr.mxFrame;
Pgno iFrame;
- /* Restore the clients cache of the wal-index header to the state it
- ** was in before the client began writing to the database.
- */
- memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr));
-
- for(iFrame=pWal->hdr.mxFrame+1;
- ALWAYS(rc==SQLITE_OK) && iFrame<=iMax;
- iFrame++
- ){
- /* This call cannot fail. Unless the page for which the page number
- ** is passed as the second argument is (a) in the cache and
- ** (b) has an outstanding reference, then xUndo is either a no-op
- ** (if (a) is false) or simply expels the page from the cache (if (b)
- ** is false).
- **
- ** If the upper layer is doing a rollback, it is guaranteed that there
- ** are no outstanding references to any page other than page 1. And
- ** page 1 is never written to the log until the transaction is
- ** committed. As a result, the call to xUndo may not fail.
+ SEH_TRY {
+ /* Restore the clients cache of the wal-index header to the state it
+ ** was in before the client began writing to the database.
*/
- assert( walFramePgno(pWal, iFrame)!=1 );
- rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
+ memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr));
+
+ for(iFrame=pWal->hdr.mxFrame+1;
+ ALWAYS(rc==SQLITE_OK) && iFrame<=iMax;
+ iFrame++
+ ){
+ /* This call cannot fail. Unless the page for which the page number
+ ** is passed as the second argument is (a) in the cache and
+ ** (b) has an outstanding reference, then xUndo is either a no-op
+ ** (if (a) is false) or simply expels the page from the cache (if (b)
+ ** is false).
+ **
+ ** If the upper layer is doing a rollback, it is guaranteed that there
+ ** are no outstanding references to any page other than page 1. And
+ ** page 1 is never written to the log until the transaction is
+ ** committed. As a result, the call to xUndo may not fail.
+ */
+ assert( walFramePgno(pWal, iFrame)!=1 );
+ rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
+ }
+ if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
}
- if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
}
return rc;
}
@@ -67284,7 +68445,10 @@ static int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
pWal->hdr.mxFrame = aWalData[0];
pWal->hdr.aFrameCksum[0] = aWalData[1];
pWal->hdr.aFrameCksum[1] = aWalData[2];
- walCleanupHash(pWal);
+ SEH_TRY {
+ walCleanupHash(pWal);
+ }
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
}
return rc;
@@ -67302,10 +68466,12 @@ static int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
** or not pWal->hdr.mxFrame is modified). An SQLite error code is returned
** if an error occurs.
*/
-static int walRestartLog(Wal *pWal){
+static int walRestartLog(Wal *pWal, int *pRestarted){
int rc = SQLITE_OK;
int cnt;
+ *pRestarted = 0;
+
if( pWal->readLock==0 ){
volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
assert( pInfo->nBackfill==pWal->hdr.mxFrame );
@@ -67325,6 +68491,7 @@ static int walRestartLog(Wal *pWal){
** to handle if this transaction is rolled back. */
walRestartHdr(pWal, salt1);
walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
+ *pRestarted = 1;
}else if( rc!=SQLITE_BUSY ){
return rc;
}
@@ -67400,6 +68567,9 @@ static int walWriteOneFrame(
void *pData; /* Data actually written */
u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
pData = pPage->pData;
+ rc = libsql_pager_codec(pPage, &pData);
+ if( rc ) return rc;
+
walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame);
rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset);
if( rc ) return rc;
@@ -67465,13 +68635,14 @@ static int walRewriteChecksums(Wal *pWal, u32 iLast){
** Write a set of frames to the log. The caller must hold the write-lock
** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
*/
-static int sqlite3WalFrames(
+static int walFrames(
Wal *pWal, /* Wal handle to write to */
int szPage, /* Database page-size in bytes */
PgHdr *pList, /* List of dirty pages to write */
Pgno nTruncate, /* Database size after this commit */
int isCommit, /* True if this is a commit */
- int sync_flags /* Flags to pass to OsSync() (or 0) */
+ int sync_flags, /* Flags to pass to OsSync() (or 0) */
+ int *pnFrames /* Number of frames written to the wal in the transaction. 0 for non-commit call*/
){
int rc; /* Used to catch return codes */
u32 iFrame; /* Next frame address */
@@ -67483,6 +68654,7 @@ static int sqlite3WalFrames(
WalWriter w; /* The writer */
u32 iFirst = 0; /* First frame that may be overwritten */
WalIndexHdr *pLive; /* Pointer to shared header */
+ int walRestarted; /* Whether the wal was restarted */
assert( pList );
assert( pWal->writeLock );
@@ -67506,7 +68678,7 @@ static int sqlite3WalFrames(
/* See if it is possible to write these frames into the start of the
** log file, instead of appending to it at pWal->hdr.mxFrame.
*/
- if( SQLITE_OK!=(rc = walRestartLog(pWal)) ){
+ if( SQLITE_OK!=(rc = walRestartLog(pWal, &walRestarted)) ){
return rc;
}
@@ -67553,7 +68725,9 @@ static int sqlite3WalFrames(
if( rc ) return rc;
}
}
- assert( (int)pWal->szPage==szPage );
+ if( (int)pWal->szPage!=szPage ){
+ return SQLITE_CORRUPT_BKPT; /* TH3 test case: cov1/corrupt155.test */
+ }
/* Setup information needed to write frames into the WAL */
w.pWal = pWal;
@@ -67574,7 +68748,7 @@ static int sqlite3WalFrames(
** checksums must be recomputed when the transaction is committed. */
if( iFirst && (p->pDirty || isCommit==0) ){
u32 iWrite = 0;
- VVA_ONLY(rc =) pWal->pMethods->xFindFrame(pWal, p->pgno, &iWrite);
+ VVA_ONLY(rc =) sqlite3WalFindFrame(pWal, p->pgno, &iWrite);
assert( rc==SQLITE_OK || iWrite==0 );
if( iWrite>=iFirst ){
i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE;
@@ -67582,7 +68756,9 @@ static int sqlite3WalFrames(
if( pWal->iReCksum==0 || iWriteiReCksum ){
pWal->iReCksum = iWrite;
}
- pData = p->pData;
+
+ rc = libsql_pager_codec(p, &pData);
+ if( rc ) return rc;
rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff);
if( rc ) return rc;
p->flags &= ~PGHDR_WAL_APPEND;
@@ -67677,6 +68853,17 @@ static int sqlite3WalFrames(
pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
testcase( szPage<=32768 );
testcase( szPage>=65536 );
+ if (pnFrames) {
+ if (isCommit) {
+ if (walRestarted) {
+ *pnFrames = iFrame;
+ } else {
+ *pnFrames = iFrame - pWal->hdr.mxFrame;
+ }
+ } else {
+ *pnFrames = 0;
+ }
+ }
pWal->hdr.mxFrame = iFrame;
if( isCommit ){
pWal->hdr.iChange++;
@@ -67693,6 +68880,30 @@ static int sqlite3WalFrames(
return rc;
}
+/*
+** Write a set of frames to the log. The caller must hold the write-lock
+** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
+**
+** The difference between this function and walFrames() is that this
+** function wraps walFrames() in an SEH_TRY{...} block.
+*/
+SQLITE_PRIVATE int sqlite3WalFrames(
+ Wal *pWal, /* Wal handle to write to */
+ int szPage, /* Database page-size in bytes */
+ PgHdr *pList, /* List of dirty pages to write */
+ Pgno nTruncate, /* Database size after this commit */
+ int isCommit, /* True if this is a commit */
+ int sync_flags, /* Flags to pass to OsSync() (or 0) */
+ int *pnFrames /* OUT: Number of frames appended to the wal on commit */
+){
+ int rc;
+ SEH_TRY {
+ rc = walFrames(pWal, szPage, pList, nTruncate, isCommit, sync_flags, pnFrames);
+ }
+ SEH_EXCEPT( rc = walHandleException(pWal); )
+ return rc;
+}
+
/*
** This routine is called to implement sqlite3_wal_checkpoint() and
** related interfaces.
@@ -67704,7 +68915,7 @@ static int sqlite3WalFrames(
** callback. In this case this function runs a blocking checkpoint.
*/
static int sqlite3WalCheckpoint(
- Wal *pWal, /* Wal connection */
+ Wal *pWal, /* Wal connection */
sqlite3 *db, /* Check this handle's interrupt flag */
int eMode, /* PASSIVE, FULL, RESTART, or TRUNCATE */
int (*xBusy)(void*), /* Function to call when busy */
@@ -67713,7 +68924,9 @@ static int sqlite3WalCheckpoint(
int nBuf, /* Size of temporary buffer */
u8 *zBuf, /* Temporary buffer to use */
int *pnLog, /* OUT: Number of frames in WAL */
- int *pnCkpt /* OUT: Number of backfilled frames in WAL */
+ int *pnCkpt, /* OUT: Number of backfilled frames in WAL */
+ int (*xCb)(void*, int, const unsigned char*, int, int, int), /* page, page_no, frame_no */
+ void *pCbData
){
int rc; /* Return code */
int isChanged = 0; /* True if a new wal-index header is loaded */
@@ -67732,7 +68945,7 @@ static int sqlite3WalCheckpoint(
/* Enable blocking locks, if possible. If blocking locks are successfully
** enabled, set xBusy2=0 so that the busy-handler is never invoked. */
- pWal->pMethods->xDb(pWal, db);
+ sqlite3WalDb(pWal, db);
(void)walEnableBlocking(pWal);
/* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
@@ -67772,30 +68985,33 @@ static int sqlite3WalCheckpoint(
/* Read the wal-index header. */
- if( rc==SQLITE_OK ){
- walDisableBlocking(pWal);
- rc = walIndexReadHdr(pWal, &isChanged);
- (void)walEnableBlocking(pWal);
- if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
- sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
+ SEH_TRY {
+ if( rc==SQLITE_OK ){
+ walDisableBlocking(pWal);
+ rc = walIndexReadHdr(pWal, &isChanged);
+ (void)walEnableBlocking(pWal);
+ if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
+ sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
+ }
}
- }
-
- /* Copy data from the log to the database file. */
- if( rc==SQLITE_OK ){
- if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
- rc = SQLITE_CORRUPT_BKPT;
- }else{
- rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
- }
+ /* Copy data from the log to the database file. */
+ if( rc==SQLITE_OK ){
+ if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
+ rc = SQLITE_CORRUPT_BKPT;
+ }else{
+ rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags,zBuf, pCbData, xCb);
+ }
- /* If no error occurred, set the output variables. */
- if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
- if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
- if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
+ /* If no error occurred, set the output variables. */
+ if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
+ if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
+ SEH_INJECT_FAULT;
+ if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
+ }
}
}
+ SEH_EXCEPT( rc = walHandleException(pWal); )
if( isChanged ){
/* If a new wal-index header was loaded before the checkpoint was
@@ -67808,10 +69024,10 @@ static int sqlite3WalCheckpoint(
}
walDisableBlocking(pWal);
- pWal->pMethods->xDb(pWal, 0);
+ sqlite3WalDb(pWal, 0);
/* Release the locks. */
- pWal->pMethods->xEndWriteTransaction(pWal);
+ sqlite3WalEndWriteTransaction(pWal);
if( pWal->ckptLock ){
walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
pWal->ckptLock = 0;
@@ -67947,7 +69163,7 @@ static void sqlite3WalSnapshotOpen(
** Return a +ve value if snapshot p1 is newer than p2. A -ve value if
** p1 is older than p2 and zero if p1 and p2 are the same snapshot.
*/
-static int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){
+SQLITE_API int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){
WalIndexHdr *pHdr1 = (WalIndexHdr*)p1;
WalIndexHdr *pHdr2 = (WalIndexHdr*)p2;
@@ -67973,16 +69189,19 @@ static int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){
*/
static int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot){
int rc;
- rc = walLockShared(pWal, WAL_CKPT_LOCK);
- if( rc==SQLITE_OK ){
- WalIndexHdr *pNew = (WalIndexHdr*)pSnapshot;
- if( memcmp(pNew->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
- || pNew->mxFramenBackfillAttempted
- ){
- rc = SQLITE_ERROR_SNAPSHOT;
- walUnlockShared(pWal, WAL_CKPT_LOCK);
+ SEH_TRY {
+ rc = walLockShared(pWal, WAL_CKPT_LOCK);
+ if( rc==SQLITE_OK ){
+ WalIndexHdr *pNew = (WalIndexHdr*)pSnapshot;
+ if( memcmp(pNew->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
+ || pNew->mxFramenBackfillAttempted
+ ){
+ rc = SQLITE_ERROR_SNAPSHOT;
+ walUnlockShared(pWal, WAL_CKPT_LOCK);
+ }
}
}
+ SEH_EXCEPT( rc = walHandleException(pWal); )
return rc;
}
@@ -68025,150 +69244,244 @@ static void libsqlGetWalPathname(char *buf, const char *orig, int orig_len) {
memcpy(buf + orig_len, "-wal", 4);
}
-static int libsqlPreMainDbOpen(struct libsql_wal_methods *methods, const char *main_db_path) {
- return SQLITE_OK;
+SQLITE_PRIVATE int sqlite3LogExists(wal_manager_impl* self, sqlite3_vfs *vfs, const char *main_db_path_name, int *exists) {
+ const char *zWal = sqlite3_filename_wal(main_db_path_name);
+ int rc = sqlite3OsAccess(vfs, zWal, SQLITE_ACCESS_EXISTS, exists);
+ return rc;
}
-libsql_wal_methods *libsql_wal_methods_find(const char *zName) {
- static libsql_wal_methods methods;
- static libsql_wal_methods *methods_head = NULL;
+SQLITE_PRIVATE int sqlite3LogDestroy(wal_manager_impl* self, sqlite3_vfs *vfs, const char *main_db_path_name) {
+ const char *zWal = sqlite3_filename_wal(main_db_path_name);
+ int rc = sqlite3OsDelete(vfs, zWal, 0);
+ return rc;
+}
-#ifndef SQLITE_OMIT_AUTOINIT
- int rc = sqlite3_initialize();
- if (rc != SQLITE_OK) {
- return NULL;
- }
+/*
+** Open a connection to the WAL file zWalName. The database file must
+** already be opened on connection pDbFd. The buffer that zWalName points
+** to must remain valid for the lifetime of the returned Wal* handle.
+**
+** Custom virtual methods may be provided via the pMethods parameter.
+**
+** A SHARED lock should be held on the database file when this function
+** is called. The purpose of this SHARED lock is to prevent any other
+** client from unlinking the WAL or wal-index file. If another process
+** were to do this just after this client opened one of these files, the
+** system would be badly broken.
+**
+** If the log file is successfully opened, SQLITE_OK is returned and
+** *ppWal is set to point to a new WAL handle. If an error occurs,
+** an SQLite error code is returned and *ppWal is left unmodified.
+*/
+static int sqlite3WalOpen(
+ wal_manager_impl *self,
+ sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */
+ sqlite3_file *pDbFd, /* The open database file */
+ int bNoShm, /* True to run in heap-memory mode */
+ i64 mxWalSize, /* Truncate WAL to this size on reset */
+ const char* main_db_file_name,
+ libsql_wal *out /* OUT: Allocated Wal handle */
+){
+ int rc; /* Return Code */
+ Wal *pRet; /* Object to allocate and return */
+ int flags; /* Flags passed to OsOpen() */
+
+ assert( pDbFd );
+
+ /* Verify the values of various constants. Any changes to the values
+ ** of these constants would result in an incompatible on-disk format
+ ** for the -shm file. Any change that causes one of these asserts to
+ ** fail is a backward compatibility problem, even if the change otherwise
+ ** works.
+ **
+ ** This table also serves as a helpful cross-reference when trying to
+ ** interpret hex dumps of the -shm file.
+ */
+ assert( 48 == sizeof(WalIndexHdr) );
+ assert( 40 == sizeof(WalCkptInfo) );
+ assert( 120 == WALINDEX_LOCK_OFFSET );
+ assert( 136 == WALINDEX_HDR_SIZE );
+ assert( 4096 == HASHTABLE_NPAGE );
+ assert( 4062 == HASHTABLE_NPAGE_ONE );
+ assert( 8192 == HASHTABLE_NSLOT );
+ assert( 383 == HASHTABLE_HASH_1 );
+ assert( 32768 == WALINDEX_PGSZ );
+ assert( 8 == SQLITE_SHM_NLOCK );
+ assert( 5 == WAL_NREADER );
+ assert( 24 == WAL_FRAME_HDRSIZE );
+ assert( 32 == WAL_HDRSIZE );
+ assert( 120 == WALINDEX_LOCK_OFFSET + WAL_WRITE_LOCK );
+ assert( 121 == WALINDEX_LOCK_OFFSET + WAL_CKPT_LOCK );
+ assert( 122 == WALINDEX_LOCK_OFFSET + WAL_RECOVER_LOCK );
+ assert( 123 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(0) );
+ assert( 124 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(1) );
+ assert( 125 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(2) );
+ assert( 126 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(3) );
+ assert( 127 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(4) );
+
+ /* In the amalgamation, the os_unix.c and os_win.c source files come before
+ ** this source file. Verify that the #defines of the locking byte offsets
+ ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value.
+ ** For that matter, if the lock offset ever changes from its initial design
+ ** value of 120, we need to know that so there is an assert() to check it.
+ */
+#ifdef WIN_SHM_BASE
+ assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET );
+#endif
+#ifdef UNIX_SHM_BASE
+ assert( UNIX_SHM_BASE==WALINDEX_LOCK_OFFSET );
#endif
- if (!zName || *zName == '\0') {
- zName = "default";
- }
- if (methods_head == NULL && strncmp(zName, "default", 7) == 0) {
- methods.iVersion = 1;
- methods.xOpen = sqlite3WalOpen;
- methods.xClose = sqlite3WalClose;
- methods.xLimit = sqlite3WalLimit;
- methods.xBeginReadTransaction = sqlite3WalBeginReadTransaction;
- methods.xEndReadTransaction = sqlite3WalEndReadTransaction;
- methods.xFindFrame = sqlite3WalFindFrame;
- methods.xReadFrame = sqlite3WalReadFrame;
- methods.xDbsize = sqlite3WalDbsize;
- methods.xBeginWriteTransaction = sqlite3WalBeginWriteTransaction;
- methods.xEndWriteTransaction = sqlite3WalEndWriteTransaction;
- methods.xUndo = sqlite3WalUndo;
- methods.xSavepoint = sqlite3WalSavepoint;
- methods.xSavepointUndo = sqlite3WalSavepointUndo;
- methods.xFrames = sqlite3WalFrames;
- methods.xCheckpoint = sqlite3WalCheckpoint;
- methods.xCallback = sqlite3WalCallback;
- methods.xExclusiveMode = sqlite3WalExclusiveMode;
- methods.xHeapMemory = sqlite3WalHeapMemory;
+ const char *zWalName = sqlite3_filename_wal(main_db_file_name);
+
+ /* Allocate an instance of struct Wal to return. */
+ pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile);
+ if( !pRet ){
+ return SQLITE_NOMEM_BKPT;
+ }
+
+ pRet->pVfs = pVfs;
+ pRet->pWalFd = (sqlite3_file *)&pRet[1];
+ pRet->pDbFd = pDbFd;
+ pRet->readLock = -1;
+ pRet->mxWalSize = mxWalSize;
+ pRet->zWalName = zWalName;
+ pRet->syncHeader = 1;
+ pRet->padToSectorBoundary = 1;
+ pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);
+
+ /* Open file handle on the write-ahead log file. */
+ flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
+ rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags);
+ if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){
+ pRet->readOnly = WAL_RDONLY;
+ }
+
+ if( rc!=SQLITE_OK ){
+ walIndexClose(pRet, 0);
+ sqlite3OsClose(pRet->pWalFd);
+ sqlite3_free(pRet);
+ }else{
+ int iDC = sqlite3OsDeviceCharacteristics(pDbFd);
+ if( iDC & SQLITE_IOCAP_SEQUENTIAL ){ pRet->syncHeader = 0; }
+ if( iDC & SQLITE_IOCAP_POWERSAFE_OVERWRITE ){
+ pRet->padToSectorBoundary = 0;
+ }
+ out->pData = (wal_impl*) pRet;
+ out->methods.iVersion = 1;
+ out->methods.xLimit = (void (*)(wal_impl *, long long))sqlite3WalLimit;
+ out->methods.xBeginReadTransaction = (int (*)(wal_impl *, int *))sqlite3WalBeginReadTransaction;
+ out->methods.xEndReadTransaction = (void (*)(wal_impl *))sqlite3WalEndReadTransaction;
+ out->methods.xFindFrame = (int (*)(wal_impl *, unsigned int, unsigned int *))sqlite3WalFindFrame;
+ out->methods.xReadFrame = (int (*)(wal_impl *, unsigned int, int, unsigned char *))sqlite3WalReadFrame;
+ out->methods.xDbsize = (unsigned int (*)(wal_impl *))sqlite3WalDbsize;
+ out->methods.xBeginWriteTransaction = (int (*)(wal_impl *))sqlite3WalBeginWriteTransaction;
+ out->methods.xEndWriteTransaction = (int (*)(wal_impl *))sqlite3WalEndWriteTransaction;
+ out->methods.xUndo = (int (*)(wal_impl *, int (*)(void *, unsigned int), void *))sqlite3WalUndo;
+ out->methods.xSavepoint = (void (*)(wal_impl *, unsigned int *))sqlite3WalSavepoint;
+ out->methods.xSavepointUndo = (int (*)(wal_impl *, unsigned int *))sqlite3WalSavepointUndo;
+ out->methods.xFrames = (int (*)(wal_impl *, int, libsql_pghdr *, unsigned int, int, int, int *))sqlite3WalFrames;
+ out->methods.xCheckpoint = (int (*)(wal_impl *, sqlite3 *, int, int (*)(void *), void *, int, int, unsigned char *, int *, int *, int (*)(void*, int, const unsigned char*, int, int, int), void*))sqlite3WalCheckpoint;
+ out->methods.xCallback = (int (*)(wal_impl *))sqlite3WalCallback;
+ out->methods.xExclusiveMode = (int (*)(wal_impl *, int))sqlite3WalExclusiveMode;
+ out->methods.xHeapMemory = (int (*)(wal_impl *))sqlite3WalHeapMemory;
#ifdef SQLITE_ENABLE_SNAPSHOT
- methods.xSnapshotGet = sqlite3WalSnapshotGet;
- methods.xSnapshotOpen = sqlite3WalSnapshotOpen;
- methods.xSnapshotRecover = sqlite3WalSnapshotRecover;
- methods.xSnapshotCheck = sqlite3WalSnapshotCheck;
- methods.xSnapshotUnlock = sqlite3WalSnapshotUnlock;
+ out->methods.xSnapshotGet = sqlite3WalSnapshotGet;
+ out->methods.xSnapshotOpen = sqlite3WalSnapshotOpen;
+ out->methods.xSnapshotRecover = sqlite3WalSnapshotRecover;
+ out->methods.xSnapshotCheck = sqlite3WalSnapshotCheck;
+ out->methods.xSnapshotUnlock = sqlite3WalSnapshotUnlock;
#endif
#ifdef SQLITE_ENABLE_ZIPVFS
- methods.xFramesize = sqlite3WalFramesize;
+ outWal->methods.xFramesize = sqlite3WalFramesize;
#endif
- methods.xFile = sqlite3WalFile;
+ out->methods.xFile = (sqlite3_file *(*)(wal_impl *))sqlite3WalFile;
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
- methods.xWriteLock = sqlite3WalWriteLock;
+ outWal->methods.xWriteLock = sqlite3WalWriteLock;
#endif
- methods.xDb = sqlite3WalDb;
- methods.xPathnameLen = libsqlWalPathnameLen;
- methods.xGetWalPathname = libsqlGetWalPathname;
- methods.xPreMainDbOpen = libsqlPreMainDbOpen;
-
- methods.bUsesShm = 1;
- methods.zName = "default";
- methods.pNext = NULL;
- methods_head = &methods;
+ out->methods.xDb = (void (*)(wal_impl *, sqlite3 *))sqlite3WalDb;
- return methods_head;
- }
-
- // Look up in the methods table
- for (libsql_wal_methods *m = methods_head; m != NULL; m = m->pNext) {
- if (m && strcmp(zName, m->zName) == 0) {
- return m;
- }
+ WALTRACE(("WAL%d: opened\n", pRet));
}
- return NULL;
+ return rc;
}
-int libsql_wal_methods_register(libsql_wal_methods* pWalMethods) {
-#ifndef SQLITE_OMIT_AUTOINIT
- int rc = sqlite3_initialize();
- if (rc != SQLITE_OK) {
- return rc;
- }
-#endif
-
- if (strncmp(pWalMethods->zName, "default", 7) == 0) {
- return SQLITE_MISUSE;
- }
- MUTEX_LOGIC(sqlite3_mutex *mutex;)
- MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
- sqlite3_mutex_enter(mutex);
+SQLITE_PRIVATE void sqlite3DestroyWalManager(wal_manager_impl *self) { }
- libsql_wal_methods *prev = libsql_wal_methods_find("default");
- libsql_wal_methods *m = prev->pNext;
+int make_ref_counted_wal_manager(libsql_wal_manager wal_manager, RefCountedWalManager **out) {
+ RefCountedWalManager *p = (RefCountedWalManager*)sqlite3MallocZero(sizeof(RefCountedWalManager));
+ if (!p) return SQLITE_NOMEM;
+ p->n = 1;
+ p->ref = wal_manager;
+ p->is_static = 0;
+ *out = p;
+ return SQLITE_OK;
+}
- while (1) {
- if (m == NULL) {
- prev->pNext = pWalMethods;
- pWalMethods->pNext = NULL;
- break;
- }
- if (strcmp(m->zName, pWalMethods->zName) == 0) {
- prev->pNext = pWalMethods;
- pWalMethods->pNext = m->pNext;
- break;
+/*
+ * Decrease the ref count and call the wal_manager destructor when the count reaches 0.
+ * Must be called from withing a critical section.
+ */
+void destroy_wal_manager(RefCountedWalManager *p) {
+ if (p->is_static) return;
+ assert(p->n != 0);
+ p->n -= 1;
+ if (p->n == 0) {
+ (p->ref.xDestroy)(p->ref.pData);
+ sqlite3_free(p);
}
- prev = m;
- m = m->pNext;
- }
- sqlite3_mutex_leave(mutex);
- return SQLITE_OK;
}
-int libsql_wal_methods_unregister(libsql_wal_methods *pWalMethods) {
- if (strncmp(pWalMethods->zName, "default", 7) == 0) {
- return SQLITE_MISUSE;
- }
- MUTEX_LOGIC(sqlite3_mutex *mutex;)
- MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
- sqlite3_mutex_enter(mutex);
+/*
+ * Increase the ref count and return a pointer to the wal.
+ * Must be called from withing a critical section.
+ * Return NULL if the passed pointer ref count is already 0.
+ */
+RefCountedWalManager* clone_wal_manager(RefCountedWalManager *p) {
+ assert(p->n != 0);
+ p->n += 1;
+ return p;
+}
- libsql_wal_methods *prev = libsql_wal_methods_find("default");
- libsql_wal_methods *m = prev->pNext;
+SQLITE_API const libsql_wal_manager sqlite3_wal_manager = {
+ .pData = NULL,
+ .xOpen = (int (*)(wal_manager_impl *, sqlite3_vfs *, sqlite3_file *, int, long long, const char*, libsql_wal *))sqlite3WalOpen,
+ .xClose = (int (*)(wal_manager_impl *, wal_impl *, sqlite3 *, int, int, unsigned char *))sqlite3WalClose,
+ .bUsesShm = 1,
+ .xLogDestroy = (int (*)(wal_manager_impl *, sqlite3_vfs*, const char*))sqlite3LogDestroy,
+ .xLogExists = (int (*)(wal_manager_impl *, sqlite3_vfs*, const char*, int *))sqlite3LogExists,
+ .xDestroy =(void (*)(wal_manager_impl*))sqlite3DestroyWalManager,
+};
- while (m != NULL) {
- if (strcmp(m->zName, pWalMethods->zName) == 0) {
- prev->pNext = m->pNext;
- break;
+RefCountedWalManager *make_sqlite3_wal_manager_rc() {
+ static int initialized = 0;
+ static RefCountedWalManager manager = { 0 };
+ /*
+ * re-initializing is idempotent
+ */
+ if (!initialized) {
+ manager.is_static = 1;
+ manager.ref = sqlite3_wal_manager;
+ manager.n = 1;
+ initialized = 1;
}
- prev = m;
- m = m->pNext;
- }
- sqlite3_mutex_leave(mutex);
- return SQLITE_OK;
+
+ return &manager;
}
-libsql_wal_methods *libsql_wal_methods_next(libsql_wal_methods *w) {
- return w->pNext;
+typedef struct wal_impl wal_impl;
+
+SQLITE_API int sqlite3_wal_backfilled(sqlite3_wal *pWal) {
+ return walCkptInfo(pWal)->nBackfill;
}
-const char *libsql_wal_methods_name(libsql_wal_methods *w) {
- return w->zName;
+SQLITE_API u32 sqlite3_wal_frame_page_no(sqlite3_wal *pWal, u32 iFrame) {
+ return walFramePgno(pWal, iFrame);
}
#endif /* #ifndef SQLITE_OMIT_WAL */
@@ -68368,7 +69681,7 @@ const char *libsql_wal_methods_name(libsql_wal_methods *w) {
** byte are used. The integer consists of all bytes that have bit 8 set and
** the first byte with bit 8 clear. The most significant byte of the integer
** appears first. A variable-length integer may not be more than 9 bytes long.
-** As a special case, all 8 bytes of the 9th byte are used as data. This
+** As a special case, all 8 bits of the 9th byte are used as data. This
** allows a 64-bit integer to be encoded in 9 bytes.
**
** 0x00 becomes 0x00000000
@@ -68376,7 +69689,7 @@ const char *libsql_wal_methods_name(libsql_wal_methods *w) {
** 0x81 0x00 becomes 0x00000080
** 0x82 0x00 becomes 0x00000100
** 0x80 0x7f becomes 0x0000007f
-** 0x8a 0x91 0xd1 0xac 0x78 becomes 0x12345678
+** 0x81 0x91 0xd1 0xac 0x78 becomes 0x12345678
** 0x81 0x81 0x81 0x81 0x01 becomes 0x10204081
**
** Variable length integers are used for rowids and to hold the number of
@@ -68459,7 +69772,7 @@ typedef struct CellInfo CellInfo;
** page that has been loaded into memory. The information in this object
** is derived from the raw on-disk page content.
**
-** As each database page is loaded into memory, the pager allocats an
+** As each database page is loaded into memory, the pager allocates an
** instance of this object and zeros the first 8 bytes. (This is the
** "extra" information associated with each page of the pager.)
**
@@ -68752,7 +70065,7 @@ struct BtCursor {
#define BTCF_WriteFlag 0x01 /* True if a write cursor */
#define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */
#define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */
-#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */
+#define BTCF_AtLast 0x08 /* Cursor is pointing to the last entry */
#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */
#define BTCF_Multiple 0x20 /* Maybe another cursor on the same btree */
#define BTCF_Pinned 0x40 /* Cursor is busy and cannot be moved */
@@ -68891,14 +70204,15 @@ struct IntegrityCk {
BtShared *pBt; /* The tree being checked out */
Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
u8 *aPgRef; /* 1 bit per page in the db (see above) */
- Pgno nPage; /* Number of pages in the database */
+ Pgno nCkPage; /* Pages in the database. 0 for partial check */
int mxErr; /* Stop accumulating errors when this reaches zero */
int nErr; /* Number of messages written to zErrMsg so far */
int rc; /* SQLITE_OK, SQLITE_NOMEM, or SQLITE_INTERRUPT */
u32 nStep; /* Number of steps into the integrity_check process */
const char *zPfx; /* Error message prefix */
- Pgno v1; /* Value for first %u substitution in zPfx */
- int v2; /* Value for second %d substitution in zPfx */
+ Pgno v0; /* Value for first %u substitution in zPfx (root page) */
+ Pgno v1; /* Value for second %u substitution in zPfx (current pg) */
+ int v2; /* Value for third %d substitution in zPfx */
StrAccum errMsg; /* Accumulate the error message text here */
u32 *heap; /* Min-heap used for analyzing cell coverage */
sqlite3 *db; /* Database connection running the check */
@@ -68914,7 +70228,7 @@ struct IntegrityCk {
/*
** get2byteAligned(), unlike get2byte(), requires that its argument point to a
-** two-byte aligned address. get2bytea() is only used for accessing the
+** two-byte aligned address. get2byteAligned() is only used for accessing the
** cell addresses in a btree header.
*/
#if SQLITE_BYTEORDER==4321
@@ -69091,7 +70405,7 @@ SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree *p){
**
** There is a corresponding leave-all procedures.
**
-** Enter the mutexes in accending order by BtShared pointer address
+** Enter the mutexes in ascending order by BtShared pointer address
** to avoid the possibility of deadlock when two threads with
** two or more btrees in common both try to lock all their btrees
** at the same instant.
@@ -69361,8 +70675,8 @@ SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){
int corruptPageError(int lineno, MemPage *p){
char *zMsg;
sqlite3BeginBenignMalloc();
- zMsg = sqlite3_mprintf("database corruption page %d of %s",
- (int)p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0)
+ zMsg = sqlite3_mprintf("database corruption page %u of %s",
+ p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0)
);
sqlite3EndBenignMalloc();
if( zMsg ){
@@ -70171,8 +71485,25 @@ SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow)
*/
SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor *pCur, int eHintType, ...){
/* Used only by system that substitute their own storage engine */
+#ifdef SQLITE_DEBUG
+ if( ALWAYS(eHintType==BTREE_HINT_RANGE) ){
+ va_list ap;
+ Expr *pExpr;
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = sqlite3CursorRangeHintExprCheck;
+ va_start(ap, eHintType);
+ pExpr = va_arg(ap, Expr*);
+ w.u.aMem = va_arg(ap, Mem*);
+ va_end(ap);
+ assert( pExpr!=0 );
+ assert( w.u.aMem!=0 );
+ sqlite3WalkExpr(&w, pExpr);
+ }
+#endif /* SQLITE_DEBUG */
}
-#endif
+#endif /* SQLITE_ENABLE_CURSOR_HINTS */
+
/*
** Provide flag hints to the cursor.
@@ -70257,7 +71588,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);
if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
- TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent));
+ TRACE(("PTRMAP_UPDATE: %u->(%u,%u)\n", key, eType, parent));
*pRC= rc = sqlite3PagerWrite(pDbPage);
if( rc==SQLITE_OK ){
pPtrmap[offset] = eType;
@@ -70741,7 +72072,7 @@ static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){
pPage->xParseCell(pPage, pCell, &info);
if( info.nLocalaDataEnd, pCell, pCell+info.nLocal) ){
+ if( SQLITE_OVERFLOW(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){
testcase( pSrc!=pPage );
*pRC = SQLITE_CORRUPT_BKPT;
return;
@@ -70842,7 +72173,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
iCellStart = get2byte(&data[hdr+5]);
if( nCell>0 ){
temp = sqlite3PagerTempSpace(pPage->pBt->pPager);
- memcpy(&temp[iCellStart], &data[iCellStart], usableSize - iCellStart);
+ memcpy(temp, data, usableSize);
src = temp;
for(i=0; ihdrOffset; /* Local cache of pPage->hdrOffset */
u8 * const data = pPage->aData; /* Local cache of pPage->aData */
int top; /* First byte of cell content area */
@@ -70997,13 +72328,14 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
** integer, so a value of 0 is used in its place. */
pTmp = &data[hdr+5];
top = get2byte(pTmp);
- assert( top<=(int)pPage->pBt->usableSize ); /* by btreeComputeFreeSpace() */
if( gap>top ){
if( top==0 && pPage->pBt->usableSize==65536 ){
top = 65536;
}else{
return SQLITE_CORRUPT_PAGE(pPage);
}
+ }else if( top>(int)pPage->pBt->usableSize ){
+ return SQLITE_CORRUPT_PAGE(pPage);
}
/* If there is enough space between gap and top for one more cell pointer,
@@ -71065,7 +72397,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
**
** Even though the freeblock list was checked by btreeComputeFreeSpace(),
** that routine will not detect overlap between cells or freeblocks. Nor
-** does it detect cells or freeblocks that encrouch into the reserved bytes
+** does it detect cells or freeblocks that encroach into the reserved bytes
** at the end of the page. So do additional corruption checks inside this
** routine and return SQLITE_CORRUPT if any problems are found.
*/
@@ -71086,7 +72418,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( iSize>=4 ); /* Minimum cell size is 4 */
- assert( iStart<=pPage->pBt->usableSize-4 );
+ assert( CORRUPT_DB || iStart<=pPage->pBt->usableSize-4 );
/* The list of freeblocks must be in ascending order. Find the
** spot on the list where iStart should be inserted.
@@ -71143,6 +72475,11 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
}
pTmp = &data[hdr+5];
x = get2byte(pTmp);
+ if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
+ /* Overwrite deleted information with zeros when the secure_delete
+ ** option is enabled */
+ memset(&data[iStart], 0, iSize);
+ }
if( iStart<=x ){
/* The new freeblock is at the beginning of the cell content area,
** so just extend the cell content area rather than create another
@@ -71154,14 +72491,9 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
}else{
/* Insert the new freeblock into the freelist */
put2byte(&data[iPtr], iStart);
+ put2byte(&data[iStart], iFreeBlk);
+ put2byte(&data[iStart+2], iSize);
}
- if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
- /* Overwrite deleted information with zeros when the secure_delete
- ** option is enabled */
- memset(&data[iStart], 0, iSize);
- }
- put2byte(&data[iStart], iFreeBlk);
- put2byte(&data[iStart+2], iSize);
pPage->nFree += iOrigSize;
return SQLITE_OK;
}
@@ -71524,68 +72856,41 @@ SQLITE_PRIVATE Pgno sqlite3BtreeLastPage(Btree *p){
/*
** Get a page from the pager and initialize it.
-**
-** If pCur!=0 then the page is being fetched as part of a moveToChild()
-** call. Do additional sanity checking on the page in this case.
-** And if the fetch fails, this routine must decrement pCur->iPage.
-**
-** The page is fetched as read-write unless pCur is not NULL and is
-** a read-only cursor.
-**
-** If an error occurs, then *ppPage is undefined. It
-** may remain unchanged, or it may be set to an invalid value.
*/
static int getAndInitPage(
BtShared *pBt, /* The database file */
Pgno pgno, /* Number of the page to get */
MemPage **ppPage, /* Write the page pointer here */
- BtCursor *pCur, /* Cursor to receive the page, or NULL */
int bReadOnly /* True for a read-only page */
){
int rc;
DbPage *pDbPage;
+ MemPage *pPage;
assert( sqlite3_mutex_held(pBt->mutex) );
- assert( pCur==0 || ppPage==&pCur->pPage );
- assert( pCur==0 || bReadOnly==pCur->curPagerFlags );
- assert( pCur==0 || pCur->iPage>0 );
if( pgno>btreePagecount(pBt) ){
- rc = SQLITE_CORRUPT_BKPT;
- goto getAndInitPage_error1;
+ *ppPage = 0;
+ return SQLITE_CORRUPT_BKPT;
}
rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly);
if( rc ){
- goto getAndInitPage_error1;
+ *ppPage = 0;
+ return rc;
}
- *ppPage = (MemPage*)sqlite3PagerGetExtra(pDbPage);
- if( (*ppPage)->isInit==0 ){
+ pPage = (MemPage*)sqlite3PagerGetExtra(pDbPage);
+ if( pPage->isInit==0 ){
btreePageFromDbPage(pDbPage, pgno, pBt);
- rc = btreeInitPage(*ppPage);
+ rc = btreeInitPage(pPage);
if( rc!=SQLITE_OK ){
- goto getAndInitPage_error2;
+ releasePage(pPage);
+ *ppPage = 0;
+ return rc;
}
}
- assert( (*ppPage)->pgno==pgno || CORRUPT_DB );
- assert( (*ppPage)->aData==sqlite3PagerGetData(pDbPage) );
-
- /* If obtaining a child page for a cursor, we must verify that the page is
- ** compatible with the root page. */
- if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){
- rc = SQLITE_CORRUPT_PGNO(pgno);
- goto getAndInitPage_error2;
- }
+ assert( pPage->pgno==pgno || CORRUPT_DB );
+ assert( pPage->aData==sqlite3PagerGetData(pDbPage) );
+ *ppPage = pPage;
return SQLITE_OK;
-
-getAndInitPage_error2:
- releasePage(*ppPage);
-getAndInitPage_error1:
- if( pCur ){
- pCur->iPage--;
- pCur->pPage = pCur->apPage[pCur->iPage];
- }
- testcase( pgno==0 );
- assert( pgno!=0 || rc!=SQLITE_OK );
- return rc;
}
/*
@@ -71668,7 +72973,7 @@ static void pageReinit(DbPage *pData){
** call to btreeInitPage() will likely return SQLITE_CORRUPT.
** But no harm is done by this. And it is very important that
** btreeInitPage() be called on every btree page so we make
- ** the call for every page that comes in for re-initing. */
+ ** the call for every page that comes in for re-initializing. */
btreeInitPage(pPage);
}
}
@@ -71707,7 +73012,6 @@ static int btreeInvokeBusyHandler(void *pArg){
*/
SQLITE_PRIVATE int sqlite3BtreeOpen(
sqlite3_vfs *pVfs, /* VFS to use for this b-tree */
- libsql_wal_methods *pWal,/* WAL methods to use for this b-tree */
const char *zFilename, /* Name of the file containing the BTree database */
sqlite3 *db, /* Associated database handle */
Btree **ppBtree, /* Pointer to new Btree object written here */
@@ -71848,12 +73152,15 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
assert( sizeof(u16)==2 );
assert( sizeof(Pgno)==4 );
+ /* Suppress false-positive compiler warning from PVS-Studio */
+ memset(&zDbHeader[16], 0, 8);
+
pBt = sqlite3MallocZero( sizeof(*pBt) );
if( pBt==0 ){
rc = SQLITE_NOMEM_BKPT;
goto btree_open_out;
}
- rc = sqlite3PagerOpen(pVfs, pWal, &pBt->pPager, zFilename,
+ rc = sqlite3PagerOpen(pVfs, db->wal_manager ,&pBt->pPager, zFilename,
sizeof(MemPage), flags, vfsFlags, pageReinit);
if( rc==SQLITE_OK ){
sqlite3PagerSetMmapLimit(pBt->pPager, db->szMmap);
@@ -72064,7 +73371,7 @@ static SQLITE_NOINLINE int allocateTempSpace(BtShared *pBt){
** can mean that fillInCell() only initializes the first 2 or 3
** bytes of pTmpSpace, but that the first 4 bytes are copied from
** it into a database page. This is not actually a problem, but it
- ** does cause a valgrind error when the 1 or 2 bytes of unitialized
+ ** does cause a valgrind error when the 1 or 2 bytes of uninitialized
** data is passed to system call write(). So to avoid this error,
** zero the first 4 bytes of temp space here.
**
@@ -72299,7 +73606,7 @@ SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p){
/*
** Return the number of bytes of space at the end of every page that
-** are intentually left unused. This is the "reserved" space that is
+** are intentionally left unused. This is the "reserved" space that is
** sometimes used by extensions.
**
** The value returned is the larger of the current reserve size and
@@ -72546,7 +73853,6 @@ static int lockBtree(BtShared *pBt){
){
goto page1_init_failed;
}
- pBt->btsFlags |= BTS_PAGESIZE_FIXED;
assert( (pageSize & 7)==0 );
/* EVIDENCE-OF: R-59310-51205 The "reserved space" size in the 1-byte
** integer at offset 20 is the number of bytes of space at the end of
@@ -72566,6 +73872,7 @@ static int lockBtree(BtShared *pBt){
releasePageOne(pPage1);
pBt->usableSize = usableSize;
pBt->pageSize = pageSize;
+ pBt->btsFlags |= BTS_PAGESIZE_FIXED;
freeTempSpace(pBt);
rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize,
pageSize-usableSize);
@@ -72585,6 +73892,7 @@ static int lockBtree(BtShared *pBt){
if( usableSize<480 ){
goto page1_init_failed;
}
+ pBt->btsFlags |= BTS_PAGESIZE_FIXED;
pBt->pageSize = pageSize;
pBt->usableSize = usableSize;
#ifndef SQLITE_OMIT_AUTOVACUUM
@@ -72763,7 +74071,11 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){
** when A already has a read lock, we encourage A to give up and let B
** proceed.
*/
-SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
+static SQLITE_NOINLINE int btreeBeginTrans(
+ Btree *p, /* The btree in which to start the transaction */
+ int wrflag, /* True to start a write transaction */
+ int *pSchemaVersion /* Put schema version number here, if not NULL */
+){
BtShared *pBt = p->pBt;
Pager *pPager = pBt->pPager;
int rc = SQLITE_OK;
@@ -72935,6 +74247,28 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVers
sqlite3BtreeLeave(p);
return rc;
}
+SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
+ BtShared *pBt;
+ if( p->sharable
+ || p->inTrans==TRANS_NONE
+ || (p->inTrans==TRANS_READ && wrflag!=0)
+ ){
+ return btreeBeginTrans(p,wrflag,pSchemaVersion);
+ }
+ pBt = p->pBt;
+ if( pSchemaVersion ){
+ *pSchemaVersion = get4byte(&pBt->pPage1->aData[40]);
+ }
+ if( wrflag ){
+ /* This call makes sure that the pager has the correct number of
+ ** open savepoints. If the second parameter is greater than 0 and
+ ** the sub-journal is not already open, then it will be opened here.
+ */
+ return sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint);
+ }else{
+ return SQLITE_OK;
+ }
+}
#ifndef SQLITE_OMIT_AUTOVACUUM
@@ -73072,7 +74406,7 @@ static int relocatePage(
if( iDbPage<3 ) return SQLITE_CORRUPT_BKPT;
/* Move page iDbPage from its current location to page number iFreePage */
- TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n",
+ TRACE(("AUTOVACUUM: Moving %u to free page %u (ptr page %u type %u)\n",
iDbPage, iFreePage, iPtrPage, eType));
rc = sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage, isCommit);
if( rc!=SQLITE_OK ){
@@ -74030,7 +75364,6 @@ SQLITE_PRIVATE void sqlite3BtreeCursorUnpin(BtCursor *pCur){
pCur->curFlags &= ~BTCF_Pinned;
}
-#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
/*
** Return the offset into the database file for the start of the
** payload to which the cursor is pointing.
@@ -74042,7 +75375,6 @@ SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor *pCur){
return (i64)pCur->pBt->pageSize*((i64)pCur->pPage->pgno - 1) +
(i64)(pCur->info.pPayload - pCur->pPage->aData);
}
-#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */
/*
** Return the number of bytes of payload for the entry that pCur is
@@ -74068,7 +75400,7 @@ SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor *pCur){
** routine always returns 2147483647 (which is the largest record
** that SQLite can handle) or more. But returning a smaller value might
** prevent large memory allocations when trying to interpret a
-** corrupt datrabase.
+** corrupt database.
**
** The current implementation merely returns the size of the underlying
** database file.
@@ -74530,6 +75862,7 @@ SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){
** vice-versa).
*/
static int moveToChild(BtCursor *pCur, u32 newPgno){
+ int rc;
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPageapPage[pCur->iPage] = pCur->pPage;
pCur->ix = 0;
pCur->iPage++;
- return getAndInitPage(pCur->pBt, newPgno, &pCur->pPage, pCur,
- pCur->curPagerFlags);
+ rc = getAndInitPage(pCur->pBt, newPgno, &pCur->pPage, pCur->curPagerFlags);
+ assert( pCur->pPage!=0 || rc!=SQLITE_OK );
+ if( rc==SQLITE_OK
+ && (pCur->pPage->nCell<1 || pCur->pPage->intKey!=pCur->curIntKey)
+ ){
+ releasePage(pCur->pPage);
+ rc = SQLITE_CORRUPT_PGNO(newPgno);
+ }
+ if( rc ){
+ pCur->pPage = pCur->apPage[--pCur->iPage];
+ }
+ return rc;
}
#ifdef SQLITE_DEBUG
@@ -74651,7 +75994,7 @@ static int moveToRoot(BtCursor *pCur){
sqlite3BtreeClearCursor(pCur);
}
rc = getAndInitPage(pCur->pBt, pCur->pgnoRoot, &pCur->pPage,
- 0, pCur->curPagerFlags);
+ pCur->curPagerFlags);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
return rc;
@@ -74763,7 +76106,7 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
*pRes = 0;
rc = moveToLeftmost(pCur);
}else if( rc==SQLITE_EMPTY ){
- assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
+ assert( pCur->pgnoRoot==0 || (pCur->pPage!=0 && pCur->pPage->nCell==0) );
*pRes = 1;
rc = SQLITE_OK;
}
@@ -74868,7 +76211,7 @@ SQLITE_PRIVATE int sqlite3BtreeTableMoveto(
/* If the requested key is one more than the previous key, then
** try to get there using sqlite3BtreeNext() rather than a full
** binary search. This is an optimization only. The correct answer
- ** is still obtained without this case, only a little more slowely */
+ ** is still obtained without this case, only a little more slowly. */
if( pCur->info.nKey+1==intKey ){
*pRes = 0;
rc = sqlite3BtreeNext(pCur, 0);
@@ -75264,10 +76607,36 @@ SQLITE_PRIVATE int sqlite3BtreeIndexMoveto(
}else{
chldPg = get4byte(findCell(pPage, lwr));
}
- pCur->ix = (u16)lwr;
- rc = moveToChild(pCur, chldPg);
- if( rc ) break;
- }
+
+ /* This block is similar to an in-lined version of:
+ **
+ ** pCur->ix = (u16)lwr;
+ ** rc = moveToChild(pCur, chldPg);
+ ** if( rc ) break;
+ */
+ pCur->info.nSize = 0;
+ pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
+ if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ pCur->aiIdx[pCur->iPage] = (u16)lwr;
+ pCur->apPage[pCur->iPage] = pCur->pPage;
+ pCur->ix = 0;
+ pCur->iPage++;
+ rc = getAndInitPage(pCur->pBt, chldPg, &pCur->pPage, pCur->curPagerFlags);
+ if( rc==SQLITE_OK
+ && (pCur->pPage->nCell<1 || pCur->pPage->intKey!=pCur->curIntKey)
+ ){
+ releasePage(pCur->pPage);
+ rc = SQLITE_CORRUPT_PGNO(chldPg);
+ }
+ if( rc ){
+ pCur->pPage = pCur->apPage[--pCur->iPage];
+ break;
+ }
+ /*
+ ***** End of in-lined moveToChild() call */
+ }
moveto_index_finish:
pCur->info.nSize = 0;
assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
@@ -75358,7 +76727,8 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
pPage = pCur->pPage;
idx = ++pCur->ix;
- if( NEVER(!pPage->isInit) || sqlite3FaultSim(412) ){
+ if( sqlite3FaultSim(412) ) pPage->isInit = 0;
+ if( !pPage->isInit ){
return SQLITE_CORRUPT_BKPT;
}
@@ -75621,7 +76991,7 @@ static int allocateBtreePage(
memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
*ppPage = pTrunk;
pTrunk = 0;
- TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
+ TRACE(("ALLOCATE: %u trunk - %u free pages left\n", *pPgno, n-1));
}else if( k>(u32)(pBt->usableSize/4 - 2) ){
/* Value of k is out of range. Database corruption */
rc = SQLITE_CORRUPT_PGNO(iTrunk);
@@ -75687,7 +77057,7 @@ static int allocateBtreePage(
}
}
pTrunk = 0;
- TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
+ TRACE(("ALLOCATE: %u trunk - %u free pages left\n", *pPgno, n-1));
#endif
}else if( k>0 ){
/* Extract a leaf from the trunk */
@@ -75732,8 +77102,8 @@ static int allocateBtreePage(
){
int noContent;
*pPgno = iPage;
- TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
- ": %d more free pages\n",
+ TRACE(("ALLOCATE: %u was leaf %u of %u on trunk %u"
+ ": %u more free pages\n",
*pPgno, closest+1, k, pTrunk->pgno, n-1));
rc = sqlite3PagerWrite(pTrunk->pDbPage);
if( rc ) goto end_allocate_page;
@@ -75789,7 +77159,7 @@ static int allocateBtreePage(
** becomes a new pointer-map page, the second is used by the caller.
*/
MemPage *pPg = 0;
- TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
+ TRACE(("ALLOCATE: %u from end of file (pointer-map page)\n", pBt->nPage));
assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
rc = btreeGetUnusedPage(pBt, pBt->nPage, &pPg, bNoContent);
if( rc==SQLITE_OK ){
@@ -75812,7 +77182,7 @@ static int allocateBtreePage(
releasePage(*ppPage);
*ppPage = 0;
}
- TRACE(("ALLOCATE: %d from end of file\n", *pPgno));
+ TRACE(("ALLOCATE: %u from end of file\n", *pPgno));
}
assert( CORRUPT_DB || *pPgno!=PENDING_BYTE_PAGE(pBt) );
@@ -75940,7 +77310,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
}
rc = btreeSetHasContent(pBt, iPage);
}
- TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno));
+ TRACE(("FREE-PAGE: %u leaf on trunk page %u\n",pPage->pgno,pTrunk->pgno));
goto freepage_out;
}
}
@@ -75961,7 +77331,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
put4byte(pPage->aData, iTrunk);
put4byte(&pPage->aData[4], 0);
put4byte(&pPage1->aData[32], iPage);
- TRACE(("FREE-PAGE: %d new trunk page replacing %d\n", pPage->pgno, iTrunk));
+ TRACE(("FREE-PAGE: %u new trunk page replacing %u\n", pPage->pgno, iTrunk));
freepage_out:
if( pPage ){
@@ -76050,7 +77420,7 @@ static SQLITE_NOINLINE int clearCellOverflow(
/* Call xParseCell to compute the size of a cell. If the cell contains
** overflow, then invoke cellClearOverflow to clear out that overflow.
-** STore the result code (SQLITE_OK or some error code) in rc.
+** Store the result code (SQLITE_OK or some error code) in rc.
**
** Implemented as macro to force inlining for performance.
*/
@@ -76320,6 +77690,14 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
** in pTemp or the original pCell) and also record its index.
** Allocating a new entry in pPage->aCell[] implies that
** pPage->nOverflow is incremented.
+**
+** The insertCellFast() routine below works exactly the same as
+** insertCell() except that it lacks the pTemp and iChild parameters
+** which are assumed zero. Other than that, the two routines are the
+** same.
+**
+** Fixes or enhancements to this routine should be reflected in
+** insertCellFast()!
*/
static int insertCell(
MemPage *pPage, /* Page into which we are copying */
@@ -76342,14 +77720,103 @@ static int insertCell(
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( sz==pPage->xCellSize(pPage, pCell) || CORRUPT_DB );
assert( pPage->nFree>=0 );
+ assert( iChild>0 );
if( pPage->nOverflow || sz+2>pPage->nFree ){
if( pTemp ){
memcpy(pTemp, pCell, sz);
pCell = pTemp;
}
- if( iChild ){
- put4byte(pCell, iChild);
+ put4byte(pCell, iChild);
+ j = pPage->nOverflow++;
+ /* Comparison against ArraySize-1 since we hold back one extra slot
+ ** as a contingency. In other words, never need more than 3 overflow
+ ** slots but 4 are allocated, just to be safe. */
+ assert( j < ArraySize(pPage->apOvfl)-1 );
+ pPage->apOvfl[j] = pCell;
+ pPage->aiOvfl[j] = (u16)i;
+
+ /* When multiple overflows occur, they are always sequential and in
+ ** sorted order. This invariants arise because multiple overflows can
+ ** only occur when inserting divider cells into the parent page during
+ ** balancing, and the dividers are adjacent and sorted.
+ */
+ assert( j==0 || pPage->aiOvfl[j-1]<(u16)i ); /* Overflows in sorted order */
+ assert( j==0 || i==pPage->aiOvfl[j-1]+1 ); /* Overflows are sequential */
+ }else{
+ int rc = sqlite3PagerWrite(pPage->pDbPage);
+ if( NEVER(rc!=SQLITE_OK) ){
+ return rc;
+ }
+ assert( sqlite3PagerIswriteable(pPage->pDbPage) );
+ data = pPage->aData;
+ assert( &data[pPage->cellOffset]==pPage->aCellIdx );
+ rc = allocateSpace(pPage, sz, &idx);
+ if( rc ){ return rc; }
+ /* The allocateSpace() routine guarantees the following properties
+ ** if it returns successfully */
+ assert( idx >= 0 );
+ assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB );
+ assert( idx+sz <= (int)pPage->pBt->usableSize );
+ pPage->nFree -= (u16)(2 + sz);
+ /* In a corrupt database where an entry in the cell index section of
+ ** a btree page has a value of 3 or less, the pCell value might point
+ ** as many as 4 bytes in front of the start of the aData buffer for
+ ** the source page. Make sure this does not cause problems by not
+ ** reading the first 4 bytes */
+ memcpy(&data[idx+4], pCell+4, sz-4);
+ put4byte(&data[idx], iChild);
+ pIns = pPage->aCellIdx + i*2;
+ memmove(pIns+2, pIns, 2*(pPage->nCell - i));
+ put2byte(pIns, idx);
+ pPage->nCell++;
+ /* increment the cell count */
+ if( (++data[pPage->hdrOffset+4])==0 ) data[pPage->hdrOffset+3]++;
+ assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell || CORRUPT_DB );
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ if( pPage->pBt->autoVacuum ){
+ int rc2 = SQLITE_OK;
+ /* The cell may contain a pointer to an overflow page. If so, write
+ ** the entry for the overflow page into the pointer map.
+ */
+ ptrmapPutOvflPtr(pPage, pPage, pCell, &rc2);
+ if( rc2 ) return rc2;
}
+#endif
+ }
+ return SQLITE_OK;
+}
+
+/*
+** This variant of insertCell() assumes that the pTemp and iChild
+** parameters are both zero. Use this variant in sqlite3BtreeInsert()
+** for performance improvement, and also so that this variant is only
+** called from that one place, and is thus inlined, and thus runs must
+** faster.
+**
+** Fixes or enhancements to this routine should be reflected into
+** the insertCell() routine.
+*/
+static int insertCellFast(
+ MemPage *pPage, /* Page into which we are copying */
+ int i, /* New cell becomes the i-th cell of the page */
+ u8 *pCell, /* Content of the new cell */
+ int sz /* Bytes of content in pCell */
+){
+ int idx = 0; /* Where to write new cell content in data[] */
+ int j; /* Loop counter */
+ u8 *data; /* The content of the whole page */
+ u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */
+
+ assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
+ assert( MX_CELL(pPage->pBt)<=10921 );
+ assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB );
+ assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) );
+ assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) );
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+ assert( sz==pPage->xCellSize(pPage, pCell) || CORRUPT_DB );
+ assert( pPage->nFree>=0 );
+ assert( pPage->nOverflow==0 );
+ if( sz+2>pPage->nFree ){
j = pPage->nOverflow++;
/* Comparison against ArraySize-1 since we hold back one extra slot
** as a contingency. In other words, never need more than 3 overflow
@@ -76381,17 +77848,7 @@ static int insertCell(
assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB );
assert( idx+sz <= (int)pPage->pBt->usableSize );
pPage->nFree -= (u16)(2 + sz);
- if( iChild ){
- /* In a corrupt database where an entry in the cell index section of
- ** a btree page has a value of 3 or less, the pCell value might point
- ** as many as 4 bytes in front of the start of the aData buffer for
- ** the source page. Make sure this does not cause problems by not
- ** reading the first 4 bytes */
- memcpy(&data[idx+4], pCell+4, sz-4);
- put4byte(&data[idx], iChild);
- }else{
- memcpy(&data[idx], pCell, sz);
- }
+ memcpy(&data[idx], pCell, sz);
pIns = pPage->aCellIdx + i*2;
memmove(pIns+2, pIns, 2*(pPage->nCell - i));
put2byte(pIns, idx);
@@ -76574,12 +78031,13 @@ static int rebuildPage(
int k; /* Current slot in pCArray->apEnd[] */
u8 *pSrcEnd; /* Current pCArray->apEnd[k] value */
+ assert( nCell>0 );
assert( i(u32)usableSize ){ j = 0; }
memcpy(&pTmp[j], &aData[j], usableSize - j);
- for(k=0; pCArray->ixNx[k]<=i && ALWAYS(kixNx[k]<=i; k++){}
pSrcEnd = pCArray->apEnd[k];
pData = pEnd;
@@ -76642,7 +78100,7 @@ static int rebuildPage(
** Finally, argument pBegin points to the byte immediately following the
** end of the space required by this page for the cell-pointer area (for
** all cells - not just those inserted by the current call). If the content
-** area must be extended to before this point in order to accomodate all
+** area must be extended to before this point in order to accommodate all
** cells in apCell[], then the cells do not fit and non-zero is returned.
*/
static int pageInsertArray(
@@ -76662,7 +78120,7 @@ static int pageInsertArray(
u8 *pEnd; /* Maximum extent of cell data */
assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */
if( iEnd<=iFirst ) return 0;
- for(k=0; pCArray->ixNx[k]<=i && ALWAYS(kixNx[k]<=i ; k++){}
pEnd = pCArray->apEnd[k];
while( 1 /*Exit by break*/ ){
int sz, rc;
@@ -76720,42 +78178,50 @@ static int pageFreeArray(
u8 * const pEnd = &aData[pPg->pBt->usableSize];
u8 * const pStart = &aData[pPg->hdrOffset + 8 + pPg->childPtrSize];
int nRet = 0;
- int i;
+ int i, j;
int iEnd = iFirst + nCell;
- u8 *pFree = 0; /* \__ Parameters for pending call to */
- int szFree = 0; /* / freeSpace() */
+ int nFree = 0;
+ int aOfst[10];
+ int aAfter[10];
for(i=iFirst; iapCell[i];
if( SQLITE_WITHIN(pCell, pStart, pEnd) ){
int sz;
+ int iAfter;
+ int iOfst;
/* No need to use cachedCellSize() here. The sizes of all cells that
** are to be freed have already been computing while deciding which
** cells need freeing */
sz = pCArray->szCell[i]; assert( sz>0 );
- if( pFree!=(pCell + sz) ){
- if( pFree ){
- assert( pFree>aData && (pFree - aData)<65536 );
- freeSpace(pPg, (u16)(pFree - aData), szFree);
- }
- pFree = pCell;
- szFree = sz;
- if( pFree+sz>pEnd ){
- return 0;
+ iOfst = (u16)(pCell - aData);
+ iAfter = iOfst+sz;
+ for(j=0; j=nFree ){
+ if( nFree>=(int)(sizeof(aOfst)/sizeof(aOfst[0])) ){
+ for(j=0; jpEnd ) return 0;
+ nFree++;
}
nRet++;
}
}
- if( pFree ){
- assert( pFree>aData && (pFree - aData)<65536 );
- freeSpace(pPg, (u16)(pFree - aData), szFree);
+ for(j=0; jpPg->aDataEnd ) goto editpage_fail;
+ if( NEVER(pData>pPg->aDataEnd) ) goto editpage_fail;
/* Add cells to the start of the page */
if( iNew0), or
** (2) pPage is a virtual root page. A virtual root page is when
@@ -77547,7 +79014,7 @@ static int balance_nonroot(
** that page.
*/
assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) || CORRUPT_DB);
- TRACE(("BALANCE: old: %d(nc=%d) %d(nc=%d) %d(nc=%d)\n",
+ TRACE(("BALANCE: old: %u(nc=%u) %u(nc=%u) %u(nc=%u)\n",
apOld[0]->pgno, apOld[0]->nCell,
nOld>=2 ? apOld[1]->pgno : 0, nOld>=2 ? apOld[1]->nCell : 0,
nOld>=3 ? apOld[2]->pgno : 0, nOld>=3 ? apOld[2]->nCell : 0
@@ -77631,8 +79098,8 @@ static int balance_nonroot(
}
}
- TRACE(("BALANCE: new: %d(%d nc=%d) %d(%d nc=%d) %d(%d nc=%d) "
- "%d(%d nc=%d) %d(%d nc=%d)\n",
+ TRACE(("BALANCE: new: %u(%u nc=%u) %u(%u nc=%u) %u(%u nc=%u) "
+ "%u(%u nc=%u) %u(%u nc=%u)\n",
apNew[0]->pgno, szNew[0], cntNew[0],
nNew>=2 ? apNew[1]->pgno : 0, nNew>=2 ? szNew[1] : 0,
nNew>=2 ? cntNew[1] - cntNew[0] - !leafData : 0,
@@ -77764,9 +79231,9 @@ static int balance_nonroot(
iOvflSpace += sz;
assert( sz<=pBt->maxLocal+23 );
assert( iOvflSpace <= (int)pBt->pageSize );
- for(k=0; b.ixNx[k]<=j && ALWAYS(k=0 && iPg=1 || i>=0 );
+ assert( iPg=0 /* On the upwards pass, or... */
|| cntOld[iPg-1]>=cntNew[iPg-1] /* Condition (1) is true */
@@ -77877,7 +79346,7 @@ static int balance_nonroot(
}
assert( pParent->isInit );
- TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n",
+ TRACE(("BALANCE: finished: old=%u new=%u cells=%u\n",
nOld, nNew, b.nCell));
/* Free any old pages that were not reused as new pages.
@@ -77962,7 +79431,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
assert( sqlite3PagerIswriteable(pRoot->pDbPage) );
assert( pChild->nCell==pRoot->nCell || CORRUPT_DB );
- TRACE(("BALANCE: copy root %d into %d\n", pRoot->pgno, pChild->pgno));
+ TRACE(("BALANCE: copy root %u into %u\n", pRoot->pgno, pChild->pgno));
/* Copy the overflow cells from pRoot to pChild */
memcpy(pChild->aiOvfl, pRoot->aiOvfl,
@@ -78156,7 +79625,7 @@ static int btreeOverwriteContent(
){
int nData = pX->nData - iOffset;
if( nData<=0 ){
- /* Overwritting with zeros */
+ /* Overwriting with zeros */
int i;
for(i=0; ipData to write */
@@ -78445,7 +79914,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
}
}
assert( pCur->eState==CURSOR_VALID
- || (pCur->eState==CURSOR_INVALID && loc) );
+ || (pCur->eState==CURSOR_INVALID && loc) || CORRUPT_DB );
pPage = pCur->pPage;
assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) );
@@ -78460,7 +79929,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
if( rc ) return rc;
}
- TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n",
+ TRACE(("INSERT: table=%u nkey=%lld ndata=%u page=%u %s\n",
pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno,
loc==0 ? "overwrite" : "new entry"));
assert( pPage->isInit || CORRUPT_DB );
@@ -78487,6 +79956,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
assert( szNew==pPage->xCellSize(pPage, newCell) );
assert( szNew <= MX_CELL_SIZE(p->pBt) );
idx = pCur->ix;
+ pCur->info.nSize = 0;
if( loc==0 ){
CellInfo info;
assert( idx>=0 );
@@ -78535,7 +80005,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
}else{
assert( pPage->leaf );
}
- rc = insertCell(pPage, idx, newCell, szNew, 0, 0);
+ rc = insertCellFast(pPage, idx, newCell, szNew);
assert( pPage->nOverflow==0 || rc==SQLITE_OK );
assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
@@ -78559,7 +80029,6 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
** larger than the largest existing key, it is possible to insert the
** row without seeking the cursor. This can be a big performance boost.
*/
- pCur->info.nSize = 0;
if( pPage->nOverflow ){
assert( rc==SQLITE_OK );
pCur->curFlags &= ~(BTCF_ValidNKey);
@@ -78760,6 +80229,9 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ){
return SQLITE_CORRUPT_BKPT;
}
+ if( pCell<&pPage->aCellIdx[pPage->nCell] ){
+ return SQLITE_CORRUPT_BKPT;
+ }
/* If the BTREE_SAVEPOSITION bit is on, then the cursor position must
** be preserved following this delete operation. If the current delete
@@ -78936,7 +80408,7 @@ static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){
MemPage *pRoot;
Pgno pgnoRoot;
int rc;
- int ptfFlags; /* Page-type flage for the root page of new table */
+ int ptfFlags; /* Page-type flags for the root page of new table */
assert( sqlite3BtreeHoldsMutex(p) );
assert( pBt->inTransaction==TRANS_WRITE );
@@ -79105,7 +80577,7 @@ static int clearDatabasePage(
if( pgno>btreePagecount(pBt) ){
return SQLITE_CORRUPT_BKPT;
}
- rc = getAndInitPage(pBt, pgno, &pPage, 0, 0);
+ rc = getAndInitPage(pBt, pgno, &pPage, 0);
if( rc ) return rc;
if( (pBt->openFlags & BTREE_SINGLE)==0
&& sqlite3PagerPageRefcount(pPage->pDbPage) != (1 + (pgno==1))
@@ -79381,8 +80853,9 @@ SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){
** Otherwise, if an error is encountered (i.e. an IO error or database
** corruption) an SQLite error code is returned.
*/
-SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3 *db, BtCursor *pCur, i64 *pnEntry){
+SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3 *db, BtCursor *pCur, i64 *pnEntry, i64 *pnPages){
i64 nEntry = 0; /* Value to return in *pnEntry */
+ i64 nPages = 0; /* Number of visited pages */
int rc; /* Return code */
rc = moveToRoot(pCur);
@@ -79405,6 +80878,7 @@ SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3 *db, BtCursor *pCur, i64 *pnEntry){
pPage = pCur->pPage;
if( pPage->leaf || !pPage->intKey ){
nEntry += pPage->nCell;
+ nPages++;
}
/* pPage is a leaf node. This loop navigates the cursor so that it
@@ -79422,6 +80896,7 @@ SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3 *db, BtCursor *pCur, i64 *pnEntry){
if( pCur->iPage==0 ){
/* All pages of the b-tree have been visited. Return successfully. */
*pnEntry = nEntry;
+ *pnPages = nPages;
return moveToRoot(pCur);
}
moveToParent(pCur);
@@ -79508,7 +80983,8 @@ static void checkAppendMsg(
sqlite3_str_append(&pCheck->errMsg, "\n", 1);
}
if( pCheck->zPfx ){
- sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2);
+ sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx,
+ pCheck->v0, pCheck->v1, pCheck->v2);
}
sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap);
va_end(ap);
@@ -79525,7 +81001,8 @@ static void checkAppendMsg(
** corresponds to page iPg is already set.
*/
static int getPageReferenced(IntegrityCk *pCheck, Pgno iPg){
- assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 );
+ assert( pCheck->aPgRef!=0 );
+ assert( iPg<=pCheck->nCkPage && sizeof(pCheck->aPgRef[0])==1 );
return (pCheck->aPgRef[iPg/8] & (1 << (iPg & 0x07)));
}
@@ -79533,7 +81010,8 @@ static int getPageReferenced(IntegrityCk *pCheck, Pgno iPg){
** Set the bit in the IntegrityCk.aPgRef[] array that corresponds to page iPg.
*/
static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){
- assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 );
+ assert( pCheck->aPgRef!=0 );
+ assert( iPg<=pCheck->nCkPage && sizeof(pCheck->aPgRef[0])==1 );
pCheck->aPgRef[iPg/8] |= (1 << (iPg & 0x07));
}
@@ -79547,12 +81025,12 @@ static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){
** Also check that the page number is in bounds.
*/
static int checkRef(IntegrityCk *pCheck, Pgno iPage){
- if( iPage>pCheck->nPage || iPage==0 ){
- checkAppendMsg(pCheck, "invalid page number %d", iPage);
+ if( iPage>pCheck->nCkPage || iPage==0 ){
+ checkAppendMsg(pCheck, "invalid page number %u", iPage);
return 1;
}
if( getPageReferenced(pCheck, iPage) ){
- checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
+ checkAppendMsg(pCheck, "2nd reference to page %u", iPage);
return 1;
}
setPageReferenced(pCheck, iPage);
@@ -79578,13 +81056,13 @@ static void checkPtrmap(
rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) checkOom(pCheck);
- checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild);
+ checkAppendMsg(pCheck, "Failed to read ptrmap key=%u", iChild);
return;
}
if( ePtrmapType!=eType || iPtrmapParent!=iParent ){
checkAppendMsg(pCheck,
- "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)",
+ "Bad ptr map entry key=%u expected=(%u,%u) got=(%u,%u)",
iChild, eType, iParent, ePtrmapType, iPtrmapParent);
}
}
@@ -79609,7 +81087,7 @@ static void checkList(
if( checkRef(pCheck, iPage) ) break;
N--;
if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){
- checkAppendMsg(pCheck, "failed to get page %d", iPage);
+ checkAppendMsg(pCheck, "failed to get page %u", iPage);
break;
}
pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage);
@@ -79622,7 +81100,7 @@ static void checkList(
#endif
if( n>pCheck->pBt->usableSize/4-2 ){
checkAppendMsg(pCheck,
- "freelist leaf count too big on page %d", iPage);
+ "freelist leaf count too big on page %u", iPage);
N--;
}else{
for(i=0; i<(int)n; i++){
@@ -79654,7 +81132,7 @@ static void checkList(
}
if( N && nErrAtStart==pCheck->nErr ){
checkAppendMsg(pCheck,
- "%s is %d but should be %d",
+ "%s is %u but should be %u",
isFreeList ? "size" : "overflow list length",
expected-N, expected);
}
@@ -79769,11 +81247,12 @@ static int checkTreePage(
usableSize = pBt->usableSize;
if( iPage==0 ) return 0;
if( checkRef(pCheck, iPage) ) return 0;
- pCheck->zPfx = "Page %u: ";
+ pCheck->zPfx = "Tree %u page %u: ";
pCheck->v1 = iPage;
if( (rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0 ){
checkAppendMsg(pCheck,
"unable to get the page. error code=%d", rc);
+ if( rc==SQLITE_IOERR_NOMEM ) pCheck->rc = SQLITE_NOMEM;
goto end_of_check;
}
@@ -79796,7 +81275,7 @@ static int checkTreePage(
hdr = pPage->hdrOffset;
/* Set up for cell analysis */
- pCheck->zPfx = "On tree page %u cell %d: ";
+ pCheck->zPfx = "Tree %u page %u cell %u: ";
contentOffset = get2byteNotZero(&data[hdr+5]);
assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
@@ -79816,7 +81295,7 @@ static int checkTreePage(
pgno = get4byte(&data[hdr+8]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
- pCheck->zPfx = "On page %u at right child: ";
+ pCheck->zPfx = "Tree %u page %u right child: ";
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
}
#endif
@@ -79840,7 +81319,7 @@ static int checkTreePage(
pc = get2byteAligned(pCellIdx);
pCellIdx -= 2;
if( pcusableSize-4 ){
- checkAppendMsg(pCheck, "Offset %d out of range %d..%d",
+ checkAppendMsg(pCheck, "Offset %u out of range %u..%u",
pc, contentOffset, usableSize-4);
doCoverageCheck = 0;
continue;
@@ -79972,7 +81451,7 @@ static int checkTreePage(
*/
if( heap[0]==0 && nFrag!=data[hdr+7] ){
checkAppendMsg(pCheck,
- "Fragmentation of %d bytes reported as %d on page %u",
+ "Fragmentation of %u bytes reported as %u on page %u",
nFrag, data[hdr+7], iPage);
}
}
@@ -80044,15 +81523,15 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
sCheck.db = db;
sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager;
- sCheck.nPage = btreePagecount(sCheck.pBt);
+ sCheck.nCkPage = btreePagecount(sCheck.pBt);
sCheck.mxErr = mxErr;
sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
sCheck.errMsg.printfFlags = SQLITE_PRINTF_INTERNAL;
- if( sCheck.nPage==0 ){
+ if( sCheck.nCkPage==0 ){
goto integrity_ck_cleanup;
}
- sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1);
+ sCheck.aPgRef = sqlite3MallocZero((sCheck.nCkPage / 8)+ 1);
if( !sCheck.aPgRef ){
checkOom(&sCheck);
goto integrity_ck_cleanup;
@@ -80064,12 +81543,12 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
}
i = PENDING_BYTE_PAGE(pBt);
- if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i);
+ if( i<=sCheck.nCkPage ) setPageReferenced(&sCheck, i);
/* Check the integrity of the freelist
*/
if( bCkFreelist ){
- sCheck.zPfx = "Main freelist: ";
+ sCheck.zPfx = "Freelist: ";
checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
get4byte(&pBt->pPage1->aData[36]));
sCheck.zPfx = 0;
@@ -80086,7 +81565,7 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
mxInHdr = get4byte(&pBt->pPage1->aData[52]);
if( mx!=mxInHdr ){
checkAppendMsg(&sCheck,
- "max rootpage (%d) disagrees with header (%d)",
+ "max rootpage (%u) disagrees with header (%u)",
mx, mxInHdr
);
}
@@ -80107,6 +81586,7 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
}
#endif
+ sCheck.v0 = aRoot[i];
checkTreePage(&sCheck, aRoot[i], ¬Used, LARGEST_INT64);
}
pBt->db->flags = savedDbFlags;
@@ -80114,10 +81594,10 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
/* Make sure every page in the file is referenced
*/
if( !bPartial ){
- for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
+ for(i=1; i<=sCheck.nCkPage && sCheck.mxErr; i++){
#ifdef SQLITE_OMIT_AUTOVACUUM
if( getPageReferenced(&sCheck, i)==0 ){
- checkAppendMsg(&sCheck, "Page %d is never used", i);
+ checkAppendMsg(&sCheck, "Page %u: never used", i);
}
#else
/* If the database supports auto-vacuum, make sure no tables contain
@@ -80125,11 +81605,11 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
*/
if( getPageReferenced(&sCheck, i)==0 &&
(PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
- checkAppendMsg(&sCheck, "Page %d is never used", i);
+ checkAppendMsg(&sCheck, "Page %u: never used", i);
}
if( getPageReferenced(&sCheck, i)!=0 &&
(PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
- checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
+ checkAppendMsg(&sCheck, "Page %u: pointer map referenced", i);
}
#endif
}
@@ -80691,13 +82171,7 @@ static int backupOnePage(
assert( !isFatalError(p->rc) );
assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) );
assert( zSrcData );
-
- /* Catch the case where the destination is an in-memory database and the
- ** page sizes of the source and destination differ.
- */
- if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){
- rc = SQLITE_READONLY;
- }
+ assert( nSrcPgsz==nDestPgsz || sqlite3PagerIsMemdb(pDestPager)==0 );
/* This loop runs once for each destination page spanned by the source
** page. For each iteration, variable iOff is set to the byte offset
@@ -80830,7 +82304,10 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
pgszDest = sqlite3BtreeGetPageSize(p->pDest);
destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest));
- if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){
+ if( SQLITE_OK==rc
+ && (destMode==PAGER_JOURNALMODE_WAL || sqlite3PagerIsMemdb(pDestPager))
+ && pgszSrc!=pgszDest
+ ){
rc = SQLITE_READONLY;
}
@@ -81379,6 +82856,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemValidStrRep(Mem *p){
char *z;
int i, j, incr;
if( (p->flags & MEM_Str)==0 ) return 1;
+ if( p->db && p->db->mallocFailed ) return 1;
if( p->flags & MEM_Term ){
/* Insure that the string is properly zero-terminated. Pay particular
** attention to the case where p->n is odd */
@@ -81535,6 +83013,40 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
return SQLITE_OK;
}
+/*
+** If pMem is already a string, detect if it is a zero-terminated
+** string, or make it into one if possible, and mark it as such.
+**
+** This is an optimization. Correct operation continues even if
+** this routine is a no-op.
+*/
+SQLITE_PRIVATE void sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){
+ if( (pMem->flags & (MEM_Str|MEM_Term|MEM_Ephem|MEM_Static))!=MEM_Str ){
+ /* pMem must be a string, and it cannot be an ephemeral or static string */
+ return;
+ }
+ if( pMem->enc!=SQLITE_UTF8 ) return;
+ if( NEVER(pMem->z==0) ) return;
+ if( pMem->flags & MEM_Dyn ){
+ if( pMem->xDel==sqlite3_free
+ && sqlite3_msize(pMem->z) >= (u64)(pMem->n+1)
+ ){
+ pMem->z[pMem->n] = 0;
+ pMem->flags |= MEM_Term;
+ return;
+ }
+ if( pMem->xDel==sqlite3RCStrUnref ){
+ /* Blindly assume that all RCStr objects are zero-terminated */
+ pMem->flags |= MEM_Term;
+ return;
+ }
+ }else if( pMem->szMalloc >= pMem->n+1 ){
+ pMem->z[pMem->n] = 0;
+ pMem->flags |= MEM_Term;
+ return;
+ }
+}
+
/*
** It is already known that pMem contains an unterminated string.
** Add the zero terminator.
@@ -81661,7 +83173,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
vdbeMemRenderNum(nByte, pMem->z, pMem);
assert( pMem->z!=0 );
- assert( pMem->n==sqlite3Strlen30NN(pMem->z) );
+ assert( pMem->n==(int)sqlite3Strlen30NN(pMem->z) );
pMem->enc = SQLITE_UTF8;
pMem->flags |= MEM_Str|MEM_Term;
if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
@@ -81796,36 +83308,6 @@ SQLITE_PRIVATE void sqlite3VdbeMemReleaseMalloc(Mem *p){
if( p->szMalloc ) vdbeMemClear(p);
}
-/*
-** Convert a 64-bit IEEE double into a 64-bit signed integer.
-** If the double is out of range of a 64-bit signed integer then
-** return the closest available 64-bit signed integer.
-*/
-static SQLITE_NOINLINE i64 doubleToInt64(double r){
-#ifdef SQLITE_OMIT_FLOATING_POINT
- /* When floating-point is omitted, double and int64 are the same thing */
- return r;
-#else
- /*
- ** Many compilers we encounter do not define constants for the
- ** minimum and maximum 64-bit integers, or they define them
- ** inconsistently. And many do not understand the "LL" notation.
- ** So we define our own static constants here using nothing
- ** larger than a 32-bit integer constant.
- */
- static const i64 maxInt = LARGEST_INT64;
- static const i64 minInt = SMALLEST_INT64;
-
- if( r<=(double)minInt ){
- return minInt;
- }else if( r>=(double)maxInt ){
- return maxInt;
- }else{
- return (i64)r;
- }
-#endif
-}
-
/*
** Return some kind of integer value which is the best we can do
** at representing the value that *pMem describes as an integer.
@@ -81852,7 +83334,7 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(const Mem *pMem){
testcase( flags & MEM_IntReal );
return pMem->u.i;
}else if( flags & MEM_Real ){
- return doubleToInt64(pMem->u.r);
+ return sqlite3RealToI64(pMem->u.r);
}else if( (flags & (MEM_Str|MEM_Blob))!=0 && pMem->z!=0 ){
return memIntValue(pMem);
}else{
@@ -81914,7 +83396,7 @@ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){
if( pMem->flags & MEM_IntReal ){
MemSetTypeFlag(pMem, MEM_Int);
}else{
- i64 ix = doubleToInt64(pMem->u.r);
+ i64 ix = sqlite3RealToI64(pMem->u.r);
/* Only mark the value as an integer if
**
@@ -81982,8 +83464,8 @@ SQLITE_PRIVATE int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){
** from UBSAN.
*/
SQLITE_PRIVATE i64 sqlite3RealToI64(double r){
- if( r<=(double)SMALLEST_INT64 ) return SMALLEST_INT64;
- if( r>=(double)LARGEST_INT64) return LARGEST_INT64;
+ if( r<-9223372036854774784.0 ) return SMALLEST_INT64;
+ if( r>+9223372036854774784.0 ) return LARGEST_INT64;
return (i64)r;
}
@@ -82054,6 +83536,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
break;
}
default: {
+ int rc;
assert( aff==SQLITE_AFF_TEXT );
assert( MEM_Str==(MEM_Blob>>3) );
pMem->flags |= (pMem->flags&MEM_Blob)>>3;
@@ -82061,7 +83544,9 @@ SQLITE_PRIVATE int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero);
if( encoding!=SQLITE_UTF8 ) pMem->n &= ~1;
- return sqlite3VdbeChangeEncoding(pMem, encoding);
+ rc = sqlite3VdbeChangeEncoding(pMem, encoding);
+ if( rc ) return rc;
+ sqlite3VdbeMemZeroTerminateIfAble(pMem);
}
}
return SQLITE_OK;
@@ -82585,6 +84070,24 @@ SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
return valueToText(pVal, enc);
}
+/* Return true if sqlit3_value object pVal is a string or blob value
+** that uses the destructor specified in the second argument.
+**
+** TODO: Maybe someday promote this interface into a published API so
+** that third-party extensions can get access to it?
+*/
+SQLITE_PRIVATE int sqlite3ValueIsOfClass(const sqlite3_value *pVal, void(*xFree)(void*)){
+ if( ALWAYS(pVal!=0)
+ && ALWAYS((pVal->flags & (MEM_Str|MEM_Blob))!=0)
+ && (pVal->flags & MEM_Dyn)!=0
+ && pVal->xDel==xFree
+ ){
+ return 1;
+ }else{
+ return 0;
+ }
+}
+
/*
** Create a new sqlite3_value object.
*/
@@ -82652,6 +84155,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
}
pRec->nField = p->iVal+1;
+ sqlite3VdbeMemSetNull(&pRec->aMem[p->iVal]);
return &pRec->aMem[p->iVal];
}
#else
@@ -82705,6 +84209,9 @@ static int valueFromFunction(
if( pList ) nVal = pList->nExpr;
assert( !ExprHasProperty(p, EP_IntValue) );
pFunc = sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0);
+#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+ if( pFunc==0 ) return SQLITE_OK;
+#endif
assert( pFunc );
if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
|| (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
@@ -82741,16 +84248,11 @@ static int valueFromFunction(
}else{
sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8);
assert( rc==SQLITE_OK );
- assert( enc==pVal->enc
- || (pVal->flags & MEM_Str)==0
- || db->mallocFailed );
-#if 0 /* Not reachable except after a prior failure */
rc = sqlite3VdbeChangeEncoding(pVal, enc);
- if( rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal) ){
+ if( NEVER(rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal)) ){
rc = SQLITE_TOOBIG;
pCtx->pParse->nErr++;
}
-#endif
}
value_from_function_out:
@@ -82814,6 +84316,13 @@ static int valueFromExpr(
rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx);
testcase( rc!=SQLITE_OK );
if( *ppVal ){
+#ifdef SQLITE_ENABLE_STAT4
+ rc = ExpandBlob(*ppVal);
+#else
+ /* zero-blobs only come from functions, not literal values. And
+ ** functions are only processed under STAT4 */
+ assert( (ppVal[0][0].flags & MEM_Zero)==0 );
+#endif
sqlite3VdbeMemCast(*ppVal, aff, enc);
sqlite3ValueApplyAffinity(*ppVal, affinity, enc);
}
@@ -82906,6 +84415,7 @@ static int valueFromExpr(
if( pVal ){
pVal->flags = MEM_Int;
pVal->u.i = pExpr->u.zToken[4]==0;
+ sqlite3ValueApplyAffinity(pVal, affinity, enc);
}
}
@@ -83435,6 +84945,35 @@ static void test_addop_breakpoint(int pc, Op *pOp){
}
#endif
+/*
+** Slow paths for sqlite3VdbeAddOp3() and sqlite3VdbeAddOp4Int() for the
+** unusual case when we need to increase the size of the Vdbe.aOp[] array
+** before adding the new opcode.
+*/
+static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){
+ assert( p->nOpAlloc<=p->nOp );
+ if( growOpArray(p, 1) ) return 1;
+ assert( p->nOpAlloc>p->nOp );
+ return sqlite3VdbeAddOp3(p, op, p1, p2, p3);
+}
+static SQLITE_NOINLINE int addOp4IntSlow(
+ Vdbe *p, /* Add the opcode to this VM */
+ int op, /* The new opcode */
+ int p1, /* The P1 operand */
+ int p2, /* The P2 operand */
+ int p3, /* The P3 operand */
+ int p4 /* The P4 operand as an integer */
+){
+ int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3);
+ if( p->db->mallocFailed==0 ){
+ VdbeOp *pOp = &p->aOp[addr];
+ pOp->p4type = P4_INT32;
+ pOp->p4.i = p4;
+ }
+ return addr;
+}
+
+
/*
** Add a new instruction to the list of instructions current in the
** VDBE. Return the address of the new instruction.
@@ -83445,17 +84984,16 @@ static void test_addop_breakpoint(int pc, Op *pOp){
**
** op The opcode for this instruction
**
-** p1, p2, p3 Operands
-**
-** Use the sqlite3VdbeResolveLabel() function to fix an address and
-** the sqlite3VdbeChangeP4() function to change the value of the P4
-** operand.
+** p1, p2, p3, p4 Operands
*/
-static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){
- assert( p->nOpAlloc<=p->nOp );
- if( growOpArray(p, 1) ) return 1;
- assert( p->nOpAlloc>p->nOp );
- return sqlite3VdbeAddOp3(p, op, p1, p2, p3);
+SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe *p, int op){
+ return sqlite3VdbeAddOp3(p, op, 0, 0, 0);
+}
+SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe *p, int op, int p1){
+ return sqlite3VdbeAddOp3(p, op, p1, 0, 0);
+}
+SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe *p, int op, int p1, int p2){
+ return sqlite3VdbeAddOp3(p, op, p1, p2, 0);
}
SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
int i;
@@ -83478,6 +85016,9 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
pOp->p3 = p3;
pOp->p4.p = 0;
pOp->p4type = P4_NOTUSED;
+
+ /* Replicate this logic in sqlite3VdbeAddOp4Int()
+ ** vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
pOp->zComment = 0;
#endif
@@ -83494,16 +85035,59 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
#ifdef SQLITE_VDBE_COVERAGE
pOp->iSrcLine = 0;
#endif
+ /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ ** Replicate in sqlite3VdbeAddOp4Int() */
+
return i;
}
-SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe *p, int op){
- return sqlite3VdbeAddOp3(p, op, 0, 0, 0);
-}
-SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe *p, int op, int p1){
- return sqlite3VdbeAddOp3(p, op, p1, 0, 0);
-}
-SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe *p, int op, int p1, int p2){
- return sqlite3VdbeAddOp3(p, op, p1, p2, 0);
+SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(
+ Vdbe *p, /* Add the opcode to this VM */
+ int op, /* The new opcode */
+ int p1, /* The P1 operand */
+ int p2, /* The P2 operand */
+ int p3, /* The P3 operand */
+ int p4 /* The P4 operand as an integer */
+){
+ int i;
+ VdbeOp *pOp;
+
+ i = p->nOp;
+ if( p->nOpAlloc<=i ){
+ return addOp4IntSlow(p, op, p1, p2, p3, p4);
+ }
+ p->nOp++;
+ pOp = &p->aOp[i];
+ assert( pOp!=0 );
+ pOp->opcode = (u8)op;
+ pOp->p5 = 0;
+ pOp->p1 = p1;
+ pOp->p2 = p2;
+ pOp->p3 = p3;
+ pOp->p4.i = p4;
+ pOp->p4type = P4_INT32;
+
+ /* Replicate this logic in sqlite3VdbeAddOp3()
+ ** vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+ pOp->zComment = 0;
+#endif
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
+ pOp->nExec = 0;
+ pOp->nCycle = 0;
+#endif
+#ifdef SQLITE_DEBUG
+ if( p->db->flags & SQLITE_VdbeAddopTrace ){
+ sqlite3VdbePrintOp(0, i, &p->aOp[i]);
+ test_addop_breakpoint(i, &p->aOp[i]);
+ }
+#endif
+#ifdef SQLITE_VDBE_COVERAGE
+ pOp->iSrcLine = 0;
+#endif
+ /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ ** Replicate in sqlite3VdbeAddOp3() */
+
+ return i;
}
/* Generate code for an unconditional jump to instruction iDest
@@ -83681,7 +85265,7 @@ SQLITE_PRIVATE int sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt,
if( bPush){
pParse->addrExplain = iThis;
}
- sqlite3VdbeScanStatus(v, iThis, 0, 0, 0, 0);
+ sqlite3VdbeScanStatus(v, iThis, -1, -1, 0, 0);
}
return addr;
}
@@ -83711,26 +85295,6 @@ SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere,
sqlite3MayAbort(p->pParse);
}
-/*
-** Add an opcode that includes the p4 value as an integer.
-*/
-SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(
- Vdbe *p, /* Add the opcode to this VM */
- int op, /* The new opcode */
- int p1, /* The P1 operand */
- int p2, /* The P2 operand */
- int p3, /* The P3 operand */
- int p4 /* The P4 operand as an integer */
-){
- int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3);
- if( p->db->mallocFailed==0 ){
- VdbeOp *pOp = &p->aOp[addr];
- pOp->p4type = P4_INT32;
- pOp->p4.i = p4;
- }
- return addr;
-}
-
/* Insert the end of a co-routine
*/
SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe *v, int regYield){
@@ -84037,11 +85601,13 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
Op *pOp;
Parse *pParse = p->pParse;
int *aLabel = pParse->aLabel;
+
+ assert( pParse->db->mallocFailed==0 ); /* tag-20230419-1 */
p->readOnly = 1;
p->bIsReader = 0;
pOp = &p->aOp[p->nOp-1];
assert( p->aOp[0].opcode==OP_Init );
- while( 1 /* Loop termates when it reaches the OP_Init opcode */ ){
+ while( 1 /* Loop terminates when it reaches the OP_Init opcode */ ){
/* Only JUMP opcodes and the short list of special opcodes in the switch
** below need to be considered. The mkopcodeh.tcl generator script groups
** all these opcodes together near the front of the opcode list. Skip
@@ -84096,6 +85662,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
** have non-negative values for P2. */
assert( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 );
assert( ADDR(pOp->p2)<-pParse->nLabel );
+ assert( aLabel!=0 ); /* True because of tag-20230419-1 */
pOp->p2 = aLabel[ADDR(pOp->p2)];
}
break;
@@ -84162,6 +85729,10 @@ SQLITE_PRIVATE void sqlite3VdbeNoJumpsOutsideSubrtn(
int iDest = pOp->p2; /* Jump destination */
if( iDest==0 ) continue;
if( pOp->opcode==OP_Gosub ) continue;
+ if( pOp->p3==20230325 && pOp->opcode==OP_NotNull ){
+ /* This is a deliberately taken illegal branch. tag-20230325-2 */
+ continue;
+ }
if( iDest<0 ){
int j = ADDR(iDest);
assert( j>=0 );
@@ -84410,8 +85981,8 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatusCounters(
pScan = 0;
}
if( pScan ){
- pScan->addrLoop = addrLoop;
- pScan->addrVisit = addrVisit;
+ if( addrLoop>0 ) pScan->addrLoop = addrLoop;
+ if( addrVisit>0 ) pScan->addrVisit = addrVisit;
}
}
}
@@ -84494,7 +86065,7 @@ SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe *p, int addr){
/*
** If the input FuncDef structure is ephemeral, then free it. If
-** the FuncDef is not ephermal, then do nothing.
+** the FuncDef is not ephemeral, then do nothing.
*/
static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
assert( db!=0 );
@@ -84658,7 +86229,6 @@ SQLITE_PRIVATE void sqlite3VdbeReleaseRegisters(
}
#endif /* SQLITE_DEBUG */
-
/*
** Change the value of the P4 operand for a specific instruction.
** This routine is useful when a large program is loaded from a
@@ -84839,7 +86409,7 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
/* Return the most recently added opcode
*/
-VdbeOp * sqlite3VdbeGetLastOp(Vdbe *p){
+SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetLastOp(Vdbe *p){
return sqlite3VdbeGetOp(p, p->nOp - 1);
}
@@ -85579,7 +87149,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
sqlite3VdbeMemSetInt64(pMem+1, pOp->p2);
sqlite3VdbeMemSetInt64(pMem+2, pOp->p3);
sqlite3VdbeMemSetStr(pMem+3, zP4, -1, SQLITE_UTF8, sqlite3_free);
- p->nResColumn = 4;
+ assert( p->nResColumn==4 );
}else{
sqlite3VdbeMemSetInt64(pMem+0, i);
sqlite3VdbeMemSetStr(pMem+1, (char*)sqlite3OpcodeName(pOp->opcode),
@@ -85598,7 +87168,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
sqlite3VdbeMemSetNull(pMem+7);
#endif
sqlite3VdbeMemSetStr(pMem+5, zP4, -1, SQLITE_UTF8, sqlite3_free);
- p->nResColumn = 8;
+ assert( p->nResColumn==8 );
}
p->pResultRow = pMem;
if( db->mallocFailed ){
@@ -85812,26 +87382,9 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
resolveP2Values(p, &nArg);
p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
if( pParse->explain ){
- static const char * const azColName[] = {
- "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
- "id", "parent", "notused", "detail"
- };
- int iFirst, mx, i;
if( nMem<10 ) nMem = 10;
p->explain = pParse->explain;
- if( pParse->explain==2 ){
- sqlite3VdbeSetNumCols(p, 4);
- iFirst = 8;
- mx = 12;
- }else{
- sqlite3VdbeSetNumCols(p, 8);
- iFirst = 0;
- mx = 8;
- }
- for(i=iFirst; inResColumn = 12 - 4*p->explain;
}
p->expired = 0;
@@ -85883,7 +87436,23 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
if( pCx ) sqlite3VdbeFreeCursorNN(p,pCx);
}
+static SQLITE_NOINLINE void freeCursorWithCache(Vdbe *p, VdbeCursor *pCx){
+ VdbeTxtBlbCache *pCache = pCx->pCache;
+ assert( pCx->colCache );
+ pCx->colCache = 0;
+ pCx->pCache = 0;
+ if( pCache->pCValue ){
+ sqlite3RCStrUnref(pCache->pCValue);
+ pCache->pCValue = 0;
+ }
+ sqlite3DbFree(p->db, pCache);
+ sqlite3VdbeFreeCursorNN(p, pCx);
+}
SQLITE_PRIVATE void sqlite3VdbeFreeCursorNN(Vdbe *p, VdbeCursor *pCx){
+ if( pCx->colCache ){
+ freeCursorWithCache(p, pCx);
+ return;
+ }
switch( pCx->eCurType ){
case CURTYPE_SORTER: {
sqlite3VdbeSorterClose(p->db, pCx);
@@ -85984,12 +87553,12 @@ SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
int n;
sqlite3 *db = p->db;
- if( p->nResColumn ){
- releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
+ if( p->nResAlloc ){
+ releaseMemArray(p->aColName, p->nResAlloc*COLNAME_N);
sqlite3DbFree(db, p->aColName);
}
n = nResColumn*COLNAME_N;
- p->nResColumn = (u16)nResColumn;
+ p->nResColumn = p->nResAlloc = (u16)nResColumn;
p->aColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n );
if( p->aColName==0 ) return;
initMemArray(p->aColName, n, db, MEM_Null);
@@ -86014,14 +87583,14 @@ SQLITE_PRIVATE int sqlite3VdbeSetColName(
){
int rc;
Mem *pColName;
- assert( idxnResColumn );
+ assert( idxnResAlloc );
assert( vardb->mallocFailed ){
assert( !zName || xDel!=SQLITE_DYNAMIC );
return SQLITE_NOMEM_BKPT;
}
assert( p->aColName!=0 );
- pColName = &(p->aColName[idx+var*p->nResColumn]);
+ pColName = &(p->aColName[idx+var*p->nResAlloc]);
rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, xDel);
assert( rc!=0 || !zName || (pColName->flags&MEM_Term)!=0 );
return rc;
@@ -86534,6 +88103,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
sqlite3VdbeLeave(p);
return SQLITE_BUSY;
}else if( rc!=SQLITE_OK ){
+ sqlite3SystemError(db, rc);
p->rc = rc;
sqlite3RollbackAll(db, SQLITE_OK);
p->nChange = 0;
@@ -86543,6 +88113,8 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
db->flags &= ~(u64)SQLITE_DeferFKs;
sqlite3CommitInternalChanges(db);
}
+ }else if( p->rc==SQLITE_SCHEMA && db->nVdbeActive>1 ){
+ p->nChange = 0;
}else{
sqlite3RollbackAll(db, SQLITE_OK);
p->nChange = 0;
@@ -86843,7 +88415,7 @@ static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
assert( db!=0 );
assert( p->db==0 || p->db==db );
if( p->aColName ){
- releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
+ releaseMemArray(p->aColName, p->nResAlloc*COLNAME_N);
sqlite3DbNNFreeNN(db, p->aColName);
}
for(pSub=p->pProgram; pSub; pSub=pNext){
@@ -86861,9 +88433,9 @@ static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
#ifdef SQLITE_ENABLE_NORMALIZE
sqlite3DbFree(db, p->zNormSql);
{
- DblquoteStr *pThis, *pNext;
- for(pThis=p->pDblStr; pThis; pThis=pNext){
- pNext = pThis->pNextStr;
+ DblquoteStr *pThis, *pNxt;
+ for(pThis=p->pDblStr; pThis; pThis=pNxt){
+ pNxt = pThis->pNextStr;
sqlite3DbFree(db, pThis);
}
}
@@ -87443,6 +89015,15 @@ static int vdbeRecordCompareDebug(
if( d1+(u64)serial_type1+2>(u64)nKey1
&& d1+(u64)sqlite3VdbeSerialTypeLen(serial_type1)>(u64)nKey1
){
+ if( serial_type1>=1
+ && serial_type1<=7
+ && d1+(u64)sqlite3VdbeSerialTypeLen(serial_type1)<=(u64)nKey1+8
+ && CORRUPT_DB
+ ){
+ return 1; /* corrupt record not detected by
+ ** sqlite3VdbeRecordCompareWithSkip(). Return true
+ ** to avoid firing the assert() */
+ }
break;
}
@@ -87611,20 +89192,33 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem
return n1 - n2;
}
+/* The following two functions are used only within testcase() to prove
+** test coverage. These functions do no exist for production builds.
+** We must use separate SQLITE_NOINLINE functions here, since otherwise
+** optimizer code movement causes gcov to become very confused.
+*/
+#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG)
+static int SQLITE_NOINLINE doubleLt(double a, double b){ return a8 ){
+ if( sqlite3IsNaN(r) ){
+ /* SQLite considers NaN to be a NULL. And all integer values are greater
+ ** than NULL */
+ return 1;
+ }
+ if( sqlite3Config.bUseLongDouble ){
LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i;
testcase( xr );
testcase( x==r );
- if( xr ) return +1; /*NO_TEST*/ /* work around bugs in gcov */
- return 0; /*NO_TEST*/ /* work around bugs in gcov */
+ return (xr);
}else{
i64 y;
double s;
@@ -87634,9 +89228,10 @@ SQLITE_PRIVATE int sqlite3IntFloatCompare(i64 i, double r){
if( iy ) return +1;
s = (double)i;
- if( sr ) return +1;
- return 0;
+ testcase( doubleLt(s,r) );
+ testcase( doubleLt(r,s) );
+ testcase( doubleEq(r,s) );
+ return (sr);
}
}
@@ -87886,7 +89481,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
/* Serial types 12 or greater are strings and blobs (greater than
** numbers). Types 10 and 11 are currently "reserved for future
** use", so it doesn't really matter what the results of comparing
- ** them to numberic values are. */
+ ** them to numeric values are. */
rc = serial_type==10 ? -1 : +1;
}else if( serial_type==0 ){
rc = -1;
@@ -88490,6 +90085,20 @@ SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context *pCtx){
return 1;
}
+#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG)
+/*
+** This Walker callback is used to help verify that calls to
+** sqlite3BtreeCursorHint() with opcode BTREE_HINT_RANGE have
+** byte-code register values correctly initialized.
+*/
+SQLITE_PRIVATE int sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_REGISTER ){
+ assert( (pWalker->u.aMem[pExpr->iTable].flags & MEM_Undefined)==0 );
+ }
+ return WRC_Continue;
+}
+#endif /* SQLITE_ENABLE_CURSOR_HINTS && SQLITE_DEBUG */
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored
@@ -88552,6 +90161,16 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
PreUpdate preupdate;
const char *zTbl = pTab->zName;
static const u8 fakeSortOrder = 0;
+#ifdef SQLITE_DEBUG
+ int nRealCol;
+ if( pTab->tabFlags & TF_WithoutRowid ){
+ nRealCol = sqlite3PrimaryKeyIndex(pTab)->nColumn;
+ }else if( pTab->tabFlags & TF_HasVirtual ){
+ nRealCol = pTab->nNVCol;
+ }else{
+ nRealCol = pTab->nCol;
+ }
+#endif
assert( db->pPreUpdate==0 );
memset(&preupdate, 0, sizeof(PreUpdate));
@@ -88568,8 +90187,8 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
assert( pCsr!=0 );
assert( pCsr->eCurType==CURTYPE_BTREE );
- assert( pCsr->nField==pTab->nCol
- || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1)
+ assert( pCsr->nField==nRealCol
+ || (pCsr->nField==nRealCol+1 && op==SQLITE_DELETE && iReg==-1)
);
preupdate.v = v;
@@ -88876,7 +90495,7 @@ SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){
SQLITE_NULL, /* 0x1f (not possible) */
SQLITE_FLOAT, /* 0x20 INTREAL */
SQLITE_NULL, /* 0x21 (not possible) */
- SQLITE_TEXT, /* 0x22 INTREAL + TEXT */
+ SQLITE_FLOAT, /* 0x22 INTREAL + TEXT */
SQLITE_NULL, /* 0x23 (not possible) */
SQLITE_FLOAT, /* 0x24 (not possible) */
SQLITE_NULL, /* 0x25 (not possible) */
@@ -88980,7 +90599,7 @@ SQLITE_API void sqlite3_value_free(sqlite3_value *pOld){
** is too big or if an OOM occurs.
**
** The invokeValueDestructor(P,X) routine invokes destructor function X()
-** on value P is not going to be used and need to be destroyed.
+** on value P if P is not going to be used and need to be destroyed.
*/
static void setResultStrOrError(
sqlite3_context *pCtx, /* Function context */
@@ -89010,7 +90629,7 @@ static void setResultStrOrError(
static int invokeValueDestructor(
const void *p, /* Value to destroy */
void (*xDel)(void*), /* The destructor */
- sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if no NULL */
+ sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if not NULL */
){
assert( xDel!=SQLITE_DYNAMIC );
if( xDel==0 ){
@@ -89020,7 +90639,14 @@ static int invokeValueDestructor(
}else{
xDel((void*)p);
}
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx!=0 ){
+ sqlite3_result_error_toobig(pCtx);
+ }
+#else
+ assert( pCtx!=0 );
sqlite3_result_error_toobig(pCtx);
+#endif
return SQLITE_TOOBIG;
}
SQLITE_API void sqlite3_result_blob(
@@ -89029,6 +90655,12 @@ SQLITE_API void sqlite3_result_blob(
int n,
void (*xDel)(void *)
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 || n<0 ){
+ invokeValueDestructor(z, xDel, pCtx);
+ return;
+ }
+#endif
assert( n>=0 );
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, 0, xDel);
@@ -89039,8 +90671,14 @@ SQLITE_API void sqlite3_result_blob64(
sqlite3_uint64 n,
void (*xDel)(void *)
){
- assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
assert( xDel!=SQLITE_DYNAMIC );
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ){
+ invokeValueDestructor(z, xDel, 0);
+ return;
+ }
+#endif
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
if( n>0x7fffffff ){
(void)invokeValueDestructor(z, xDel, pCtx);
}else{
@@ -89048,30 +90686,48 @@ SQLITE_API void sqlite3_result_blob64(
}
}
SQLITE_API void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetDouble(pCtx->pOut, rVal);
}
SQLITE_API void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_ERROR;
sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
}
#ifndef SQLITE_OMIT_UTF16
SQLITE_API void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_ERROR;
sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
}
#endif
SQLITE_API void sqlite3_result_int(sqlite3_context *pCtx, int iVal){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetInt64(pCtx->pOut, (i64)iVal);
}
SQLITE_API void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetInt64(pCtx->pOut, iVal);
}
SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetNull(pCtx->pOut);
}
@@ -89081,14 +90737,25 @@ SQLITE_API void sqlite3_result_pointer(
const char *zPType,
void (*xDestructor)(void*)
){
- Mem *pOut = pCtx->pOut;
+ Mem *pOut;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ){
+ invokeValueDestructor(pPtr, xDestructor, 0);
+ return;
+ }
+#endif
+ pOut = pCtx->pOut;
assert( sqlite3_mutex_held(pOut->db->mutex) );
sqlite3VdbeMemRelease(pOut);
pOut->flags = MEM_Null;
sqlite3VdbeMemSetPointer(pOut, pPtr, zPType, xDestructor);
}
SQLITE_API void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){
- Mem *pOut = pCtx->pOut;
+ Mem *pOut;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
+ pOut = pCtx->pOut;
assert( sqlite3_mutex_held(pOut->db->mutex) );
pOut->eSubtype = eSubtype & 0xff;
pOut->flags |= MEM_Subtype;
@@ -89099,6 +90766,12 @@ SQLITE_API void sqlite3_result_text(
int n,
void (*xDel)(void *)
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ){
+ invokeValueDestructor(z, xDel, 0);
+ return;
+ }
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel);
}
@@ -89109,6 +90782,12 @@ SQLITE_API void sqlite3_result_text64(
void (*xDel)(void *),
unsigned char enc
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ){
+ invokeValueDestructor(z, xDel, 0);
+ return;
+ }
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
assert( xDel!=SQLITE_DYNAMIC );
if( enc!=SQLITE_UTF8 ){
@@ -89119,6 +90798,7 @@ SQLITE_API void sqlite3_result_text64(
(void)invokeValueDestructor(z, xDel, pCtx);
}else{
setResultStrOrError(pCtx, z, (int)n, enc, xDel);
+ sqlite3VdbeMemZeroTerminateIfAble(pCtx->pOut);
}
}
#ifndef SQLITE_OMIT_UTF16
@@ -89151,7 +90831,16 @@ SQLITE_API void sqlite3_result_text16le(
}
#endif /* SQLITE_OMIT_UTF16 */
SQLITE_API void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
- Mem *pOut = pCtx->pOut;
+ Mem *pOut;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+ if( pValue==0 ){
+ sqlite3_result_null(pCtx);
+ return;
+ }
+#endif
+ pOut = pCtx->pOut;
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemCopy(pOut, pValue);
sqlite3VdbeChangeEncoding(pOut, pCtx->enc);
@@ -89163,7 +90852,12 @@ SQLITE_API void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
sqlite3_result_zeroblob64(pCtx, n>0 ? n : 0);
}
SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){
- Mem *pOut = pCtx->pOut;
+ Mem *pOut;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return SQLITE_MISUSE_BKPT;
+#endif
+ pOut = pCtx->pOut;
assert( sqlite3_mutex_held(pOut->db->mutex) );
if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){
sqlite3_result_error_toobig(pCtx);
@@ -89177,6 +90871,9 @@ SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){
#endif
}
SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
pCtx->isError = errCode ? errCode : -1;
#ifdef SQLITE_DEBUG
if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode;
@@ -89189,6 +90886,9 @@ SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
/* Force an SQLITE_TOOBIG error. */
SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_TOOBIG;
sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1,
@@ -89197,6 +90897,9 @@ SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){
/* An SQLITE_NOMEM error. */
SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetNull(pCtx->pOut);
pCtx->isError = SQLITE_NOMEM_BKPT;
@@ -89449,7 +91152,11 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
** pointer to it.
*/
SQLITE_API void *sqlite3_user_data(sqlite3_context *p){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ) return 0;
+#else
assert( p && p->pFunc );
+#endif
return p->pFunc->pUserData;
}
@@ -89464,7 +91171,11 @@ SQLITE_API void *sqlite3_user_data(sqlite3_context *p){
** application defined function.
*/
SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ) return 0;
+#else
assert( p && p->pOut );
+#endif
return p->pOut->db;
}
@@ -89483,7 +91194,11 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
** value, as a signal to the xUpdate routine that the column is unchanged.
*/
SQLITE_API int sqlite3_vtab_nochange(sqlite3_context *p){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ) return 0;
+#else
assert( p );
+#endif
return sqlite3_value_nochange(p->pOut);
}
@@ -89491,7 +91206,7 @@ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context *p){
** The destructor function for a ValueList object. This needs to be
** a separate function, unknowable to the application, to ensure that
** calls to sqlite3_vtab_in_first()/sqlite3_vtab_in_next() that are not
-** preceeded by activation of IN processing via sqlite3_vtab_int() do not
+** preceded by activation of IN processing via sqlite3_vtab_int() do not
** try to access a fake ValueList object inserted by a hostile extension.
*/
SQLITE_PRIVATE void sqlite3VdbeValueListFree(void *pToDelete){
@@ -89511,7 +91226,7 @@ static int valueFromValueList(
ValueList *pRhs;
*ppOut = 0;
- if( pVal==0 ) return SQLITE_MISUSE;
+ if( pVal==0 ) return SQLITE_MISUSE_BKPT;
if( (pVal->flags & MEM_Dyn)==0 || pVal->xDel!=sqlite3VdbeValueListFree ){
return SQLITE_ERROR;
}else{
@@ -89642,6 +91357,9 @@ SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
AuxData *pAuxData;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return 0;
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
#if SQLITE_ENABLE_STAT4
if( pCtx->pVdbe==0 ) return 0;
@@ -89674,8 +91392,12 @@ SQLITE_API void sqlite3_set_auxdata(
void (*xDelete)(void*)
){
AuxData *pAuxData;
- Vdbe *pVdbe = pCtx->pVdbe;
+ Vdbe *pVdbe;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
+ pVdbe= pCtx->pVdbe;
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
#ifdef SQLITE_ENABLE_STAT4
if( pVdbe==0 ) goto failed;
@@ -89731,7 +91453,8 @@ SQLITE_API int sqlite3_aggregate_count(sqlite3_context *p){
*/
SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt){
Vdbe *pVm = (Vdbe *)pStmt;
- return pVm ? pVm->nResColumn : 0;
+ if( pVm==0 ) return 0;
+ return pVm->nResColumn;
}
/*
@@ -89820,7 +91543,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
** sqlite3_column_real()
** sqlite3_column_bytes()
** sqlite3_column_bytes16()
-** sqiite3_column_blob()
+** sqlite3_column_blob()
*/
static void columnMallocFailure(sqlite3_stmt *pStmt)
{
@@ -89904,6 +91627,32 @@ SQLITE_API int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
return iType;
}
+/*
+** Column names appropriate for EXPLAIN or EXPLAIN QUERY PLAN.
+*/
+static const char * const azExplainColNames8[] = {
+ "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment", /* EXPLAIN */
+ "id", "parent", "notused", "detail" /* EQP */
+};
+static const u16 azExplainColNames16data[] = {
+ /* 0 */ 'a', 'd', 'd', 'r', 0,
+ /* 5 */ 'o', 'p', 'c', 'o', 'd', 'e', 0,
+ /* 12 */ 'p', '1', 0,
+ /* 15 */ 'p', '2', 0,
+ /* 18 */ 'p', '3', 0,
+ /* 21 */ 'p', '4', 0,
+ /* 24 */ 'p', '5', 0,
+ /* 27 */ 'c', 'o', 'm', 'm', 'e', 'n', 't', 0,
+ /* 35 */ 'i', 'd', 0,
+ /* 38 */ 'p', 'a', 'r', 'e', 'n', 't', 0,
+ /* 45 */ 'n', 'o', 't', 'u', 's', 'e', 'd', 0,
+ /* 53 */ 'd', 'e', 't', 'a', 'i', 'l', 0
+};
+static const u8 iExplainColNames16[] = {
+ 0, 5, 12, 15, 18, 21, 24, 27,
+ 35, 38, 45, 53
+};
+
/*
** Convert the N-th element of pStmt->pColName[] into a string using
** xFunc() then return that string. If N is out of range, return 0.
@@ -89936,15 +91685,29 @@ static const void *columnName(
return 0;
}
#endif
+ if( N<0 ) return 0;
ret = 0;
p = (Vdbe *)pStmt;
db = p->db;
assert( db!=0 );
- n = sqlite3_column_count(pStmt);
- if( N=0 ){
+ sqlite3_mutex_enter(db->mutex);
+
+ if( p->explain ){
+ if( useType>0 ) goto columnName_end;
+ n = p->explain==1 ? 8 : 4;
+ if( N>=n ) goto columnName_end;
+ if( useUtf16 ){
+ int i = iExplainColNames16[N + 8*p->explain - 8];
+ ret = (void*)&azExplainColNames16data[i];
+ }else{
+ ret = (void*)azExplainColNames8[N + 8*p->explain - 8];
+ }
+ goto columnName_end;
+ }
+ n = p->nResColumn;
+ if( NmallocFailed;
N += useType*n;
- sqlite3_mutex_enter(db->mutex);
- assert( db->mallocFailed==0 );
#ifndef SQLITE_OMIT_UTF16
if( useUtf16 ){
ret = sqlite3_value_text16((sqlite3_value*)&p->aColName[N]);
@@ -89956,12 +91719,14 @@ static const void *columnName(
/* A malloc may have failed inside of the _text() call. If this
** is the case, clear the mallocFailed flag and return NULL.
*/
- if( db->mallocFailed ){
+ assert( db->mallocFailed==0 || db->mallocFailed==1 );
+ if( db->mallocFailed > prior_mallocFailed ){
sqlite3OomClear(db);
ret = 0;
}
- sqlite3_mutex_leave(db->mutex);
}
+columnName_end:
+ sqlite3_mutex_leave(db->mutex);
return ret;
}
@@ -90054,7 +91819,7 @@ SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
/*
** Unbind the value bound to variable i in virtual machine p. This is the
** the same as binding a NULL value to the column. If the "i" parameter is
-** out of range, then SQLITE_RANGE is returned. Othewise SQLITE_OK.
+** out of range, then SQLITE_RANGE is returned. Otherwise SQLITE_OK.
**
** A successful evaluation of this routine acquires the mutex on p.
** the mutex is released if any kind of error occurs.
@@ -90069,7 +91834,7 @@ static int vdbeUnbind(Vdbe *p, unsigned int i){
}
sqlite3_mutex_enter(p->db->mutex);
if( p->eVdbeState!=VDBE_READY_STATE ){
- sqlite3Error(p->db, SQLITE_MISUSE);
+ sqlite3Error(p->db, SQLITE_MISUSE_BKPT);
sqlite3_mutex_leave(p->db->mutex);
sqlite3_log(SQLITE_MISUSE,
"bind on a busy prepared statement: [%s]", p->zSql);
@@ -90298,6 +92063,9 @@ SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint64 n){
int rc;
Vdbe *p = (Vdbe *)pStmt;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(p->db->mutex);
if( n>(u64)p->db->aLimit[SQLITE_LIMIT_LENGTH] ){
rc = SQLITE_TOOBIG;
@@ -90418,6 +92186,42 @@ SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt){
return pStmt ? ((Vdbe*)pStmt)->explain : 0;
}
+/*
+** Set the explain mode for a statement.
+*/
+SQLITE_API int sqlite3_stmt_explain(sqlite3_stmt *pStmt, int eMode){
+ Vdbe *v = (Vdbe*)pStmt;
+ int rc;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pStmt==0 ) return SQLITE_MISUSE_BKPT;
+#endif
+ sqlite3_mutex_enter(v->db->mutex);
+ if( ((int)v->explain)==eMode ){
+ rc = SQLITE_OK;
+ }else if( eMode<0 || eMode>2 ){
+ rc = SQLITE_ERROR;
+ }else if( (v->prepFlags & SQLITE_PREPARE_SAVESQL)==0 ){
+ rc = SQLITE_ERROR;
+ }else if( v->eVdbeState!=VDBE_READY_STATE ){
+ rc = SQLITE_BUSY;
+ }else if( v->nMem>=10 && (eMode!=2 || v->haveEqpOps) ){
+ /* No reprepare necessary */
+ v->explain = eMode;
+ rc = SQLITE_OK;
+ }else{
+ v->explain = eMode;
+ rc = sqlite3Reprepare(v);
+ v->haveEqpOps = eMode==2;
+ }
+ if( v->explain ){
+ v->nResColumn = 12 - 4*v->explain;
+ }else{
+ v->nResColumn = v->nResAlloc;
+ }
+ sqlite3_mutex_leave(v->db->mutex);
+ return rc;
+}
+
/*
** Return true if the prepared statement is in need of being reset.
*/
@@ -90458,7 +92262,7 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
u32 v;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !pStmt
- || (op!=SQLITE_STMTSTATUS_MEMUSED && (op<0||op>=ArraySize(pVdbe->aCounter)))
+ || (op!=SQLITE_STMTSTATUS_MEMUSED && (op<0||(op>=ArraySize(pVdbe->aCounter)&&oppPreUpdate;
+ PreUpdate *p;
Mem *pMem;
int rc = SQLITE_OK;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( db==0 || ppValue==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+ p = db->pPreUpdate;
/* Test that this call is being made from within an SQLITE_DELETE or
** SQLITE_UPDATE pre-update callback, and that iIdx is within range. */
if( !p || p->op==SQLITE_INSERT ){
@@ -90624,7 +92434,12 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa
** the number of columns in the row being updated, deleted or inserted.
*/
SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){
- PreUpdate *p = db->pPreUpdate;
+ PreUpdate *p;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ p = db!=0 ? db->pPreUpdate : 0;
+#else
+ p = db->pPreUpdate;
+#endif
return (p ? p->keyinfo.nKeyField : 0);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -90642,7 +92457,12 @@ SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){
** or SET DEFAULT action is considered a trigger.
*/
SQLITE_API int sqlite3_preupdate_depth(sqlite3 *db){
- PreUpdate *p = db->pPreUpdate;
+ PreUpdate *p;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ p = db!=0 ? db->pPreUpdate : 0;
+#else
+ p = db->pPreUpdate;
+#endif
return (p ? p->v->nFrame : 0);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -90653,7 +92473,12 @@ SQLITE_API int sqlite3_preupdate_depth(sqlite3 *db){
** only.
*/
SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *db){
- PreUpdate *p = db->pPreUpdate;
+ PreUpdate *p;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ p = db!=0 ? db->pPreUpdate : 0;
+#else
+ p = db->pPreUpdate;
+#endif
return (p ? p->iBlobWrite : -1);
}
#endif
@@ -90664,10 +92489,16 @@ SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *db){
** a field of the row currently being updated or inserted.
*/
SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
- PreUpdate *p = db->pPreUpdate;
+ PreUpdate *p;
int rc = SQLITE_OK;
Mem *pMem;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( db==0 || ppValue==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+ p = db->pPreUpdate;
if( !p || p->op==SQLITE_DELETE ){
rc = SQLITE_MISUSE_BKPT;
goto preupdate_new_out;
@@ -90746,15 +92577,33 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
void *pOut /* OUT: Write the answer here */
){
Vdbe *p = (Vdbe*)pStmt;
- ScanStatus *pScan;
+ VdbeOp *aOp;
+ int nOp;
+ ScanStatus *pScan = 0;
int idx;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 || pOut==0
+ || iScanStatusOpSQLITE_SCANSTAT_NCYCLE ){
+ return 1;
+ }
+#endif
+ aOp = p->aOp;
+ nOp = p->nOp;
+ if( p->pFrame ){
+ VdbeFrame *pFrame;
+ for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
+ aOp = pFrame->aOp;
+ nOp = pFrame->nOp;
+ }
+
if( iScan<0 ){
int ii;
if( iScanStatusOp==SQLITE_SCANSTAT_NCYCLE ){
i64 res = 0;
- for(ii=0; iinOp; ii++){
- res += p->aOp[ii].nCycle;
+ for(ii=0; iiaddrLoop>0 ){
- *(sqlite3_int64*)pOut = p->aOp[pScan->addrLoop].nExec;
+ *(sqlite3_int64*)pOut = aOp[pScan->addrLoop].nExec;
}else{
*(sqlite3_int64*)pOut = -1;
}
@@ -90788,7 +92637,7 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
}
case SQLITE_SCANSTAT_NVISIT: {
if( pScan->addrVisit>0 ){
- *(sqlite3_int64*)pOut = p->aOp[pScan->addrVisit].nExec;
+ *(sqlite3_int64*)pOut = aOp[pScan->addrVisit].nExec;
}else{
*(sqlite3_int64*)pOut = -1;
}
@@ -90810,7 +92659,7 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
}
case SQLITE_SCANSTAT_EXPLAIN: {
if( pScan->addrExplain ){
- *(const char**)pOut = p->aOp[ pScan->addrExplain ].p4.z;
+ *(const char**)pOut = aOp[ pScan->addrExplain ].p4.z;
}else{
*(const char**)pOut = 0;
}
@@ -90818,7 +92667,7 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
}
case SQLITE_SCANSTAT_SELECTID: {
if( pScan->addrExplain ){
- *(int*)pOut = p->aOp[ pScan->addrExplain ].p1;
+ *(int*)pOut = aOp[ pScan->addrExplain ].p1;
}else{
*(int*)pOut = -1;
}
@@ -90826,7 +92675,7 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
}
case SQLITE_SCANSTAT_PARENTID: {
if( pScan->addrExplain ){
- *(int*)pOut = p->aOp[ pScan->addrExplain ].p2;
+ *(int*)pOut = aOp[ pScan->addrExplain ].p2;
}else{
*(int*)pOut = -1;
}
@@ -90844,18 +92693,18 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
if( iIns==0 ) break;
if( iIns>0 ){
while( iIns<=iEnd ){
- res += p->aOp[iIns].nCycle;
+ res += aOp[iIns].nCycle;
iIns++;
}
}else{
int iOp;
- for(iOp=0; iOpnOp; iOp++){
- Op *pOp = &p->aOp[iOp];
+ for(iOp=0; iOpp1!=iEnd ) continue;
if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_NCYCLE)==0 ){
continue;
}
- res += p->aOp[iOp].nCycle;
+ res += aOp[iOp].nCycle;
}
}
}
@@ -90888,7 +92737,7 @@ SQLITE_API int sqlite3_stmt_scanstatus(
SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe*)pStmt;
int ii;
- for(ii=0; iinOp; ii++){
+ for(ii=0; p!=0 && iinOp; ii++){
Op *pOp = &p->aOp[ii];
pOp->nExec = 0;
pOp->nCycle = 0;
@@ -91654,6 +93503,9 @@ SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr){
sqlite3_str_appendchar(pStr, 1, (c>=0x20&&c<=0x7f) ? c : '.');
}
sqlite3_str_appendf(pStr, "]%s", encnames[pMem->enc]);
+ if( f & MEM_Term ){
+ sqlite3_str_appendf(pStr, "(0-term)");
+ }
}
}
#endif
@@ -91790,6 +93642,93 @@ static u64 filterHash(const Mem *aMem, const Op *pOp){
return h;
}
+
+/*
+** For OP_Column, factor out the case where content is loaded from
+** overflow pages, so that the code to implement this case is separate
+** the common case where all content fits on the page. Factoring out
+** the code reduces register pressure and helps the common case
+** to run faster.
+*/
+static SQLITE_NOINLINE int vdbeColumnFromOverflow(
+ VdbeCursor *pC, /* The BTree cursor from which we are reading */
+ int iCol, /* The column to read */
+ int t, /* The serial-type code for the column value */
+ i64 iOffset, /* Offset to the start of the content value */
+ u32 cacheStatus, /* Current Vdbe.cacheCtr value */
+ u32 colCacheCtr, /* Current value of the column cache counter */
+ Mem *pDest /* Store the value into this register. */
+){
+ int rc;
+ sqlite3 *db = pDest->db;
+ int encoding = pDest->enc;
+ int len = sqlite3VdbeSerialTypeLen(t);
+ assert( pC->eCurType==CURTYPE_BTREE );
+ if( len>db->aLimit[SQLITE_LIMIT_LENGTH] ) return SQLITE_TOOBIG;
+ if( len > 4000 && pC->pKeyInfo==0 ){
+ /* Cache large column values that are on overflow pages using
+ ** an RCStr (reference counted string) so that if they are reloaded,
+ ** that do not have to be copied a second time. The overhead of
+ ** creating and managing the cache is such that this is only
+ ** profitable for larger TEXT and BLOB values.
+ **
+ ** Only do this on table-btrees so that writes to index-btrees do not
+ ** need to clear the cache. This buys performance in the common case
+ ** in exchange for generality.
+ */
+ VdbeTxtBlbCache *pCache;
+ char *pBuf;
+ if( pC->colCache==0 ){
+ pC->pCache = sqlite3DbMallocZero(db, sizeof(VdbeTxtBlbCache) );
+ if( pC->pCache==0 ) return SQLITE_NOMEM;
+ pC->colCache = 1;
+ }
+ pCache = pC->pCache;
+ if( pCache->pCValue==0
+ || pCache->iCol!=iCol
+ || pCache->cacheStatus!=cacheStatus
+ || pCache->colCacheCtr!=colCacheCtr
+ || pCache->iOffset!=sqlite3BtreeOffset(pC->uc.pCursor)
+ ){
+ if( pCache->pCValue ) sqlite3RCStrUnref(pCache->pCValue);
+ pBuf = pCache->pCValue = sqlite3RCStrNew( len+3 );
+ if( pBuf==0 ) return SQLITE_NOMEM;
+ rc = sqlite3BtreePayload(pC->uc.pCursor, iOffset, len, pBuf);
+ if( rc ) return rc;
+ pBuf[len] = 0;
+ pBuf[len+1] = 0;
+ pBuf[len+2] = 0;
+ pCache->iCol = iCol;
+ pCache->cacheStatus = cacheStatus;
+ pCache->colCacheCtr = colCacheCtr;
+ pCache->iOffset = sqlite3BtreeOffset(pC->uc.pCursor);
+ }else{
+ pBuf = pCache->pCValue;
+ }
+ assert( t>=12 );
+ sqlite3RCStrRef(pBuf);
+ if( t&1 ){
+ rc = sqlite3VdbeMemSetStr(pDest, pBuf, len, encoding,
+ sqlite3RCStrUnref);
+ pDest->flags |= MEM_Term;
+ }else{
+ rc = sqlite3VdbeMemSetStr(pDest, pBuf, len, 0,
+ sqlite3RCStrUnref);
+ }
+ }else{
+ rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, iOffset, len, pDest);
+ if( rc ) return rc;
+ sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
+ if( (t&1)!=0 && encoding==SQLITE_UTF8 ){
+ pDest->z[len] = 0;
+ pDest->flags |= MEM_Term;
+ }
+ }
+ pDest->flags &= ~MEM_Ephem;
+ return rc;
+}
+
+
/*
** Return the symbolic name for the data type of a pMem
*/
@@ -91837,6 +93776,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
Mem *pIn2 = 0; /* 2nd input operand */
Mem *pIn3 = 0; /* 3rd input operand */
Mem *pOut = 0; /* Output operand */
+ u32 colCacheCtr = 0; /* Column cache counter */
#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
u64 *pnCycle = 0;
int bStmtScanStatus = IS_STMT_SCANSTATUS(db)!=0;
@@ -92032,8 +93972,8 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
case OP_Goto: { /* jump */
#ifdef SQLITE_DEBUG
- /* In debuggging mode, when the p5 flags is set on an OP_Goto, that
- ** means we should really jump back to the preceeding OP_ReleaseReg
+ /* In debugging mode, when the p5 flags is set on an OP_Goto, that
+ ** means we should really jump back to the preceding OP_ReleaseReg
** instruction. */
if( pOp->p5 ){
assert( pOp->p2 < (int)(pOp - aOp) );
@@ -92241,7 +94181,7 @@ case OP_HaltIfNull: { /* in3 */
** P5 is a value between 0 and 4, inclusive, that modifies the P4 string.
**
** 0: (no change)
-** 1: NOT NULL contraint failed: P4
+** 1: NOT NULL constraint failed: P4
** 2: UNIQUE constraint failed: P4
** 3: CHECK constraint failed: P4
** 4: FOREIGN KEY constraint failed: P4
@@ -93372,10 +95312,10 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
** opcodes are allowed to occur between this instruction and the previous
** OP_Lt or OP_Gt.
**
-** If result of an OP_Eq comparison on the same two operands as the
-** prior OP_Lt or OP_Gt would have been true, then jump to P2.
-** If the result of an OP_Eq comparison on the two previous
-** operands would have been false or NULL, then fall through.
+** If the result of an OP_Eq comparison on the same two operands as
+** the prior OP_Lt or OP_Gt would have been true, then jump to P2. If
+** the result of an OP_Eq comparison on the two previous operands
+** would have been false or NULL, then fall through.
*/
case OP_ElseEq: { /* same as TK_ESCAPE, jump */
@@ -93502,7 +95442,7 @@ case OP_Compare: {
/* Opcode: Jump P1 P2 P3 * *
**
** Jump to the instruction at address P1, P2, or P3 depending on whether
-** in the most recent OP_Compare instruction the P1 vector was less than
+** in the most recent OP_Compare instruction the P1 vector was less than,
** equal to, or greater than the P2 vector, respectively.
**
** This opcode must immediately follow an OP_Compare opcode.
@@ -93729,6 +95669,12 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */
** (0x01) bit. SQLITE_FLOAT is the 0x02 bit. SQLITE_TEXT is 0x04.
** SQLITE_BLOB is 0x08. SQLITE_NULL is 0x10.
**
+** WARNING: This opcode does not reliably distinguish between NULL and REAL
+** when P1>=0. If the database contains a NaN value, this opcode will think
+** that the datatype is REAL when it should be NULL. When P1<0 and the value
+** is already stored in register P3, then this opcode does reliably
+** distinguish between NULL and REAL. The problem only arises then P1>=0.
+**
** Take the jump to address P2 if and only if the datatype of the
** value determined by P1 and P3 corresponds to one of the bits in the
** P5 bitmask.
@@ -93799,7 +95745,7 @@ case OP_IsType: { /* jump */
/* Opcode: ZeroOrNull P1 P2 P3 * *
** Synopsis: r[P2] = 0 OR NULL
**
-** If all both registers P1 and P3 are NOT NULL, then store a zero in
+** If both registers P1 and P3 are NOT NULL, then store a zero in
** register P2. If either registers P1 or P3 are NULL then put
** a NULL in register P2.
*/
@@ -93842,7 +95788,7 @@ case OP_IfNullRow: { /* jump */
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1nCursor );
pC = p->apCsr[pOp->p1];
- if( ALWAYS(pC) && pC->nullRow ){
+ if( pC && pC->nullRow ){
sqlite3VdbeMemSetNull(aMem + pOp->p3);
goto jump_to_p2;
}
@@ -94153,11 +96099,16 @@ case OP_Column: { /* ncycle */
pDest->flags = aFlag[t&1];
}
}else{
+ u8 p5;
pDest->enc = encoding;
+ assert( pDest->db==db );
/* This branch happens only when content is on overflow pages */
- if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
- && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
- || (len = sqlite3VdbeSerialTypeLen(t))==0
+ if( ((p5 = (pOp->p5 & OPFLAG_BYTELENARG))!=0
+ && (p5==OPFLAG_TYPEOFARG
+ || (t>=12 && ((t&1)==0 || p5==OPFLAG_BYTELENARG))
+ )
+ )
+ || sqlite3VdbeSerialTypeLen(t)==0
){
/* Content is irrelevant for
** 1. the typeof() function,
@@ -94174,11 +96125,13 @@ case OP_Column: { /* ncycle */
*/
sqlite3VdbeSerialGet((u8*)sqlite3CtypeMap, t, pDest);
}else{
- if( len>db->aLimit[SQLITE_LIMIT_LENGTH] ) goto too_big;
- rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
- sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
- pDest->flags &= ~MEM_Ephem;
+ rc = vdbeColumnFromOverflow(pC, p2, t, aOffset[p2],
+ p->cacheCtr, colCacheCtr, pDest);
+ if( rc ){
+ if( rc==SQLITE_NOMEM ) goto no_mem;
+ if( rc==SQLITE_TOOBIG ) goto too_big;
+ goto abort_due_to_error;
+ }
}
}
@@ -94337,7 +96290,7 @@ case OP_Affinity: {
}else{
pIn1->u.r = (double)pIn1->u.i;
pIn1->flags |= MEM_Real;
- pIn1->flags &= ~MEM_Int;
+ pIn1->flags &= ~(MEM_Int|MEM_Str);
}
}
REGISTER_TRACE((int)(pIn1-aMem), pIn1);
@@ -94640,7 +96593,6 @@ case OP_MakeRecord: {
/* NULL value. No change in zPayload */
}else{
u64 v;
- u32 i;
if( serial_type==7 ){
assert( sizeof(v)==sizeof(pRec->u.r) );
memcpy(&v, &pRec->u.r, sizeof(v));
@@ -94648,12 +96600,17 @@ case OP_MakeRecord: {
}else{
v = pRec->u.i;
}
- len = i = sqlite3SmallTypeSizes[serial_type];
- assert( i>0 );
- while( 1 /*exit-by-break*/ ){
- zPayload[--i] = (u8)(v&0xFF);
- if( i==0 ) break;
- v >>= 8;
+ len = sqlite3SmallTypeSizes[serial_type];
+ assert( len>=1 && len<=8 && len!=5 && len!=7 );
+ switch( len ){
+ default: zPayload[7] = (u8)(v&0xff); v >>= 8;
+ zPayload[6] = (u8)(v&0xff); v >>= 8;
+ case 6: zPayload[5] = (u8)(v&0xff); v >>= 8;
+ zPayload[4] = (u8)(v&0xff); v >>= 8;
+ case 4: zPayload[3] = (u8)(v&0xff); v >>= 8;
+ case 3: zPayload[2] = (u8)(v&0xff); v >>= 8;
+ case 2: zPayload[1] = (u8)(v&0xff); v >>= 8;
+ case 1: zPayload[0] = (u8)(v&0xff);
}
zPayload += len;
}
@@ -94704,8 +96661,9 @@ case OP_Count: { /* out2 */
nEntry = sqlite3BtreeRowCountEst(pCrsr);
}else{
nEntry = 0; /* Not needed. Only used to silence a warning. */
- rc = sqlite3BtreeCount(db, pCrsr, &nEntry);
- p->aLibsqlCounter[LIBSQL_STMTSTATUS_ROWS_READ - LIBSQL_STMTSTATUS_BASE] += nEntry;
+ i64 nPages = 0;
+ rc = sqlite3BtreeCount(db, pCrsr, &nEntry, &nPages);
+ p->aLibsqlCounter[LIBSQL_STMTSTATUS_ROWS_READ - LIBSQL_STMTSTATUS_BASE] += nPages;
if( rc ) goto abort_due_to_error;
}
pOut = out2Prerelease(p, pOp);
@@ -95463,7 +97421,7 @@ case OP_OpenEphemeral: { /* ncycle */
}
pCx = p->apCsr[pOp->p1];
if( pCx && !pCx->noReuse && ALWAYS(pOp->p2<=pCx->nField) ){
- /* If the ephermeral table is already open and has no duplicates from
+ /* If the ephemeral table is already open and has no duplicates from
** OP_OpenDup, then erase all existing content so that the table is
** empty again, rather than creating a new table. */
assert( pCx->isEphemeral );
@@ -95474,7 +97432,7 @@ case OP_OpenEphemeral: { /* ncycle */
pCx = allocateCursor(p, pOp->p1, pOp->p2, CURTYPE_BTREE);
if( pCx==0 ) goto no_mem;
pCx->isEphemeral = 1;
- rc = sqlite3BtreeOpen(db->pVfs, db->pWalMethods, 0, db, &pCx->ub.pBtx,
+ rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->ub.pBtx,
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5,
vfsFlags);
if( rc==SQLITE_OK ){
@@ -95955,7 +97913,7 @@ case OP_SeekGT: { /* jump, in3, group, ncycle */
** row. If This.P5 is false (0) then a jump is made to SeekGE.P2. If
** This.P5 is true (non-zero) then a jump is made to This.P2. The P5==0
** case occurs when there are no inequality constraints to the right of
-** the IN constraing. The jump to SeekGE.P2 ends the loop. The P5!=0 case
+** the IN constraint. The jump to SeekGE.P2 ends the loop. The P5!=0 case
** occurs when there are inequality constraints to the right of the IN
** operator. In that case, the This.P2 will point either directly to or
** to setup code prior to the OP_IdxGT or OP_IdxGE opcode that checks for
@@ -95963,7 +97921,7 @@ case OP_SeekGT: { /* jump, in3, group, ncycle */
**
** Possible outcomes from this opcode:
**
-** - If the cursor is initally not pointed to any valid row, then
+**
- If the cursor is initially not pointed to any valid row, then
** fall through into the subsequent OP_SeekGE opcode.
**
**
- If the cursor is left pointing to a row that is before the target
@@ -96078,6 +98036,7 @@ case OP_SeekScan: { /* ncycle */
break;
}
nStep--;
+ pC->cacheStatus = CACHE_STALE;
rc = sqlite3BtreeNext(pC->uc.pCursor, 0);
if( rc ){
if( rc==SQLITE_DONE ){
@@ -96194,13 +98153,13 @@ case OP_IfNotOpen: { /* jump */
** operands to OP_NotFound and OP_IdxGT.
**
** This opcode is an optimization attempt only. If this opcode always
-** falls through, the correct answer is still obtained, but extra works
+** falls through, the correct answer is still obtained, but extra work
** is performed.
**
** A value of N in the seekHit flag of cursor P1 means that there exists
** a key P3:N that will match some record in the index. We want to know
** if it is possible for a record P3:P4 to match some record in the
-** index. If it is not possible, we can skips some work. So if seekHit
+** index. If it is not possible, we can skip some work. So if seekHit
** is less than P4, attempt to find out if a match is possible by running
** OP_NotFound.
**
@@ -96736,8 +98695,8 @@ case OP_Insert: {
#endif
assert( (pOp->p5 & OPFLAG_LASTROWID)==0 || (pOp->p5 & OPFLAG_NCHANGE)!=0 );
+ if (!pC->isEphemeral) p->aLibsqlCounter[LIBSQL_STMTSTATUS_ROWS_WRITTEN - LIBSQL_STMTSTATUS_BASE]++;
if( pOp->p5 & OPFLAG_NCHANGE ){
- p->aLibsqlCounter[LIBSQL_STMTSTATUS_ROWS_WRITTEN - LIBSQL_STMTSTATUS_BASE]++;
p->nChange++;
if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
}
@@ -96758,6 +98717,7 @@ case OP_Insert: {
);
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
+ colCacheCtr++;
/* Invoke the update-hook if required. */
if( rc ) goto abort_due_to_error;
@@ -96811,13 +98771,18 @@ case OP_RowCell: {
** left in an undefined state.
**
** If the OPFLAG_AUXDELETE bit is set on P5, that indicates that this
-** delete one of several associated with deleting a table row and all its
-** associated index entries. Exactly one of those deletes is the "primary"
-** delete. The others are all on OPFLAG_FORDELETE cursors or else are
-** marked with the AUXDELETE flag.
+** delete is one of several associated with deleting a table row and
+** all its associated index entries. Exactly one of those deletes is
+** the "primary" delete. The others are all on OPFLAG_FORDELETE
+** cursors or else are marked with the AUXDELETE flag.
**
-** If the OPFLAG_NCHANGE flag of P2 (NB: P2 not P5) is set, then the row
-** change count is incremented (otherwise not).
+** If the OPFLAG_NCHANGE (0x01) flag of P2 (NB: P2 not P5) is set, then
+** the row change count is incremented (otherwise not).
+**
+** If the OPFLAG_ISNOOP (0x40) flag of P2 (not P5!) is set, then the
+** pre-update-hook for deletes is run, but the btree is otherwise unchanged.
+** This happens when the OP_Delete is to be shortly followed by an OP_Insert
+** with the same key, causing the btree entry to be overwritten.
**
** P1 must not be pseudo-table. It has to be a real table with
** multiple rows.
@@ -96918,12 +98883,13 @@ case OP_Delete: {
rc = sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5);
pC->cacheStatus = CACHE_STALE;
+ colCacheCtr++;
pC->seekResult = 0;
if( rc ) goto abort_due_to_error;
/* Invoke the update-hook if required. */
if( opflags & OPFLAG_NCHANGE ){
- p->aLibsqlCounter[LIBSQL_STMTSTATUS_ROWS_WRITTEN - LIBSQL_STMTSTATUS_BASE]++;
+ if (!pC->isEphemeral) p->aLibsqlCounter[LIBSQL_STMTSTATUS_ROWS_WRITTEN - LIBSQL_STMTSTATUS_BASE]++;
p->nChange++;
if( db->xUpdateCallback && ALWAYS(pTab!=0) && HasRowid(pTab) ){
db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, pTab->zName,
@@ -96986,13 +98952,13 @@ case OP_SorterCompare: {
** Write into register P2 the current sorter data for sorter cursor P1.
** Then clear the column header cache on cursor P3.
**
-** This opcode is normally use to move a record out of the sorter and into
+** This opcode is normally used to move a record out of the sorter and into
** a register that is the source for a pseudo-table cursor created using
** OpenPseudo. That pseudo-table cursor is the one that is identified by
** parameter P3. Clearing the P3 column cache as part of this opcode saves
** us from having to issue a separate NullRow instruction to clear that cache.
*/
-case OP_SorterData: {
+case OP_SorterData: { /* ncycle */
VdbeCursor *pC;
pOut = &aMem[pOp->p2];
@@ -97211,6 +99177,7 @@ case OP_Last: { /* jump, ncycle */
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
if( rc ) goto abort_due_to_error;
+ p->aLibsqlCounter[LIBSQL_STMTSTATUS_ROWS_READ - LIBSQL_STMTSTATUS_BASE]++;
if( pOp->p2>0 ){
VdbeBranchTaken(res!=0,2);
if( res ) goto jump_to_p2;
@@ -97267,8 +99234,8 @@ case OP_IfSmaller: { /* jump */
** regression tests can determine whether or not the optimizer is
** correctly optimizing out sorts.
*/
-case OP_SorterSort: /* jump */
-case OP_Sort: { /* jump */
+case OP_SorterSort: /* jump ncycle */
+case OP_Sort: { /* jump ncycle */
#ifdef SQLITE_TEST
sqlite3_sort_count++;
sqlite3_search_count--;
@@ -97478,7 +99445,7 @@ case OP_IdxInsert: { /* in2 */
pIn2 = &aMem[pOp->p2];
assert( (pIn2->flags & MEM_Blob) || (pOp->p5 & OPFLAG_PREFORMAT) );
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
- if( pOp->p5 & OPFLAG_NCHANGE ) p->aLibsqlCounter[LIBSQL_STMTSTATUS_ROWS_WRITTEN - LIBSQL_STMTSTATUS_BASE]++;
+ if (!pC->isEphemeral) p->aLibsqlCounter[LIBSQL_STMTSTATUS_ROWS_WRITTEN - LIBSQL_STMTSTATUS_BASE]++;
assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->isTable==0 );
rc = ExpandBlob(pIn2);
@@ -97798,7 +99765,7 @@ case OP_IdxGE: { /* jump, ncycle */
** file is given by P1.
**
** The table being destroyed is in the main database file if P3==0. If
-** P3==1 then the table to be clear is in the auxiliary database file
+** P3==1 then the table to be destroyed is in the auxiliary database file
** that is used to store tables create using CREATE TEMPORARY TABLE.
**
** If AUTOVACUUM is enabled then it is possible that another root page
@@ -97858,8 +99825,8 @@ case OP_Destroy: { /* out2 */
** in the database file is given by P1. But, unlike Destroy, do not
** remove the table or index from the database file.
**
-** The table being clear is in the main database file if P2==0. If
-** P2==1 then the table to be clear is in the auxiliary database file
+** The table being cleared is in the main database file if P2==0. If
+** P2==1 then the table to be cleared is in the auxiliary database file
** that is used to store tables create using CREATE TEMPORARY TABLE.
**
** If the P3 value is non-zero, then the row change count is incremented
@@ -97879,7 +99846,7 @@ case OP_Clear: {
rc = sqlite3BtreeClearTable(db->aDb[pOp->p2].pBt, (u32)pOp->p1, &nChange);
if( pOp->p3 ){
p->nChange += nChange;
- p->aLibsqlCounter[LIBSQL_STMTSTATUS_ROWS_WRITTEN - LIBSQL_STMTSTATUS_BASE]++;
+ p->aLibsqlCounter[LIBSQL_STMTSTATUS_ROWS_WRITTEN - LIBSQL_STMTSTATUS_BASE] += nChange;
if( pOp->p3>0 ){
assert( memIsValid(&aMem[pOp->p3]) );
memAboutToChange(p, &aMem[pOp->p3]);
@@ -97946,13 +99913,41 @@ case OP_CreateBtree: { /* out2 */
/* Opcode: SqlExec * * * P4 *
**
** Run the SQL statement or statements specified in the P4 string.
+** Disable Auth and Trace callbacks while those statements are running if
+** P1 is true.
*/
case OP_SqlExec: {
+ char *zErr;
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ sqlite3_xauth xAuth;
+#endif
+ u8 mTrace;
+
sqlite3VdbeIncrWriteCounter(p, 0);
db->nSqlExec++;
- rc = sqlite3_exec(db, pOp->p4.z, 0, 0, 0);
+ zErr = 0;
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ xAuth = db->xAuth;
+#endif
+ mTrace = db->mTrace;
+ if( pOp->p1 ){
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ db->xAuth = 0;
+#endif
+ db->mTrace = 0;
+ }
+ rc = sqlite3_exec(db, pOp->p4.z, 0, 0, &zErr);
db->nSqlExec--;
- if( rc ) goto abort_due_to_error;
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ db->xAuth = xAuth;
+#endif
+ db->mTrace = mTrace;
+ if( zErr || rc ){
+ sqlite3VdbeError(p, "%s", zErr);
+ sqlite3_free(zErr);
+ if( rc==SQLITE_NOMEM ) goto no_mem;
+ goto abort_due_to_error;
+ }
break;
}
@@ -98686,7 +100681,7 @@ case OP_AggStep1: {
/* If this function is inside of a trigger, the register array in aMem[]
** might change from one evaluation to the next. The next block of code
** checks to see if the register array has changed, and if so it
- ** reinitializes the relavant parts of the sqlite3_context object */
+ ** reinitializes the relevant parts of the sqlite3_context object */
if( pCtx->pMem != pMem ){
pCtx->pMem = pMem;
for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
@@ -99173,6 +101168,53 @@ case OP_VOpen: { /* ncycle */
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VCheck P1 P2 P3 P4 *
+**
+** P4 is a pointer to a Table object that is a virtual table in schema P1
+** that supports the xIntegrity() method. This opcode runs the xIntegrity()
+** method for that virtual table, using P3 as the integer argument. If
+** an error is reported back, the table name is prepended to the error
+** message and that message is stored in P2. If no errors are seen,
+** register P2 is set to NULL.
+*/
+case OP_VCheck: { /* out2 */
+ Table *pTab;
+ sqlite3_vtab *pVtab;
+ const sqlite3_module *pModule;
+ char *zErr = 0;
+
+ pOut = &aMem[pOp->p2];
+ sqlite3VdbeMemSetNull(pOut); /* Innocent until proven guilty */
+ assert( pOp->p4type==P4_TABLE );
+ pTab = pOp->p4.pTab;
+ assert( pTab!=0 );
+ assert( IsVirtual(pTab) );
+ assert( pTab->u.vtab.p!=0 );
+ pVtab = pTab->u.vtab.p->pVtab;
+ assert( pVtab!=0 );
+ pModule = pVtab->pModule;
+ assert( pModule!=0 );
+ assert( pModule->iVersion>=4 );
+ assert( pModule->xIntegrity!=0 );
+ pTab->nTabRef++;
+ sqlite3VtabLock(pTab->u.vtab.p);
+ assert( pOp->p1>=0 && pOp->p1nDb );
+ rc = pModule->xIntegrity(pVtab, db->aDb[pOp->p1].zDbSName, pTab->zName,
+ pOp->p3, &zErr);
+ sqlite3VtabUnlock(pTab->u.vtab.p);
+ sqlite3DeleteTable(db, pTab);
+ if( rc ){
+ sqlite3_free(zErr);
+ goto abort_due_to_error;
+ }
+ if( zErr ){
+ sqlite3VdbeMemSetStr(pOut, zErr, -1, SQLITE_UTF8, sqlite3_free);
+ }
+ break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VInitIn P1 P2 P3 * *
** Synopsis: r[P2]=ValueList(P1,P3)
@@ -99223,11 +101265,11 @@ case OP_VPreparedSql: {
pModule = pVtab->pModule;
/* Invoke the xPreparedSql method */
- if( pModule->iVersion>=700 ){
- if( pModule->xPreparedSql && p->zSql ){
- rc = pModule->xPreparedSql(pVCur, p->zSql);
- if( rc ) goto abort_due_to_error;
- }
+ if( pModule->iVersion>=700 ) {
+ if (pModule->xPreparedSql && p->zSql) {
+ rc = pModule->xPreparedSql(pVCur, p->zSql);
+ if (rc) goto abort_due_to_error;
+ }
}
break;
@@ -99391,6 +101433,7 @@ case OP_VNext: { /* jump, ncycle */
rc = pModule->xNext(pCur->uc.pVCur);
sqlite3VtabImportErrmsg(p, pVtab);
if( rc ) goto abort_due_to_error;
+ p->aLibsqlCounter[LIBSQL_STMTSTATUS_ROWS_READ - LIBSQL_STMTSTATUS_BASE]++;
res = pModule->xEof(pCur->uc.pVCur);
VdbeBranchTaken(!res,2);
if( !res ){
@@ -99598,7 +101641,7 @@ case OP_MaxPgcnt: { /* out2 */
** This opcode works exactly like OP_Function. The only difference is in
** its name. This opcode is used in places where the function must be
** purely non-deterministic. Some built-in date/time functions can be
-** either determinitic of non-deterministic, depending on their arguments.
+** either deterministic of non-deterministic, depending on their arguments.
** When those function are used in a non-deterministic way, they will check
** to see if they were called using OP_PureFunc instead of OP_Function, and
** if they were, they throw an error.
@@ -99616,7 +101659,7 @@ case OP_Function: { /* group */
/* If this function is inside of a trigger, the register array in aMem[]
** might change from one evaluation to the next. The next block of code
** checks to see if the register array has changed, and if so it
- ** reinitializes the relavant parts of the sqlite3_context object */
+ ** reinitializes the relevant parts of the sqlite3_context object */
pOut = &aMem[pOp->p3];
if( pCtx->pOut != pOut ){
pCtx->pVdbe = p;
@@ -99692,7 +101735,7 @@ case OP_FilterAdd: {
printf("hash: %llu modulo %d -> %u\n", h, pIn1->n, (int)(h%pIn1->n));
}
#endif
- h %= pIn1->n;
+ h %= (pIn1->n*8);
pIn1->z[h/8] |= 1<<(h&7);
break;
}
@@ -99728,7 +101771,7 @@ case OP_Filter: { /* jump */
printf("hash: %llu modulo %d -> %u\n", h, pIn1->n, (int)(h%pIn1->n));
}
#endif
- h %= pIn1->n;
+ h %= (pIn1->n*8);
if( (pIn1->z[h/8] & (1<<(h&7)))==0 ){
VdbeBranchTaken(1, 2);
p->aCounter[SQLITE_STMTSTATUS_FILTER_HIT]++;
@@ -99980,7 +102023,7 @@ default: { /* This is really OP_Noop, OP_Explain */
}
if( opProperty==0xff ){
/* Never happens. This code exists to avoid a harmless linkage
- ** warning aboud sqlite3VdbeRegisterDump() being defined but not
+ ** warning about sqlite3VdbeRegisterDump() being defined but not
** used. */
sqlite3VdbeRegisterDump(p);
}
@@ -100153,8 +102196,7 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
/* Set the value of register r[1] in the SQL statement to integer iRow.
** This is done directly as a performance optimization
*/
- v->aMem[1].flags = MEM_Int;
- v->aMem[1].u.i = iRow;
+ sqlite3VdbeMemSetInt64(&v->aMem[1], iRow);
/* If the statement has been run before (and is paused at the OP_ResultRow)
** then back it up to the point where it does the OP_NotExists. This could
@@ -100237,7 +102279,7 @@ SQLITE_API int sqlite3_blob_open(
#endif
*ppBlob = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
- if( !sqlite3SafetyCheckOk(db) || zTable==0 ){
+ if( !sqlite3SafetyCheckOk(db) || zTable==0 || zColumn==0 ){
return SQLITE_MISUSE_BKPT;
}
#endif
@@ -100436,7 +102478,7 @@ SQLITE_API int sqlite3_blob_open(
if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt);
sqlite3DbFree(db, pBlob);
}
- sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
+ sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : (char*)0), zErr);
sqlite3DbFree(db, zErr);
sqlite3ParseObjectReset(&sParse);
rc = sqlite3ApiExit(db, rc);
@@ -100595,7 +102637,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
((Vdbe*)p->pStmt)->rc = SQLITE_OK;
rc = blobSeekToRow(p, iRow, &zErr);
if( rc!=SQLITE_OK ){
- sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
+ sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : (char*)0), zErr);
sqlite3DbFree(db, zErr);
}
assert( rc!=SQLITE_SCHEMA );
@@ -100698,7 +102740,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
** The threshold for the amount of main memory to use before flushing
** records to a PMA is roughly the same as the limit configured for the
** page-cache of the main database. Specifically, the threshold is set to
-** the value returned by "PRAGMA main.page_size" multipled by
+** the value returned by "PRAGMA main.page_size" multiplied by
** that returned by "PRAGMA main.cache_size", in bytes.
**
** If the sorter is running in single-threaded mode, then all PMAs generated
@@ -100721,7 +102763,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
**
** If there are fewer than SORTER_MAX_MERGE_COUNT PMAs in total and the
** sorter is running in single-threaded mode, then these PMAs are merged
-** incrementally as keys are retreived from the sorter by the VDBE. The
+** incrementally as keys are retrieved from the sorter by the VDBE. The
** MergeEngine object, described in further detail below, performs this
** merge.
**
@@ -100799,7 +102841,7 @@ struct SorterFile {
struct SorterList {
SorterRecord *pList; /* Linked list of records */
u8 *aMemory; /* If non-NULL, bulk memory to hold pList */
- int szPMA; /* Size of pList as PMA in bytes */
+ i64 szPMA; /* Size of pList as PMA in bytes */
};
/*
@@ -100884,7 +102926,7 @@ struct MergeEngine {
**
** Essentially, this structure contains all those fields of the VdbeSorter
** structure for which each thread requires a separate instance. For example,
-** each thread requries its own UnpackedRecord object to unpack records in
+** each thread requeries its own UnpackedRecord object to unpack records in
** as part of comparison operations.
**
** Before a background thread is launched, variable bDone is set to 0. Then,
@@ -100908,10 +102950,10 @@ typedef int (*SorterCompare)(SortSubtask*,int*,const void*,int,const void*,int);
struct SortSubtask {
SQLiteThread *pThread; /* Background thread, if any */
int bDone; /* Set if thread is finished but not joined */
+ int nPMA; /* Number of PMAs currently in file */
VdbeSorter *pSorter; /* Sorter that owns this sub-task */
UnpackedRecord *pUnpacked; /* Space to unpack a record */
SorterList list; /* List for thread to write to a PMA */
- int nPMA; /* Number of PMAs currently in file */
SorterCompare xCompare; /* Compare function to use */
SorterFile file; /* Temp file for level-0 PMAs */
SorterFile file2; /* Space for other PMAs */
@@ -100956,7 +102998,7 @@ struct VdbeSorter {
** PMA, in sorted order. The next key to be read is cached in nKey/aKey.
** aKey might point into aMap or into aBuffer. If neither of those locations
** contain a contiguous representation of the key, then aAlloc is allocated
-** and the key is copied into aAlloc and aKey is made to poitn to aAlloc.
+** and the key is copied into aAlloc and aKey is made to point to aAlloc.
**
** pFd==0 at EOF.
*/
@@ -102327,7 +104369,7 @@ static int vdbeSorterFlushPMA(VdbeSorter *pSorter){
** the background thread from a sub-tasks previous turn is still running,
** skip it. If the first (pSorter->nTask-1) sub-tasks are all still busy,
** fall back to using the final sub-task. The first (pSorter->nTask-1)
- ** sub-tasks are prefered as they use background threads - the final
+ ** sub-tasks are preferred as they use background threads - the final
** sub-task uses the main thread. */
for(i=0; iiPrev + i + 1) % nWorker;
@@ -102385,8 +104427,8 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite(
int rc = SQLITE_OK; /* Return Code */
SorterRecord *pNew; /* New list element */
int bFlush; /* True to flush contents of memory to PMA */
- int nReq; /* Bytes of memory required */
- int nPMA; /* Bytes of PMA space required */
+ i64 nReq; /* Bytes of memory required */
+ i64 nPMA; /* Bytes of PMA space required */
int t; /* serial type of first record field */
assert( pCsr->eCurType==CURTYPE_SORTER );
@@ -102811,7 +104853,7 @@ static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){
rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode);
- /* Set up the required files for pIncr. A multi-theaded IncrMerge object
+ /* Set up the required files for pIncr. A multi-threaded IncrMerge object
** requires two temp files to itself, whereas a single-threaded object
** only requires a region of pTask->file2. */
if( rc==SQLITE_OK ){
@@ -103451,6 +105493,8 @@ static int bytecodevtabConnect(
"p5 INT,"
"comment TEXT,"
"subprog TEXT,"
+ "nexec INT,"
+ "ncycle INT,"
"stmt HIDDEN"
");",
@@ -103613,7 +105657,7 @@ static int bytecodevtabColumn(
}
}
}
- i += 10;
+ i += 20;
}
}
switch( i ){
@@ -103663,16 +105707,31 @@ static int bytecodevtabColumn(
}
break;
}
- case 10: /* tables_used.type */
+
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ case 9: /* nexec */
+ sqlite3_result_int(ctx, pOp->nExec);
+ break;
+ case 10: /* ncycle */
+ sqlite3_result_int(ctx, pOp->nCycle);
+ break;
+#else
+ case 9: /* nexec */
+ case 10: /* ncycle */
+ sqlite3_result_int(ctx, 0);
+ break;
+#endif
+
+ case 20: /* tables_used.type */
sqlite3_result_text(ctx, pCur->zType, -1, SQLITE_STATIC);
break;
- case 11: /* tables_used.schema */
+ case 21: /* tables_used.schema */
sqlite3_result_text(ctx, pCur->zSchema, -1, SQLITE_STATIC);
break;
- case 12: /* tables_used.name */
+ case 22: /* tables_used.name */
sqlite3_result_text(ctx, pCur->zName, -1, SQLITE_STATIC);
break;
- case 13: /* tables_used.wr */
+ case 23: /* tables_used.wr */
sqlite3_result_int(ctx, pOp->opcode==OP_OpenWrite);
break;
}
@@ -103746,7 +105805,7 @@ static int bytecodevtabBestIndex(
int rc = SQLITE_CONSTRAINT;
struct sqlite3_index_constraint *p;
bytecodevtab *pVTab = (bytecodevtab*)tab;
- int iBaseCol = pVTab->bTablesUsed ? 4 : 8;
+ int iBaseCol = pVTab->bTablesUsed ? 4 : 10;
pIdxInfo->estimatedCost = (double)100;
pIdxInfo->estimatedRows = 100;
pIdxInfo->idxNum = 0;
@@ -103793,7 +105852,8 @@ static sqlite3_module bytecodevtabModule = {
/* xSavepoint */ 0,
/* xRelease */ 0,
/* xRollbackTo */ 0,
- /* xShadowName */ 0
+ /* xShadowName */ 0,
+ /* xIntegrity */ 0
};
@@ -104317,7 +106377,7 @@ static int walkWindowList(Walker *pWalker, Window *pList, int bOneOnly){
** The return value from this routine is WRC_Abort to abandon the tree walk
** and WRC_Continue to continue.
*/
-static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
+SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3WalkExprNN(Walker *pWalker, Expr *pExpr){
int rc;
testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
testcase( ExprHasProperty(pExpr, EP_Reduced) );
@@ -104326,7 +106386,9 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
if( rc ) return rc & WRC_Abort;
if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
assert( pExpr->x.pList==0 || pExpr->pRight==0 );
- if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
+ if( pExpr->pLeft && sqlite3WalkExprNN(pWalker, pExpr->pLeft) ){
+ return WRC_Abort;
+ }
if( pExpr->pRight ){
assert( !ExprHasProperty(pExpr, EP_WinFunc) );
pExpr = pExpr->pRight;
@@ -104350,7 +106412,7 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
return WRC_Continue;
}
SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
- return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue;
+ return pExpr ? sqlite3WalkExprNN(pWalker,pExpr) : WRC_Continue;
}
/*
@@ -104476,7 +106538,7 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){
}
/* Increase the walkerDepth when entering a subquery, and
-** descrease when leaving the subquery.
+** decrease when leaving the subquery.
*/
SQLITE_PRIVATE int sqlite3WalkerDepthIncrease(Walker *pWalker, Select *pSelect){
UNUSED_PARAMETER(pSelect);
@@ -104620,21 +106682,36 @@ static void resolveAlias(
}
/*
-** Subqueries stores the original database, table and column names for their
-** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN".
-** Check to see if the zSpan given to this routine matches the zDb, zTab,
-** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will
-** match anything.
+** Subqueries store the original database, table and column names for their
+** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN",
+** and mark the expression-list item by setting ExprList.a[].fg.eEName
+** to ENAME_TAB.
+**
+** Check to see if the zSpan/eEName of the expression-list item passed to this
+** routine matches the zDb, zTab, and zCol. If any of zDb, zTab, and zCol are
+** NULL then those fields will match anything. Return true if there is a match,
+** or false otherwise.
+**
+** SF_NestedFrom subqueries also store an entry for the implicit rowid (or
+** _rowid_, or oid) column by setting ExprList.a[].fg.eEName to ENAME_ROWID,
+** and setting zSpan to "DATABASE.TABLE.". This type of pItem
+** argument matches if zCol is a rowid alias. If it is not NULL, (*pbRowid)
+** is set to 1 if there is this kind of match.
*/
SQLITE_PRIVATE int sqlite3MatchEName(
const struct ExprList_item *pItem,
const char *zCol,
const char *zTab,
- const char *zDb
+ const char *zDb,
+ int *pbRowid
){
int n;
const char *zSpan;
- if( pItem->fg.eEName!=ENAME_TAB ) return 0;
+ int eEName = pItem->fg.eEName;
+ if( eEName!=ENAME_TAB && (eEName!=ENAME_ROWID || NEVER(pbRowid==0)) ){
+ return 0;
+ }
+ assert( pbRowid==0 || *pbRowid==0 );
zSpan = pItem->zEName;
for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){
@@ -104646,9 +106723,11 @@ SQLITE_PRIVATE int sqlite3MatchEName(
return 0;
}
zSpan += n+1;
- if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){
- return 0;
+ if( zCol ){
+ if( eEName==ENAME_TAB && sqlite3StrICmp(zSpan, zCol)!=0 ) return 0;
+ if( eEName==ENAME_ROWID && sqlite3IsRowid(zCol)==0 ) return 0;
}
+ if( eEName==ENAME_ROWID ) *pbRowid = 1;
return 1;
}
@@ -104781,7 +106860,7 @@ static int lookupName(
){
int i, j; /* Loop counters */
int cnt = 0; /* Number of matching column names */
- int cntTab = 0; /* Number of matching table names */
+ int cntTab = 0; /* Number of potential "rowid" matches */
int nSubquery = 0; /* How many levels of subquery */
sqlite3 *db = pParse->db; /* The database connection */
SrcItem *pItem; /* Use for looping over pSrcList items */
@@ -104858,39 +106937,49 @@ static int lookupName(
assert( pEList!=0 );
assert( pEList->nExpr==pTab->nCol );
for(j=0; jnExpr; j++){
- if( !sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb) ){
+ int bRowid = 0; /* True if possible rowid match */
+ if( !sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb, &bRowid) ){
continue;
}
- if( cnt>0 ){
- if( pItem->fg.isUsing==0
- || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
- ){
- /* Two or more tables have the same column name which is
- ** not joined by USING. This is an error. Signal as much
- ** by clearing pFJMatch and letting cnt go above 1. */
- sqlite3ExprListDelete(db, pFJMatch);
- pFJMatch = 0;
- }else
- if( (pItem->fg.jointype & JT_RIGHT)==0 ){
- /* An INNER or LEFT JOIN. Use the left-most table */
- continue;
- }else
- if( (pItem->fg.jointype & JT_LEFT)==0 ){
- /* A RIGHT JOIN. Use the right-most table */
- cnt = 0;
- sqlite3ExprListDelete(db, pFJMatch);
- pFJMatch = 0;
- }else{
- /* For a FULL JOIN, we must construct a coalesce() func */
- extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
+ if( bRowid==0 ){
+ if( cnt>0 ){
+ if( pItem->fg.isUsing==0
+ || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
+ ){
+ /* Two or more tables have the same column name which is
+ ** not joined by USING. This is an error. Signal as much
+ ** by clearing pFJMatch and letting cnt go above 1. */
+ sqlite3ExprListDelete(db, pFJMatch);
+ pFJMatch = 0;
+ }else
+ if( (pItem->fg.jointype & JT_RIGHT)==0 ){
+ /* An INNER or LEFT JOIN. Use the left-most table */
+ continue;
+ }else
+ if( (pItem->fg.jointype & JT_LEFT)==0 ){
+ /* A RIGHT JOIN. Use the right-most table */
+ cnt = 0;
+ sqlite3ExprListDelete(db, pFJMatch);
+ pFJMatch = 0;
+ }else{
+ /* For a FULL JOIN, we must construct a coalesce() func */
+ extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
+ }
}
+ cnt++;
+ hit = 1;
+ }else if( cnt>0 ){
+ /* This is a potential rowid match, but there has already been
+ ** a real match found. So this can be ignored. */
+ continue;
}
- cnt++;
- cntTab = 2;
+ cntTab++;
pMatch = pItem;
pExpr->iColumn = j;
pEList->a[j].fg.bUsed = 1;
- hit = 1;
+
+ /* rowid cannot be part of a USING clause - assert() this. */
+ assert( bRowid==0 || pEList->a[j].fg.bUsingTerm==0 );
if( pEList->a[j].fg.bUsingTerm ) break;
}
if( hit || zTab==0 ) continue;
@@ -104983,7 +107072,8 @@ static int lookupName(
assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT );
if( pParse->bReturning ){
if( (pNC->ncFlags & NC_UBaseReg)!=0
- && (zTab==0 || sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0)
+ && ALWAYS(zTab==0
+ || sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0)
){
pExpr->iTable = op!=TK_DELETE;
pTab = pParse->pTriggerTab;
@@ -105084,10 +107174,10 @@ static int lookupName(
&& pMatch
&& (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0
&& sqlite3IsRowid(zCol)
- && ALWAYS(VisibleRowid(pMatch->pTab))
+ && ALWAYS(VisibleRowid(pMatch->pTab) || pMatch->fg.isNestedFrom)
){
cnt = 1;
- pExpr->iColumn = -1;
+ if( pMatch->fg.isNestedFrom==0 ) pExpr->iColumn = -1;
pExpr->affExpr = SQLITE_AFF_INTEGER;
}
@@ -105540,6 +107630,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
Window *pWin = (IsWindowFunc(pExpr) ? pExpr->y.pWin : 0);
#endif
assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) );
+ assert( pExpr->pLeft==0 || pExpr->pLeft->op==TK_ORDER );
zId = pExpr->u.zToken;
pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0);
if( pDef==0 ){
@@ -105681,6 +107772,10 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pNC->nNcErr++;
}
#endif
+ else if( is_agg==0 && pExpr->pLeft ){
+ sqlite3ExprOrderByAggregateError(pParse, pExpr);
+ pNC->nNcErr++;
+ }
if( is_agg ){
/* Window functions may not be arguments of aggregate functions.
** Or arguments of other window functions. But aggregate functions
@@ -105699,6 +107794,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
#endif
sqlite3WalkExprList(pWalker, pList);
if( is_agg ){
+ if( pExpr->pLeft ){
+ assert( pExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pExpr->pLeft) );
+ sqlite3WalkExprList(pWalker, pExpr->pLeft->x.pList);
+ }
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pWin ){
Select *pSel = pNC->pWinSelect;
@@ -105768,8 +107868,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
assert( pNC->nRef>=nRef );
if( nRef!=pNC->nRef ){
ExprSetProperty(pExpr, EP_VarSelect);
- pNC->ncFlags |= NC_VarSelect;
}
+ pNC->ncFlags |= NC_Subquery;
}
break;
}
@@ -106209,7 +108309,7 @@ static int resolveOrderGroupBy(
}
for(j=0; jpEList->nExpr; j++){
if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){
- /* Since this expresion is being changed into a reference
+ /* Since this expression is being changed into a reference
** to an identical expression in the result set, remove all Window
** objects belonging to the expression from the Select.pWin list. */
windowRemoveExprFromSelect(pSelect, pE);
@@ -106262,10 +108362,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
while( p ){
assert( (p->selFlags & SF_Expanded)!=0 );
assert( (p->selFlags & SF_Resolved)==0 );
- assert( db->suppressErr==0 ); /* SF_Resolved not set if errors suppressed */
p->selFlags |= SF_Resolved;
-
/* Resolve the expressions in the LIMIT and OFFSET clauses. These
** are not allowed to refer to any names, so pass an empty NameContext.
*/
@@ -106532,7 +108630,8 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
return SQLITE_ERROR;
}
#endif
- sqlite3WalkExpr(&w, pExpr);
+ assert( pExpr!=0 );
+ sqlite3WalkExprNN(&w, pExpr);
#if SQLITE_MAX_EXPR_DEPTH>0
w.pParse->nHeight -= pExpr->nHeight;
#endif
@@ -106574,7 +108673,7 @@ SQLITE_PRIVATE int sqlite3ResolveExprListNames(
return WRC_Abort;
}
#endif
- sqlite3WalkExpr(&w, pExpr);
+ sqlite3WalkExprNN(&w, pExpr);
#if SQLITE_MAX_EXPR_DEPTH>0
w.pParse->nHeight -= pExpr->nHeight;
#endif
@@ -106596,7 +108695,7 @@ SQLITE_PRIVATE int sqlite3ResolveExprListNames(
/*
** Resolve all names in all expressions of a SELECT and in all
-** decendents of the SELECT, including compounds off of p->pPrior,
+** descendants of the SELECT, including compounds off of p->pPrior,
** subqueries in expressions, and subqueries used as FROM clause
** terms.
**
@@ -106746,6 +108845,7 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr){
if( op==TK_SELECT_COLUMN ){
assert( pExpr->pLeft!=0 && ExprUseXSelect(pExpr->pLeft) );
assert( pExpr->iColumn < pExpr->iTable );
+ assert( pExpr->iColumn >= 0 );
assert( pExpr->iTable==pExpr->pLeft->x.pSelect->pEList->nExpr );
return sqlite3ExprAffinity(
pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
@@ -106957,11 +109057,10 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
}else{
Expr *pNext = p->pRight;
/* The Expr.x union is never used at the same time as Expr.pRight */
- assert( ExprUseXList(p) );
- assert( p->x.pList==0 || p->pRight==0 );
- if( p->x.pList!=0 && !db->mallocFailed ){
+ assert( !ExprUseXList(p) || p->x.pList==0 || p->pRight==0 );
+ if( ExprUseXList(p) && p->x.pList!=0 && !db->mallocFailed ){
int i;
- for(i=0; ALWAYS(ix.pList->nExpr); i++){
+ for(i=0; ix.pList->nExpr; i++){
if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){
pNext = p->x.pList->a[i].pExpr;
break;
@@ -106983,7 +109082,7 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
/*
** Return the collation sequence for the expression pExpr. If
** there is no defined collating sequence, return a pointer to the
-** defautl collation sequence.
+** default collation sequence.
**
** See also: sqlite3ExprCollSeq()
**
@@ -107113,7 +109212,7 @@ SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(
return pColl;
}
-/* Expresssion p is a comparison operator. Return a collation sequence
+/* Expression p is a comparison operator. Return a collation sequence
** appropriate for the comparison operator.
**
** This is normally just a wrapper around sqlite3BinaryCompareCollSeq().
@@ -107270,6 +109369,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(
*/
pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0);
if( pRet ){
+ ExprSetProperty(pRet, EP_FullSize);
pRet->iTable = nField;
pRet->iColumn = iField;
pRet->pLeft = pVector;
@@ -107569,6 +109669,15 @@ SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
#define exprSetHeight(y)
#endif /* SQLITE_MAX_EXPR_DEPTH>0 */
+/*
+** Set the error offset for an Expr node, if possible.
+*/
+SQLITE_PRIVATE void sqlite3ExprSetErrorOffset(Expr *pExpr, int iOfst){
+ if( pExpr==0 ) return;
+ if( NEVER(ExprUseWJoin(pExpr)) ) return;
+ pExpr->w.iOfst = iOfst;
+}
+
/*
** This routine is the core allocator for Expr nodes.
**
@@ -107793,9 +109902,9 @@ SQLITE_PRIVATE Select *sqlite3ExprListToValues(Parse *pParse, int nElem, ExprLis
** Join two expressions using an AND operator. If either expression is
** NULL, then just return the other expression.
**
-** If one side or the other of the AND is known to be false, then instead
-** of returning an AND expression, just return a constant expression with
-** a value of false.
+** If one side or the other of the AND is known to be false, and neither side
+** is part of an ON clause, then instead of returning an AND expression,
+** just return a constant expression with a value of false.
*/
SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
sqlite3 *db = pParse->db;
@@ -107803,14 +109912,17 @@ SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
return pRight;
}else if( pRight==0 ){
return pLeft;
- }else if( (ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight))
- && !IN_RENAME_OBJECT
- ){
- sqlite3ExprDeferredDelete(pParse, pLeft);
- sqlite3ExprDeferredDelete(pParse, pRight);
- return sqlite3Expr(db, TK_INTEGER, "0");
}else{
- return sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
+ u32 f = pLeft->flags | pRight->flags;
+ if( (f&(EP_OuterON|EP_InnerON|EP_IsFalse))==EP_IsFalse
+ && !IN_RENAME_OBJECT
+ ){
+ sqlite3ExprDeferredDelete(pParse, pLeft);
+ sqlite3ExprDeferredDelete(pParse, pRight);
+ return sqlite3Expr(db, TK_INTEGER, "0");
+ }else{
+ return sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
+ }
}
}
@@ -107848,6 +109960,69 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(
return pNew;
}
+/*
+** Report an error when attempting to use an ORDER BY clause within
+** the arguments of a non-aggregate function.
+*/
+SQLITE_PRIVATE void sqlite3ExprOrderByAggregateError(Parse *pParse, Expr *p){
+ sqlite3ErrorMsg(pParse,
+ "ORDER BY may not be used with non-aggregate %#T()", p
+ );
+}
+
+/*
+** Attach an ORDER BY clause to a function call.
+**
+** functionname( arguments ORDER BY sortlist )
+** \_____________________/ \______/
+** pExpr pOrderBy
+**
+** The ORDER BY clause is inserted into a new Expr node of type TK_ORDER
+** and added to the Expr.pLeft field of the parent TK_FUNCTION node.
+*/
+SQLITE_PRIVATE void sqlite3ExprAddFunctionOrderBy(
+ Parse *pParse, /* Parsing context */
+ Expr *pExpr, /* The function call to which ORDER BY is to be added */
+ ExprList *pOrderBy /* The ORDER BY clause to add */
+){
+ Expr *pOB;
+ sqlite3 *db = pParse->db;
+ if( NEVER(pOrderBy==0) ){
+ assert( db->mallocFailed );
+ return;
+ }
+ if( pExpr==0 ){
+ assert( db->mallocFailed );
+ sqlite3ExprListDelete(db, pOrderBy);
+ return;
+ }
+ assert( pExpr->op==TK_FUNCTION );
+ assert( pExpr->pLeft==0 );
+ assert( ExprUseXList(pExpr) );
+ if( pExpr->x.pList==0 || NEVER(pExpr->x.pList->nExpr==0) ){
+ /* Ignore ORDER BY on zero-argument aggregates */
+ sqlite3ParserAddCleanup(pParse,
+ (void(*)(sqlite3*,void*))sqlite3ExprListDelete,
+ pOrderBy);
+ return;
+ }
+ if( IsWindowFunc(pExpr) ){
+ sqlite3ExprOrderByAggregateError(pParse, pExpr);
+ sqlite3ExprListDelete(db, pOrderBy);
+ return;
+ }
+
+ pOB = sqlite3ExprAlloc(db, TK_ORDER, 0, 0);
+ if( pOB==0 ){
+ sqlite3ExprListDelete(db, pOrderBy);
+ return;
+ }
+ pOB->x.pList = pOrderBy;
+ assert( ExprUseXList(pOB) );
+ pExpr->pLeft = pOB;
+ ExprSetProperty(pOB, EP_FullSize);
+}
+
/*
** Check to see if a function is usable according to current access
** rules:
@@ -108026,7 +110201,7 @@ SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3 *db, OnOrUsing *p){
/*
** Arrange to cause pExpr to be deleted when the pParse is deleted.
** This is similar to sqlite3ExprDelete() except that the delete is
-** deferred untilthe pParse is deleted.
+** deferred until the pParse is deleted.
**
** The pExpr might be deleted immediately on an OOM error.
**
@@ -108101,11 +110276,7 @@ static int dupedExprStructSize(const Expr *p, int flags){
assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */
assert( EXPR_FULLSIZE<=0xfff );
assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 );
- if( 0==flags || p->op==TK_SELECT_COLUMN
-#ifndef SQLITE_OMIT_WINDOWFUNC
- || ExprHasProperty(p, EP_WinFunc)
-#endif
- ){
+ if( 0==flags || ExprHasProperty(p, EP_FullSize) ){
nSize = EXPR_FULLSIZE;
}else{
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
@@ -108136,56 +110307,93 @@ static int dupedExprNodeSize(const Expr *p, int flags){
/*
** Return the number of bytes required to create a duplicate of the
-** expression passed as the first argument. The second argument is a
-** mask containing EXPRDUP_XXX flags.
+** expression passed as the first argument.
**
** The value returned includes space to create a copy of the Expr struct
** itself and the buffer referred to by Expr.u.zToken, if any.
**
-** If the EXPRDUP_REDUCE flag is set, then the return value includes
-** space to duplicate all Expr nodes in the tree formed by Expr.pLeft
-** and Expr.pRight variables (but not for any structures pointed to or
-** descended from the Expr.x.pList or Expr.x.pSelect variables).
+** The return value includes space to duplicate all Expr nodes in the
+** tree formed by Expr.pLeft and Expr.pRight, but not any other
+** substructure such as Expr.x.pList, Expr.x.pSelect, and Expr.y.pWin.
*/
-static int dupedExprSize(const Expr *p, int flags){
- int nByte = 0;
- if( p ){
- nByte = dupedExprNodeSize(p, flags);
- if( flags&EXPRDUP_REDUCE ){
- nByte += dupedExprSize(p->pLeft, flags) + dupedExprSize(p->pRight, flags);
- }
- }
+static int dupedExprSize(const Expr *p){
+ int nByte;
+ assert( p!=0 );
+ nByte = dupedExprNodeSize(p, EXPRDUP_REDUCE);
+ if( p->pLeft ) nByte += dupedExprSize(p->pLeft);
+ if( p->pRight ) nByte += dupedExprSize(p->pRight);
+ assert( nByte==ROUND8(nByte) );
return nByte;
}
/*
-** This function is similar to sqlite3ExprDup(), except that if pzBuffer
-** is not NULL then *pzBuffer is assumed to point to a buffer large enough
-** to store the copy of expression p, the copies of p->u.zToken
-** (if applicable), and the copies of the p->pLeft and p->pRight expressions,
-** if any. Before returning, *pzBuffer is set to the first byte past the
-** portion of the buffer copied into by this function.
+** An EdupBuf is a memory allocation used to stored multiple Expr objects
+** together with their Expr.zToken content. This is used to help implement
+** compression while doing sqlite3ExprDup(). The top-level Expr does the
+** allocation for itself and many of its decendents, then passes an instance
+** of the structure down into exprDup() so that they decendents can have
+** access to that memory.
+*/
+typedef struct EdupBuf EdupBuf;
+struct EdupBuf {
+ u8 *zAlloc; /* Memory space available for storage */
+#ifdef SQLITE_DEBUG
+ u8 *zEnd; /* First byte past the end of memory */
+#endif
+};
+
+/*
+** This function is similar to sqlite3ExprDup(), except that if pEdupBuf
+** is not NULL then it points to memory that can be used to store a copy
+** of the input Expr p together with its p->u.zToken (if any). pEdupBuf
+** is updated with the new buffer tail prior to returning.
*/
-static Expr *exprDup(sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){
+static Expr *exprDup(
+ sqlite3 *db, /* Database connection (for memory allocation) */
+ const Expr *p, /* Expr tree to be duplicated */
+ int dupFlags, /* EXPRDUP_REDUCE for compression. 0 if not */
+ EdupBuf *pEdupBuf /* Preallocated storage space, or NULL */
+){
Expr *pNew; /* Value to return */
- u8 *zAlloc; /* Memory space from which to build Expr object */
+ EdupBuf sEdupBuf; /* Memory space from which to build Expr object */
u32 staticFlag; /* EP_Static if space not obtained from malloc */
+ int nToken = -1; /* Space needed for p->u.zToken. -1 means unknown */
assert( db!=0 );
assert( p );
assert( dupFlags==0 || dupFlags==EXPRDUP_REDUCE );
- assert( pzBuffer==0 || dupFlags==EXPRDUP_REDUCE );
+ assert( pEdupBuf==0 || dupFlags==EXPRDUP_REDUCE );
/* Figure out where to write the new Expr structure. */
- if( pzBuffer ){
- zAlloc = *pzBuffer;
+ if( pEdupBuf ){
+ sEdupBuf.zAlloc = pEdupBuf->zAlloc;
+#ifdef SQLITE_DEBUG
+ sEdupBuf.zEnd = pEdupBuf->zEnd;
+#endif
staticFlag = EP_Static;
- assert( zAlloc!=0 );
+ assert( sEdupBuf.zAlloc!=0 );
+ assert( dupFlags==EXPRDUP_REDUCE );
}else{
- zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, dupFlags));
+ int nAlloc;
+ if( dupFlags ){
+ nAlloc = dupedExprSize(p);
+ }else if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
+ nToken = sqlite3Strlen30NN(p->u.zToken)+1;
+ nAlloc = ROUND8(EXPR_FULLSIZE + nToken);
+ }else{
+ nToken = 0;
+ nAlloc = ROUND8(EXPR_FULLSIZE);
+ }
+ assert( nAlloc==ROUND8(nAlloc) );
+ sEdupBuf.zAlloc = sqlite3DbMallocRawNN(db, nAlloc);
+#ifdef SQLITE_DEBUG
+ sEdupBuf.zEnd = sEdupBuf.zAlloc ? sEdupBuf.zAlloc+nAlloc : 0;
+#endif
+
staticFlag = 0;
}
- pNew = (Expr *)zAlloc;
+ pNew = (Expr *)sEdupBuf.zAlloc;
+ assert( EIGHT_BYTE_ALIGNMENT(pNew) );
if( pNew ){
/* Set nNewSize to the size allocated for the structure pointed to
@@ -108194,22 +110402,27 @@ static Expr *exprDup(sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){
** by the copy of the p->u.zToken string (if any).
*/
const unsigned nStructSize = dupedExprStructSize(p, dupFlags);
- const int nNewSize = nStructSize & 0xfff;
- int nToken;
- if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
- nToken = sqlite3Strlen30(p->u.zToken) + 1;
- }else{
- nToken = 0;
+ int nNewSize = nStructSize & 0xfff;
+ if( nToken<0 ){
+ if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
+ nToken = sqlite3Strlen30(p->u.zToken) + 1;
+ }else{
+ nToken = 0;
+ }
}
if( dupFlags ){
+ assert( (int)(sEdupBuf.zEnd - sEdupBuf.zAlloc) >= nNewSize+nToken );
assert( ExprHasProperty(p, EP_Reduced)==0 );
- memcpy(zAlloc, p, nNewSize);
+ memcpy(sEdupBuf.zAlloc, p, nNewSize);
}else{
u32 nSize = (u32)exprStructSize(p);
- memcpy(zAlloc, p, nSize);
+ assert( (int)(sEdupBuf.zEnd - sEdupBuf.zAlloc) >=
+ (int)EXPR_FULLSIZE+nToken );
+ memcpy(sEdupBuf.zAlloc, p, nSize);
if( nSizeu.zToken string, if any. */
- if( nToken ){
- char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize];
+ assert( nToken>=0 );
+ if( nToken>0 ){
+ char *zToken = pNew->u.zToken = (char*)&sEdupBuf.zAlloc[nNewSize];
memcpy(zToken, p->u.zToken, nToken);
+ nNewSize += nToken;
}
+ sEdupBuf.zAlloc += ROUND8(nNewSize);
+
+ if( ((p->flags|pNew->flags)&(EP_TokenOnly|EP_Leaf))==0 ){
- if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_Leaf)) ){
/* Fill in the pNew->x.pSelect or pNew->x.pList member. */
if( ExprUseXSelect(p) ){
pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags);
}else{
- pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags);
+ pNew->x.pList = sqlite3ExprListDup(db, p->x.pList,
+ p->op!=TK_ORDER ? dupFlags : 0);
}
- }
- /* Fill in pNew->pLeft and pNew->pRight. */
- if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly|EP_WinFunc) ){
- zAlloc += dupedExprNodeSize(p, dupFlags);
- if( !ExprHasProperty(pNew, EP_TokenOnly|EP_Leaf) ){
- pNew->pLeft = p->pLeft ?
- exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc) : 0;
- pNew->pRight = p->pRight ?
- exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc) : 0;
- }
#ifndef SQLITE_OMIT_WINDOWFUNC
if( ExprHasProperty(p, EP_WinFunc) ){
pNew->y.pWin = sqlite3WindowDup(db, pNew, p->y.pWin);
assert( ExprHasProperty(pNew, EP_WinFunc) );
}
#endif /* SQLITE_OMIT_WINDOWFUNC */
- if( pzBuffer ){
- *pzBuffer = zAlloc;
- }
- }else{
- if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
- if( pNew->op==TK_SELECT_COLUMN ){
+
+ /* Fill in pNew->pLeft and pNew->pRight. */
+ if( dupFlags ){
+ if( p->op==TK_SELECT_COLUMN ){
pNew->pLeft = p->pLeft;
- assert( p->pRight==0 || p->pRight==p->pLeft
- || ExprHasProperty(p->pLeft, EP_Subquery) );
+ assert( p->pRight==0
+ || p->pRight==p->pLeft
+ || ExprHasProperty(p->pLeft, EP_Subquery) );
+ }else{
+ pNew->pLeft = p->pLeft ?
+ exprDup(db, p->pLeft, EXPRDUP_REDUCE, &sEdupBuf) : 0;
+ }
+ pNew->pRight = p->pRight ?
+ exprDup(db, p->pRight, EXPRDUP_REDUCE, &sEdupBuf) : 0;
+ }else{
+ if( p->op==TK_SELECT_COLUMN ){
+ pNew->pLeft = p->pLeft;
+ assert( p->pRight==0
+ || p->pRight==p->pLeft
+ || ExprHasProperty(p->pLeft, EP_Subquery) );
}else{
pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
}
@@ -108267,6 +110486,8 @@ static Expr *exprDup(sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){
}
}
}
+ if( pEdupBuf ) memcpy(pEdupBuf, &sEdupBuf, sizeof(sEdupBuf));
+ assert( sEdupBuf.zAlloc <= sEdupBuf.zEnd );
return pNew;
}
@@ -108531,11 +110752,7 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *p, int flags)
** initially NULL, then create a new expression list.
**
** The pList argument must be either NULL or a pointer to an ExprList
-** obtained from a prior call to sqlite3ExprListAppend(). This routine
-** may not be used with an ExprList obtained from sqlite3ExprListDup().
-** Reason: This routine assumes that the number of slots in pList->a[]
-** is a power of two. That is true for sqlite3ExprListAppend() returns
-** but is not necessarily true from the return value of sqlite3ExprListDup().
+** obtained from a prior call to sqlite3ExprListAppend().
**
** If a memory allocation error occurs, the entire list is freed and
** NULL is returned. If non-NULL is returned, then it is guaranteed
@@ -108868,7 +111085,7 @@ SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr *pExpr){
** and 0 if it is FALSE.
*/
SQLITE_PRIVATE int sqlite3ExprTruthValue(const Expr *pExpr){
- pExpr = sqlite3ExprSkipCollate((Expr*)pExpr);
+ pExpr = sqlite3ExprSkipCollateAndLikely((Expr*)pExpr);
assert( pExpr->op==TK_TRUEFALSE );
assert( !ExprHasProperty(pExpr, EP_IntValue) );
assert( sqlite3StrICmp(pExpr->u.zToken,"true")==0
@@ -109055,12 +111272,17 @@ SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){
}
/*
-** Check pExpr to see if it is an invariant constraint on data source pSrc.
+** Check pExpr to see if it is an constraint on the single data source
+** pSrc = &pSrcList->a[iSrc]. In other words, check to see if pExpr
+** constrains pSrc but does not depend on any other tables or data
+** sources anywhere else in the query. Return true (non-zero) if pExpr
+** is a constraint on pSrc only.
+**
** This is an optimization. False negatives will perhaps cause slower
** queries, but false positives will yield incorrect answers. So when in
** doubt, return 0.
**
-** To be an invariant constraint, the following must be true:
+** To be an single-source constraint, the following must be true:
**
** (1) pExpr cannot refer to any table other than pSrc->iCursor.
**
@@ -109071,13 +111293,31 @@ SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){
**
** (4) If pSrc is the right operand of a LEFT JOIN, then...
** (4a) pExpr must come from an ON clause..
- (4b) and specifically the ON clause associated with the LEFT JOIN.
+** (4b) and specifically the ON clause associated with the LEFT JOIN.
**
** (5) If pSrc is not the right operand of a LEFT JOIN or the left
** operand of a RIGHT JOIN, then pExpr must be from the WHERE
** clause, not an ON clause.
+**
+** (6) Either:
+**
+** (6a) pExpr does not originate in an ON or USING clause, or
+**
+** (6b) The ON or USING clause from which pExpr is derived is
+** not to the left of a RIGHT JOIN (or FULL JOIN).
+**
+** Without this restriction, accepting pExpr as a single-table
+** constraint might move the the ON/USING filter expression
+** from the left side of a RIGHT JOIN over to the right side,
+** which leads to incorrect answers. See also restriction (9)
+** on push-down.
*/
-SQLITE_PRIVATE int sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *pSrc){
+SQLITE_PRIVATE int sqlite3ExprIsSingleTableConstraint(
+ Expr *pExpr, /* The constraint */
+ const SrcList *pSrcList, /* Complete FROM clause */
+ int iSrc /* Which element of pSrcList to use */
+){
+ const SrcItem *pSrc = &pSrcList->a[iSrc];
if( pSrc->fg.jointype & JT_LTORJ ){
return 0; /* rule (3) */
}
@@ -109087,6 +111327,19 @@ SQLITE_PRIVATE int sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *pSrc
}else{
if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* rule (5) */
}
+ if( ExprHasProperty(pExpr, EP_OuterON|EP_InnerON) /* (6a) */
+ && (pSrcList->a[0].fg.jointype & JT_LTORJ)!=0 /* Fast pre-test of (6b) */
+ ){
+ int jj;
+ for(jj=0; jjw.iJoin==pSrcList->a[jj].iCursor ){
+ if( (pSrcList->a[jj].fg.jointype & JT_LTORJ)!=0 ){
+ return 0; /* restriction (6) */
+ }
+ break;
+ }
+ }
+ }
return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor); /* rules (1), (2) */
}
@@ -109325,6 +111578,27 @@ SQLITE_PRIVATE int sqlite3IsRowid(const char *z){
return 0;
}
+/*
+** Return a pointer to a buffer containing a usable rowid alias for table
+** pTab. An alias is usable if there is not an explicit user-defined column
+** of the same name.
+*/
+SQLITE_PRIVATE const char *sqlite3RowidAlias(Table *pTab){
+ const char *azOpt[] = {"_ROWID_", "ROWID", "OID"};
+ int ii;
+ assert( VisibleRowid(pTab) );
+ for(ii=0; iinCol; iCol++){
+ if( sqlite3_stricmp(azOpt[ii], pTab->aCol[iCol].zCnName)==0 ) break;
+ }
+ if( iCol==pTab->nCol ){
+ return azOpt[ii];
+ }
+ }
+ return 0;
+}
+
/*
** pX is the RHS of an IN operator. If pX is a SELECT statement
** that can be simplified to a direct table access, then return
@@ -109425,7 +111699,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
** IN_INDEX_INDEX_ASC - The cursor was opened on an ascending index.
** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index.
** IN_INDEX_EPH - The cursor was opened on a specially created and
-** populated epheremal table.
+** populated ephemeral table.
** IN_INDEX_NOOP - No cursor was allocated. The IN operator must be
** implemented as a sequence of comparisons.
**
@@ -109438,7 +111712,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
** an ephemeral table might need to be generated from the RHS and then
** pX->iTable made to point to the ephemeral table instead of an
** existing table. In this case, the creation and initialization of the
-** ephmeral table might be put inside of a subroutine, the EP_Subrtn flag
+** ephemeral table might be put inside of a subroutine, the EP_Subrtn flag
** will be set on pX and the pX->y.sub fields will be set to show where
** the subroutine is coded.
**
@@ -109450,12 +111724,12 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
**
** When IN_INDEX_LOOP is used (and the b-tree will be used to iterate
** through the set members) then the b-tree must not contain duplicates.
-** An epheremal table will be created unless the selected columns are guaranteed
+** An ephemeral table will be created unless the selected columns are guaranteed
** to be unique - either because it is an INTEGER PRIMARY KEY or due to
** a UNIQUE constraint or index.
**
** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used
-** for fast set membership tests) then an epheremal table must
+** for fast set membership tests) then an ephemeral table must
** be used unless is a single INTEGER PRIMARY KEY column or an
** index can be found with the specified as its left-most.
**
@@ -109615,7 +111889,6 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
int j;
- assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr );
for(j=0; jaiColumn[j]!=pRhs->iColumn ) continue;
assert( pIdx->azColl[j] );
@@ -109789,7 +112062,7 @@ SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){
** x IN (SELECT a FROM b) -- IN operator with subquery on the right
**
** The pExpr parameter is the IN operator. The cursor number for the
-** constructed ephermeral table is returned. The first time the ephemeral
+** constructed ephemeral table is returned. The first time the ephemeral
** table is computed, the cursor number is also stored in pExpr->iTable,
** however the cursor number returned might not be the same, as it might
** have been duplicated using OP_OpenDup.
@@ -110518,6 +112791,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(
){
int iAddr;
Vdbe *v = pParse->pVdbe;
+ int nErr = pParse->nErr;
assert( v!=0 );
assert( pParse->iSelfTab!=0 );
if( pParse->iSelfTab>0 ){
@@ -110530,6 +112804,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(
sqlite3VdbeAddOp4(v, OP_Affinity, regOut, 1, 0, &pCol->affinity, 1);
}
if( iAddr ) sqlite3VdbeJumpHere(v, iAddr);
+ if( pParse->nErr>nErr ) pParse->db->errByteOffset = -1;
}
#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
@@ -110546,6 +112821,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
Column *pCol;
assert( v!=0 );
assert( pTab!=0 );
+ assert( iCol!=XN_EXPR );
if( iCol<0 || iCol==pTab->iPKey ){
sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
VdbeComment((v, "%s.rowid", pTab->zName));
@@ -110601,10 +112877,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(
u8 p5 /* P5 value for OP_Column + FLAGS */
){
assert( pParse->pVdbe!=0 );
+ assert( (p5 & (OPFLAG_NOCHNG|OPFLAG_TYPEOFARG|OPFLAG_LENGTHARG))==p5 );
+ assert( IsVirtual(pTab) || (p5 & OPFLAG_NOCHNG)==0 );
sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pTab, iTable, iColumn, iReg);
if( p5 ){
VdbeOp *pOp = sqlite3VdbeGetLastOp(pParse->pVdbe);
if( pOp->opcode==OP_Column ) pOp->p5 = p5;
+ if( pOp->opcode==OP_VColumn ) pOp->p5 = (p5 & OPFLAG_NOCHNG);
}
return iReg;
}
@@ -110633,7 +112912,7 @@ static void exprToRegister(Expr *pExpr, int iReg){
/*
** Evaluate an expression (either a vector or a scalar expression) and store
-** the result in continguous temporary registers. Return the index of
+** the result in contiguous temporary registers. Return the index of
** the first register used to store the result.
**
** If the returned result register is a temporary scalar, then also write
@@ -110673,7 +112952,7 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){
*/
static void setDoNotMergeFlagOnCopy(Vdbe *v){
if( sqlite3VdbeGetLastOp(v)->opcode==OP_Copy ){
- sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergable */
+ sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergeable */
}
}
@@ -110763,13 +113042,13 @@ static int exprCodeInlineFunction(
}
case INLINEFUNC_implies_nonnull_row: {
- /* REsult of sqlite3ExprImpliesNonNullRow() */
+ /* Result of sqlite3ExprImpliesNonNullRow() */
Expr *pA1;
assert( nFarg==2 );
pA1 = pFarg->a[1].pExpr;
if( pA1->op==TK_COLUMN ){
sqlite3VdbeAddOp2(v, OP_Integer,
- sqlite3ExprImpliesNonNullRow(pFarg->a[0].pExpr,pA1->iTable),
+ sqlite3ExprImpliesNonNullRow(pFarg->a[0].pExpr,pA1->iTable,1),
target);
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
@@ -110857,6 +113136,41 @@ static SQLITE_NOINLINE int sqlite3IndexedExprLookup(
}
+/*
+** Expresion pExpr is guaranteed to be a TK_COLUMN or equivalent. This
+** function checks the Parse.pIdxPartExpr list to see if this column
+** can be replaced with a constant value. If so, it generates code to
+** put the constant value in a register (ideally, but not necessarily,
+** register iTarget) and returns the register number.
+**
+** Or, if the TK_COLUMN cannot be replaced by a constant, zero is
+** returned.
+*/
+static int exprPartidxExprLookup(Parse *pParse, Expr *pExpr, int iTarget){
+ IndexedExpr *p;
+ for(p=pParse->pIdxPartExpr; p; p=p->pIENext){
+ if( pExpr->iColumn==p->iIdxCol && pExpr->iTable==p->iDataCur ){
+ Vdbe *v = pParse->pVdbe;
+ int addr = 0;
+ int ret;
+
+ if( p->bMaybeNullRow ){
+ addr = sqlite3VdbeAddOp1(v, OP_IfNullRow, p->iIdxCur);
+ }
+ ret = sqlite3ExprCodeTarget(pParse, p->pExpr, iTarget);
+ sqlite3VdbeAddOp4(pParse->pVdbe, OP_Affinity, ret, 1, 0,
+ (const char*)&p->aff, 1);
+ if( addr ){
+ sqlite3VdbeJumpHere(v, addr);
+ sqlite3VdbeChangeP3(v, addr, ret);
+ }
+ return ret;
+ }
+ }
+ return 0;
+}
+
+
/*
** Generate code into the current Vdbe to evaluate the given
** expression. Attempt to store the results in register "target".
@@ -110893,12 +113207,25 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
op = pExpr->op;
}
+ assert( op!=TK_ORDER );
switch( op ){
case TK_AGG_COLUMN: {
AggInfo *pAggInfo = pExpr->pAggInfo;
struct AggInfo_col *pCol;
assert( pAggInfo!=0 );
- assert( pExpr->iAgg>=0 && pExpr->iAggnColumn );
+ assert( pExpr->iAgg>=0 );
+ if( pExpr->iAgg>=pAggInfo->nColumn ){
+ /* Happens when the left table of a RIGHT JOIN is null and
+ ** is using an expression index */
+ sqlite3VdbeAddOp2(v, OP_Null, 0, target);
+#ifdef SQLITE_VDBE_COVERAGE
+ /* Verify that the OP_Null above is exercised by tests
+ ** tag-20230325-2 */
+ sqlite3VdbeAddOp3(v, OP_NotNull, target, 1, 20230325);
+ VdbeCoverageNeverTaken(v);
+#endif
+ break;
+ }
pCol = &pAggInfo->aCol[pExpr->iAgg];
if( !pAggInfo->directMode ){
return AggInfoColumnReg(pAggInfo, pExpr->iAgg);
@@ -110933,7 +113260,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
if( ExprHasProperty(pExpr, EP_FixedCol) ){
/* This COLUMN expression is really a constant due to WHERE clause
** constraints, and that constant is coded by the pExpr->pLeft
- ** expresssion. However, make sure the constant has the correct
+ ** expression. However, make sure the constant has the correct
** datatype by applying the Affinity of the table column to the
** constant.
*/
@@ -111002,6 +113329,11 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
iTab = pParse->iSelfTab - 1;
}
}
+ else if( pParse->pIdxPartExpr
+ && 0!=(r1 = exprPartidxExprLookup(pParse, pExpr, target))
+ ){
+ return r1;
+ }
assert( ExprUseYTab(pExpr) );
assert( pExpr->y.pTab!=0 );
iReg = sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab,
@@ -111073,11 +113405,8 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
#ifndef SQLITE_OMIT_CAST
case TK_CAST: {
/* Expressions of the form: CAST(pLeft AS token) */
- inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
- if( inReg!=target ){
- sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target);
- inReg = target;
- }
+ sqlite3ExprCode(pParse, pExpr->pLeft, target);
+ assert( inReg==target );
assert( !ExprHasProperty(pExpr, EP_IntValue) );
sqlite3VdbeAddOp2(v, OP_Cast, target,
sqlite3AffinityType(pExpr->u.zToken, 0));
@@ -111262,7 +113591,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
sqlite3ErrorMsg(pParse, "unknown function: %#T()", pExpr);
break;
}
- if( pDef->funcFlags & SQLITE_FUNC_INLINE ){
+ if( (pDef->funcFlags & SQLITE_FUNC_INLINE)!=0 && ALWAYS(pFarg!=0) ){
assert( (pDef->funcFlags & SQLITE_FUNC_UNSAFE)==0 );
assert( (pDef->funcFlags & SQLITE_FUNC_DIRECT)==0 );
return exprCodeInlineFunction(pParse, pFarg,
@@ -111288,10 +113617,10 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
r1 = sqlite3GetTempRange(pParse, nFarg);
}
- /* For length() and typeof() functions with a column argument,
+ /* For length() and typeof() and octet_length() functions,
** set the P5 parameter to the OP_Column opcode to OPFLAG_LENGTHARG
- ** or OPFLAG_TYPEOFARG respectively, to avoid unnecessary data
- ** loading.
+ ** or OPFLAG_TYPEOFARG or OPFLAG_BYTELENARG respectively, to avoid
+ ** unnecessary data loading.
*/
if( (pDef->funcFlags & (SQLITE_FUNC_LENGTH|SQLITE_FUNC_TYPEOF))!=0 ){
u8 exprOp;
@@ -111301,14 +113630,16 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
if( exprOp==TK_COLUMN || exprOp==TK_AGG_COLUMN ){
assert( SQLITE_FUNC_LENGTH==OPFLAG_LENGTHARG );
assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG );
- testcase( pDef->funcFlags & OPFLAG_LENGTHARG );
- pFarg->a[0].pExpr->op2 =
- pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG);
+ assert( SQLITE_FUNC_BYTELEN==OPFLAG_BYTELENARG );
+ assert( (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG)==OPFLAG_BYTELENARG );
+ testcase( (pDef->funcFlags & OPFLAG_BYTELENARG)==OPFLAG_LENGTHARG );
+ testcase( (pDef->funcFlags & OPFLAG_BYTELENARG)==OPFLAG_TYPEOFARG );
+ testcase( (pDef->funcFlags & OPFLAG_BYTELENARG)==OPFLAG_BYTELENARG);
+ pFarg->a[0].pExpr->op2 = pDef->funcFlags & OPFLAG_BYTELENARG;
}
}
- sqlite3ExprCodeExprList(pParse, pFarg, r1, 0,
- SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
+ sqlite3ExprCodeExprList(pParse, pFarg, r1, 0, SQLITE_ECEL_FACTOR);
}else{
r1 = 0;
}
@@ -111416,13 +113747,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
** Clear subtypes as subtypes may not cross a subquery boundary.
*/
assert( pExpr->pLeft );
- inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
- if( inReg!=target ){
- sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target);
- inReg = target;
- }
- sqlite3VdbeAddOp1(v, OP_ClrSubtype, inReg);
- return inReg;
+ sqlite3ExprCode(pParse, pExpr->pLeft, target);
+ sqlite3VdbeAddOp1(v, OP_ClrSubtype, target);
+ return target;
}else{
pExpr = pExpr->pLeft;
goto expr_code_doover; /* 2018-04-28: Prevent deep recursion. */
@@ -111532,12 +113859,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
** "target" and not someplace else.
*/
pParse->okConstFactor = 0; /* note (1) above */
- inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
+ sqlite3ExprCode(pParse, pExpr->pLeft, target);
+ assert( target==inReg );
pParse->okConstFactor = okConstFactor;
- if( inReg!=target ){ /* note (2) above */
- sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target);
- inReg = target;
- }
sqlite3VdbeJumpHere(v, addrINR);
break;
}
@@ -111670,9 +113994,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
** once. If no functions are involved, then factor the code out and put it at
** the end of the prepared statement in the initialization section.
**
-** If regDest>=0 then the result is always stored in that register and the
+** If regDest>0 then the result is always stored in that register and the
** result is not reusable. If regDest<0 then this routine is free to
-** store the value whereever it wants. The register where the expression
+** store the value wherever it wants. The register where the expression
** is stored is returned. When regDest<0, two identical expressions might
** code to the same register, if they do not contain function calls and hence
** are factored out into the initialization section at the end of the
@@ -111685,6 +114009,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce(
){
ExprList *p;
assert( ConstFactorOk(pParse) );
+ assert( regDest!=0 );
p = pParse->pConstExpr;
if( regDest<0 && p ){
struct ExprList_item *pItem;
@@ -111775,7 +114100,9 @@ SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
if( inReg!=target ){
u8 op;
- if( ALWAYS(pExpr) && ExprHasProperty(pExpr,EP_Subquery) ){
+ if( ALWAYS(pExpr)
+ && (ExprHasProperty(pExpr,EP_Subquery) || pExpr->op==TK_REGISTER)
+ ){
op = OP_Copy;
}else{
op = OP_SCopy;
@@ -112588,7 +114915,7 @@ static int exprImpliesNotNull(
** pE1: x!=123 pE2: x IS NOT NULL Result: true
** pE1: x!=?1 pE2: x IS NOT NULL Result: true
** pE1: x IS NULL pE2: x IS NOT NULL Result: false
-** pE1: x IS ?2 pE2: x IS NOT NULL Reuslt: false
+** pE1: x IS ?2 pE2: x IS NOT NULL Result: false
**
** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has
** Expr.iTable<0 then assume a table number given by iTab.
@@ -112625,11 +114952,29 @@ SQLITE_PRIVATE int sqlite3ExprImpliesExpr(
return 0;
}
+/* This is a helper function to impliesNotNullRow(). In this routine,
+** set pWalker->eCode to one only if *both* of the input expressions
+** separately have the implies-not-null-row property.
+*/
+static void bothImplyNotNullRow(Walker *pWalker, Expr *pE1, Expr *pE2){
+ if( pWalker->eCode==0 ){
+ sqlite3WalkExpr(pWalker, pE1);
+ if( pWalker->eCode ){
+ pWalker->eCode = 0;
+ sqlite3WalkExpr(pWalker, pE2);
+ }
+ }
+}
+
/*
** This is the Expr node callback for sqlite3ExprImpliesNonNullRow().
** If the expression node requires that the table at pWalker->iCur
** have one or more non-NULL column, then set pWalker->eCode to 1 and abort.
**
+** pWalker->mWFlags is non-zero if this inquiry is being undertaking on
+** behalf of a RIGHT JOIN (or FULL JOIN). That makes a difference when
+** evaluating terms in the ON clause of an inner join.
+**
** This routine controls an optimization. False positives (setting
** pWalker->eCode to 1 when it should not be) are deadly, but false-negatives
** (never setting pWalker->eCode) is a harmless missed optimization.
@@ -112638,28 +114983,33 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
testcase( pExpr->op==TK_AGG_COLUMN );
testcase( pExpr->op==TK_AGG_FUNCTION );
if( ExprHasProperty(pExpr, EP_OuterON) ) return WRC_Prune;
+ if( ExprHasProperty(pExpr, EP_InnerON) && pWalker->mWFlags ){
+ /* If iCur is used in an inner-join ON clause to the left of a
+ ** RIGHT JOIN, that does *not* mean that the table must be non-null.
+ ** But it is difficult to check for that condition precisely.
+ ** To keep things simple, any use of iCur from any inner-join is
+ ** ignored while attempting to simplify a RIGHT JOIN. */
+ return WRC_Prune;
+ }
switch( pExpr->op ){
case TK_ISNOT:
case TK_ISNULL:
case TK_NOTNULL:
case TK_IS:
- case TK_OR:
case TK_VECTOR:
- case TK_CASE:
- case TK_IN:
case TK_FUNCTION:
case TK_TRUTH:
+ case TK_CASE:
testcase( pExpr->op==TK_ISNOT );
testcase( pExpr->op==TK_ISNULL );
testcase( pExpr->op==TK_NOTNULL );
testcase( pExpr->op==TK_IS );
- testcase( pExpr->op==TK_OR );
testcase( pExpr->op==TK_VECTOR );
- testcase( pExpr->op==TK_CASE );
- testcase( pExpr->op==TK_IN );
testcase( pExpr->op==TK_FUNCTION );
testcase( pExpr->op==TK_TRUTH );
+ testcase( pExpr->op==TK_CASE );
return WRC_Prune;
+
case TK_COLUMN:
if( pWalker->u.iCur==pExpr->iTable ){
pWalker->eCode = 1;
@@ -112667,21 +115017,38 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
}
return WRC_Prune;
+ case TK_OR:
case TK_AND:
- if( pWalker->eCode==0 ){
+ /* Both sides of an AND or OR must separately imply non-null-row.
+ ** Consider these cases:
+ ** 1. NOT (x AND y)
+ ** 2. x OR y
+ ** If only one of x or y is non-null-row, then the overall expression
+ ** can be true if the other arm is false (case 1) or true (case 2).
+ */
+ testcase( pExpr->op==TK_OR );
+ testcase( pExpr->op==TK_AND );
+ bothImplyNotNullRow(pWalker, pExpr->pLeft, pExpr->pRight);
+ return WRC_Prune;
+
+ case TK_IN:
+ /* Beware of "x NOT IN ()" and "x NOT IN (SELECT 1 WHERE false)",
+ ** both of which can be true. But apart from these cases, if
+ ** the left-hand side of the IN is NULL then the IN itself will be
+ ** NULL. */
+ if( ExprUseXList(pExpr) && ALWAYS(pExpr->x.pList->nExpr>0) ){
sqlite3WalkExpr(pWalker, pExpr->pLeft);
- if( pWalker->eCode ){
- pWalker->eCode = 0;
- sqlite3WalkExpr(pWalker, pExpr->pRight);
- }
}
return WRC_Prune;
case TK_BETWEEN:
- if( sqlite3WalkExpr(pWalker, pExpr->pLeft)==WRC_Abort ){
- assert( pWalker->eCode );
- return WRC_Abort;
- }
+ /* In "x NOT BETWEEN y AND z" either x must be non-null-row or else
+ ** both y and z must be non-null row */
+ assert( ExprUseXList(pExpr) );
+ assert( pExpr->x.pList->nExpr==2 );
+ sqlite3WalkExpr(pWalker, pExpr->pLeft);
+ bothImplyNotNullRow(pWalker, pExpr->x.pList->a[0].pExpr,
+ pExpr->x.pList->a[1].pExpr);
return WRC_Prune;
/* Virtual tables are allowed to use constraints like x=NULL. So
@@ -112743,7 +115110,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
** be non-NULL, then the LEFT JOIN can be safely converted into an
** ordinary join.
*/
-SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){
+SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab, int isRJ){
Walker w;
p = sqlite3ExprSkipCollateAndLikely(p);
if( p==0 ) return 0;
@@ -112751,7 +115118,7 @@ SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){
p = p->pLeft;
}else{
while( p->op==TK_AND ){
- if( sqlite3ExprImpliesNonNullRow(p->pLeft, iTab) ) return 1;
+ if( sqlite3ExprImpliesNonNullRow(p->pLeft, iTab, isRJ) ) return 1;
p = p->pRight;
}
}
@@ -112759,6 +115126,7 @@ SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){
w.xSelectCallback = 0;
w.xSelectCallback2 = 0;
w.eCode = 0;
+ w.mWFlags = isRJ!=0;
w.u.iCur = iTab;
sqlite3WalkExpr(&w, p);
return w.eCode;
@@ -112819,7 +115187,7 @@ SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(
}
-/* Structure used to pass information throught the Walker in order to
+/* Structure used to pass information throughout the Walker in order to
** implement sqlite3ReferencesSrcList().
*/
struct RefSrcList {
@@ -112926,6 +115294,12 @@ SQLITE_PRIVATE int sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList
assert( pExpr->op==TK_AGG_FUNCTION );
assert( ExprUseXList(pExpr) );
sqlite3WalkExprList(&w, pExpr->x.pList);
+ if( pExpr->pLeft ){
+ assert( pExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pExpr->pLeft) );
+ assert( pExpr->pLeft->x.pList!=0 );
+ sqlite3WalkExprList(&w, pExpr->pLeft->x.pList);
+ }
#ifndef SQLITE_OMIT_WINDOWFUNC
if( ExprHasProperty(pExpr, EP_WinFunc) ){
sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter);
@@ -112960,9 +115334,11 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
int iAgg = pExpr->iAgg;
Parse *pParse = pWalker->pParse;
sqlite3 *db = pParse->db;
+ assert( iAgg>=0 );
if( pExpr->op!=TK_AGG_FUNCTION ){
- assert( iAgg>=0 && iAggnColumn );
- if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){
+ if( iAggnColumn
+ && pAggInfo->aCol[iAgg].pCExpr==pExpr
+ ){
pExpr = sqlite3ExprDup(db, pExpr, 0);
if( pExpr ){
pAggInfo->aCol[iAgg].pCExpr = pExpr;
@@ -112971,8 +115347,9 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
}
}else{
assert( pExpr->op==TK_AGG_FUNCTION );
- assert( iAgg>=0 && iAggnFunc );
- if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){
+ if( ALWAYS(iAggnFunc)
+ && pAggInfo->aFunc[iAgg].pFExpr==pExpr
+ ){
pExpr = sqlite3ExprDup(db, pExpr, 0);
if( pExpr ){
pAggInfo->aFunc[iAgg].pFExpr = pExpr;
@@ -113032,7 +115409,7 @@ static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){
** Return the index in aCol[] of the entry that describes that column.
**
** If no prior entry is found, create a new one and return -1. The
-** new column will have an idex of pAggInfo->nColumn-1.
+** new column will have an index of pAggInfo->nColumn-1.
*/
static void findOrCreateAggInfoColumn(
Parse *pParse, /* Parsing context */
@@ -113045,6 +115422,7 @@ static void findOrCreateAggInfoColumn(
assert( pAggInfo->iFirstReg==0 );
pCol = pAggInfo->aCol;
for(k=0; knColumn; k++, pCol++){
+ if( pCol->pCExpr==pExpr ) return;
if( pCol->iTable==pExpr->iTable
&& pCol->iColumn==pExpr->iColumn
&& pExpr->op!=TK_IF_NULL_ROW
@@ -113122,7 +115500,12 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
}
if( pIEpr==0 ) break;
if( NEVER(!ExprUseYTab(pExpr)) ) break;
- if( pExpr->pAggInfo!=0 ) break; /* Already resolved by outer context */
+ for(i=0; inSrc; i++){
+ if( pSrcList->a[0].iCursor==pIEpr->iDataCur ) break;
+ }
+ if( i>=pSrcList->nSrc ) break;
+ if( NEVER(pExpr->pAggInfo!=0) ) break; /* Resolved by outer context */
+ if( pParse->nErr ){ return WRC_Abort; }
/* If we reach this point, it means that expression pExpr can be
** translated into a reference to an index column as described by
@@ -113133,6 +115516,9 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
tmp.iTable = pIEpr->iIdxCur;
tmp.iColumn = pIEpr->iIdxCol;
findOrCreateAggInfoColumn(pParse, pAggInfo, &tmp);
+ if( pParse->nErr ){ return WRC_Abort; }
+ assert( pAggInfo->aCol!=0 );
+ assert( tmp.iAggnColumn );
pAggInfo->aCol[tmp.iAgg].pCExpr = pExpr;
pExpr->pAggInfo = pAggInfo;
pExpr->iAgg = tmp.iAgg;
@@ -113156,7 +115542,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
} /* endif pExpr->iTable==pItem->iCursor */
} /* end loop over pSrcList */
}
- return WRC_Prune;
+ return WRC_Continue;
}
case TK_AGG_FUNCTION: {
if( (pNC->ncFlags & NC_InAggFunc)==0
@@ -113178,14 +115564,42 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
u8 enc = ENC(pParse->db);
i = addAggInfoFunc(pParse->db, pAggInfo);
if( i>=0 ){
+ int nArg;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
pItem = &pAggInfo->aFunc[i];
pItem->pFExpr = pExpr;
assert( ExprUseUToken(pExpr) );
+ nArg = pExpr->x.pList ? pExpr->x.pList->nExpr : 0;
pItem->pFunc = sqlite3FindFunction(pParse->db,
- pExpr->u.zToken,
- pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0);
- if( pExpr->flags & EP_Distinct ){
+ pExpr->u.zToken, nArg, enc, 0);
+ assert( pItem->bOBUnique==0 );
+ if( pExpr->pLeft
+ && (pItem->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)==0
+ ){
+ /* The NEEDCOLL test above causes any ORDER BY clause on
+ ** aggregate min() or max() to be ignored. */
+ ExprList *pOBList;
+ assert( nArg>0 );
+ assert( pExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pExpr->pLeft) );
+ pItem->iOBTab = pParse->nTab++;
+ pOBList = pExpr->pLeft->x.pList;
+ assert( pOBList->nExpr>0 );
+ assert( pItem->bOBUnique==0 );
+ if( pOBList->nExpr==1
+ && nArg==1
+ && sqlite3ExprCompare(0,pOBList->a[0].pExpr,
+ pExpr->x.pList->a[0].pExpr,0)==0
+ ){
+ pItem->bOBPayload = 0;
+ pItem->bOBUnique = ExprHasProperty(pExpr, EP_Distinct);
+ }else{
+ pItem->bOBPayload = 1;
+ }
+ }else{
+ pItem->iOBTab = -1;
+ }
+ if( ExprHasProperty(pExpr, EP_Distinct) && !pItem->bOBUnique ){
pItem->iDistinct = pParse->nTab++;
}else{
pItem->iDistinct = -1;
@@ -113309,6 +115723,37 @@ SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse *pParse){
pParse->nRangeReg = 0;
}
+/*
+** Make sure sufficient registers have been allocated so that
+** iReg is a valid register number.
+*/
+SQLITE_PRIVATE void sqlite3TouchRegister(Parse *pParse, int iReg){
+ if( pParse->nMemnMem = iReg;
+}
+
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_DEBUG)
+/*
+** Return the latest reusable register in the set of all registers.
+** The value returned is no less than iMin. If any register iMin or
+** greater is in permanent use, then return one more than that last
+** permanent register.
+*/
+SQLITE_PRIVATE int sqlite3FirstAvailableRegister(Parse *pParse, int iMin){
+ const ExprList *pList = pParse->pConstExpr;
+ if( pList ){
+ int i;
+ for(i=0; inExpr; i++){
+ if( pList->a[i].u.iConstExprReg>=iMin ){
+ iMin = pList->a[i].u.iConstExprReg + 1;
+ }
+ }
+ }
+ pParse->nTempReg = 0;
+ pParse->nRangeReg = 0;
+ return iMin;
+}
+#endif /* SQLITE_ENABLE_STAT4 || SQLITE_DEBUG */
+
/*
** Validate that no temporary register falls within the range of
** iFirst..iLast, inclusive. This routine is only call from within assert()
@@ -113328,6 +115773,14 @@ SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){
return 0;
}
}
+ if( pParse->pConstExpr ){
+ ExprList *pList = pParse->pConstExpr;
+ for(i=0; inExpr; i++){
+ int iReg = pList->a[i].u.iConstExprReg;
+ if( iReg==0 ) continue;
+ if( iReg>=iFirst && iReg<=iLast ) return 0;
+ }
+ }
return 1;
}
#endif /* SQLITE_DEBUG */
@@ -113782,14 +116235,19 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
/* Verify that constraints are still satisfied */
if( pNew->pCheck!=0
|| (pCol->notNull && (pCol->colFlags & COLFLAG_GENERATED)!=0)
+ || (pTab->tabFlags & TF_Strict)!=0
){
sqlite3NestedParse(pParse,
"SELECT CASE WHEN quick_check GLOB 'CHECK*'"
" THEN raise(ABORT,'CHECK constraint failed')"
+ " WHEN quick_check GLOB 'non-* value in*'"
+ " THEN raise(ABORT,'type mismatch on DEFAULT')"
" ELSE raise(ABORT,'NOT NULL constraint failed')"
" END"
" FROM pragma_quick_check(%Q,%Q)"
- " WHERE quick_check GLOB 'CHECK*' OR quick_check GLOB 'NULL*'",
+ " WHERE quick_check GLOB 'CHECK*'"
+ " OR quick_check GLOB 'NULL*'"
+ " OR quick_check GLOB 'non-* value in*'",
zTab, zDb
);
}
@@ -113878,7 +116336,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
pNew->u.tab.pDfltList = sqlite3ExprListDup(db, pTab->u.tab.pDfltList, 0);
pNew->pSchema = db->aDb[iDb].pSchema;
pNew->u.tab.addColOffset = pTab->u.tab.addColOffset;
- pNew->nTabRef = 1;
+ assert( pNew->nTabRef==1 );
exit_begin_add_column:
sqlite3SrcListDelete(db, pSrc);
@@ -114012,6 +116470,101 @@ SQLITE_PRIVATE void sqlite3AlterRenameColumn(
return;
}
+/*
+** Handles the following parser reduction:
+**
+** cmd ::= ALTER TABLE pSrc ALTER COLUMN pOld TO pNew
+*/
+void libsqlAlterAlterColumn(
+ Parse *pParse, /* Parsing context */
+ SrcList *pSrc, /* Table being altered. pSrc->nSrc==1 */
+ Token *pOld, /* Name of column being changed */
+ Token *pNew /* New column declaration */
+){
+ sqlite3 *db = pParse->db; /* Database connection */
+ Table *pTab; /* Table being updated */
+ int iCol; /* Index of column being updated */
+ char *zOld = 0; /* Old column name */
+ char *zNew = 0; /* New column declaration */
+ const char *zDb; /* Name of schema containing the table */
+ int iSchema; /* Index of the schema */
+ int bQuote; /* True to quote the new name */
+
+ /* Locate the table to be altered */
+ pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
+ if( !pTab ) goto exit_update_column;
+
+ /* Cannot alter a system table */
+ if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_update_column;
+ if( SQLITE_OK!=isRealTable(pParse, pTab, 0) ) goto exit_update_column;
+
+ /* Which schema holds the table to be altered */
+ iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
+ assert( iSchema>=0 );
+ zDb = db->aDb[iSchema].zDbSName;
+
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ /* Invoke the authorization callback. */
+ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){
+ goto exit_update_column;
+ }
+#endif
+
+ /* Make sure the old name really is a column name in the table to be
+ ** altered. Set iCol to be the index of the column being updated */
+ zOld = sqlite3NameFromToken(db, pOld);
+ if( !zOld ) goto exit_update_column;
+ for(iCol=0; iColnCol; iCol++){
+ if( 0==sqlite3StrICmp(pTab->aCol[iCol].zCnName, zOld) ) break;
+ }
+ if( iCol==pTab->nCol ){
+ sqlite3ErrorMsg(pParse, "no such column: \"%T\"", pOld);
+ goto exit_update_column;
+ }
+
+ /* Ensure the schema contains no double-quoted strings */
+ renameTestSchema(pParse, zDb, iSchema==1, "", 0);
+ renameFixQuotes(pParse, zDb, iSchema==1);
+
+ /* Do the update operation using a recursive UPDATE statement that
+ ** uses the sqlite_update_column() SQL function to compute the new
+ ** CREATE statement text for the sqlite_schema table.
+ */
+ sqlite3MayAbort(pParse);
+ if(pOld->n != pNew->n || sqlite3StrNICmp(pOld->z, pNew->z, pOld->n) != 0) {
+ sqlite3ErrorMsg(pParse, "UPDATE cannot also rename column: \"%T\" to \"%T\". Use ALTER TABLE RENAME instead", pOld, pNew);
+ goto exit_update_column;
+ }
+ // NOTICE: this is the main difference in ALTER COLUMN compared to RENAME COLUMN,
+ // we just take the whole new column declaration as it is.
+ // FIXME: the semicolon can also appear in the middle of the declaration when it's quoted,
+ // so we should check from the end.
+ pNew->n = sqlite3Strlen30(pNew->z);
+ while (pNew->n > 0 && pNew->z[pNew->n - 1] == ';') pNew->n--;
+ zNew = sqlite3DbStrNDup(db, pNew->z, pNew->n);
+ if( !zNew ) goto exit_update_column;
+ assert( pNew->n>0 );
+ bQuote = -1; // Contrary to RENAME, we leave quotes as is and not dequote them
+ sqlite3NestedParse(pParse,
+ "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET "
+ "sql = libsql_alter_column(sql, %Q, %Q, %d, %Q, %d, %d, %d) "
+ "WHERE tbl_name = %Q",
+ zDb,
+ zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1, pTab->aCol[iCol].colFlags,
+ pTab->zName
+ );
+
+ /* Drop and reload the database schema. */
+ renameReloadSchema(pParse, iSchema, INITFLAG_AlterRename);
+ renameTestSchema(pParse, zDb, iSchema==1, "after update", 1);
+
+ exit_update_column:
+ sqlite3SrcListDelete(db, pSrc);
+ sqlite3DbFree(db, zOld);
+ sqlite3DbFree(db, zNew);
+ return;
+}
+
/*
** Each RenameToken object maps an element of the parse tree into
** the token that generated that element. The parse tree element
@@ -114383,7 +116936,7 @@ static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){
}
/*
-** An error occured while parsing or otherwise processing a database
+** An error occurred while parsing or otherwise processing a database
** object (either pParse->pNewTable, pNewIndex or pNewTrigger) as part of an
** ALTER TABLE RENAME COLUMN program. The error message emitted by the
** sub-routine is currently stored in pParse->zErrMsg. This function
@@ -114519,7 +117072,7 @@ static int renameEditSql(
RenameCtx *pRename, /* Rename context */
const char *zSql, /* SQL statement to edit */
const char *zNew, /* New token text */
- int bQuote /* True to always quote token */
+ int bQuote /* 1 to always quote token, -1 to never quote */
){
i64 nNew = sqlite3Strlen30(zNew);
i64 nSql = sqlite3Strlen30(zSql);
@@ -114568,7 +117121,7 @@ static int renameEditSql(
RenameToken *pBest = renameColumnTokenNext(pRename);
if( zNew ){
- if( bQuote==0 && sqlite3IsIdChar(*pBest->t.z) ){
+ if( bQuote==-1 || (bQuote==0 && sqlite3IsIdChar(*pBest->t.z)) ){
nReplace = nNew;
zReplace = zNew;
}else{
@@ -114615,6 +117168,19 @@ static int renameEditSql(
return rc;
}
+/*
+** Set all pEList->a[].fg.eEName fields in the expression-list to val.
+*/
+static void renameSetENames(ExprList *pEList, int val){
+ if( pEList ){
+ int i;
+ for(i=0; inExpr; i++){
+ assert( val==ENAME_NAME || pEList->a[i].fg.eEName==ENAME_NAME );
+ pEList->a[i].fg.eEName = val;
+ }
+ }
+}
+
/*
** Resolve all symbols in the trigger at pParse->pNewTrigger, assuming
** it was read from the schema of database zDb. Return SQLITE_OK if
@@ -114662,7 +117228,17 @@ static int renameResolveTrigger(Parse *pParse){
pSrc = 0;
rc = SQLITE_NOMEM;
}else{
+ /* pStep->pExprList contains an expression-list used for an UPDATE
+ ** statement. So the a[].zEName values are the RHS of the
+ ** " = " clauses of the UPDATE statement. So, before
+ ** running SelectPrep(), change all the eEName values in
+ ** pStep->pExprList to ENAME_SPAN (from their current value of
+ ** ENAME_NAME). This is to prevent any ids in ON() clauses that are
+ ** part of pSrc from being incorrectly resolved against the
+ ** a[].zEName values as if they were column aliases. */
+ renameSetENames(pStep->pExprList, ENAME_SPAN);
sqlite3SelectPrep(pParse, pSel, 0);
+ renameSetENames(pStep->pExprList, ENAME_NAME);
rc = pParse->nErr ? SQLITE_ERROR : SQLITE_OK;
assert( pStep->pExprList==0 || pStep->pExprList==pSel->pEList );
assert( pSrc==pSel->pSrc );
@@ -114959,6 +117535,180 @@ static void renameColumnFunc(
sqlite3BtreeLeaveAll(db);
}
+/*
+** SQL function:
+**
+** libsql_alter_column(SQL,TYPE,OBJ,DB,TABLE,COL,NEWNAME,QUOTE,TEMP)
+**
+** 0. zSql: SQL statement to rewrite
+** 1. Database: Database name (e.g. "main")
+** 2. Table: Table name
+** 3. iCol: Index of column to rename
+** 4. zNew: New column clause to add, e.g. "x REFERENCES other_table(y)"
+** 5. bQuote: Non-zero if the new column name should be quoted.
+** 6. bTemp: True if zSql comes from temp schema
+**
+** Do a ALTER TABLE ALTER COLUMN operation on the CREATE statement given in zSql.
+** The iCol-th column (left-most is 0) of table zTable is translated from zCol
+** into zNew definition, which the new constraints.
+** The name should be quoted if bQuote is true.
+**
+** This function is used internally by the ALTER TABLE ALTER COLUMN command.
+** It is only accessible to SQL created using sqlite3NestedParse(). It is
+** not reachable from ordinary SQL passed into sqlite3_prepare() unless the
+** SQLITE_TESTCTRL_INTERNAL_FUNCTIONS test setting is enabled.
+*/
+static void alterColumnFunc(
+ sqlite3_context *context,
+ int NotUsed,
+ sqlite3_value **argv
+){
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ RenameCtx sCtx;
+ const char *zSql = (const char*)sqlite3_value_text(argv[0]);
+ const char *zDb = (const char*)sqlite3_value_text(argv[1]);
+ const char *zTable = (const char*)sqlite3_value_text(argv[2]);
+ int iCol = sqlite3_value_int(argv[3]);
+ const char *zNew = (const char*)sqlite3_value_text(argv[4]);
+ int bQuote = sqlite3_value_int(argv[5]);
+ int bTemp = sqlite3_value_int(argv[6]);
+ u16 iColFlags = sqlite3_value_int(argv[7]);
+
+ const char *zOld;
+ int rc;
+ Parse sParse;
+ Parse sPostAlterParse;
+ Index *pIdx;
+ int i;
+ Table *pTab;
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ sqlite3_xauth xAuth = db->xAuth;
+#endif
+
+ UNUSED_PARAMETER(NotUsed);
+ if( zSql==0 ) return;
+ if( zTable==0 ) return;
+ if( zNew==0 ) return;
+ if( iCol<0 ) return;
+ sqlite3BtreeEnterAll(db);
+ pTab = sqlite3FindTable(db, zTable, zDb);
+ if( pTab==0 || iCol>=pTab->nCol ){
+ sqlite3BtreeLeaveAll(db);
+ return;
+ }
+ zOld = pTab->aCol[iCol].zCnName;
+ memset(&sCtx, 0, sizeof(sCtx));
+ sCtx.iCol = ((iCol==pTab->iPKey) ? -1 : iCol);
+
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ db->xAuth = 0;
+#endif
+ rc = renameParseSql(&sParse, zDb, db, zSql, bTemp);
+
+ sCtx.pTab = pTab;
+ if( rc!=SQLITE_OK ) goto alterColumnFunc_done;
+ if( sParse.pNewTable ){
+ if( IsOrdinaryTable(sParse.pNewTable) ){
+ int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName);
+ FKey *pFKey;
+ sCtx.pTab = sParse.pNewTable;
+ if( bFKOnly==0 ){
+ if (iColnCol) {
+ Column *col = &sParse.pNewTable->aCol[iCol];
+ RenameToken *pCol = renameTokenFind(
+ &sParse, &sCtx, (void*)col->zCnName
+ );
+ // Expand the token until we find the end of the column definition
+ // FIXME: corner cases we don't cover are expected here, like quoted identifiers
+ // and other kinds of parentheses, and they would result in an incorrect SQL statement being generated.
+ // What we want here is to expand to the whole definition, including constraints, types, etc.
+ int open_parens = 0;
+ while (pCol->t.z[pCol->t.n] != 0 && pCol->t.z[pCol->t.n] != ',') {
+ if (pCol->t.z[pCol->t.n] == '(') open_parens++;
+ if (pCol->t.z[pCol->t.n] == ')') open_parens--;
+ if (open_parens < 0) {
+ break;
+ }
+ pCol->t.n++;
+ }
+ }
+ if( sCtx.iCol<0 ){
+ renameTokenFind(&sParse, &sCtx, (void*)&sParse.pNewTable->iPKey);
+ }
+ }
+ } else {
+ rc = SQLITE_ERROR;
+ sParse.zErrMsg = sqlite3MPrintf(sParse.db, "Only ordinary tables can be altered, not ", IsView(sParse.pNewTable) ? "views" : "virtual tables");
+ goto alterColumnFunc_done; }
+ } else if (sParse.pNewIndex) {
+ rc = SQLITE_ERROR;
+ sParse.zErrMsg = sqlite3MPrintf(sParse.db, "Only ordinary tables can be altered, not indexes");
+ goto alterColumnFunc_done;
+ } else {
+ rc = SQLITE_ERROR;
+ sParse.zErrMsg = sqlite3MPrintf(sParse.db, "Only ordinary tables can be altered");
+ goto alterColumnFunc_done;
+ }
+
+ assert( rc==SQLITE_OK );
+ rc = renameEditSql(context, &sCtx, zSql, zNew, bQuote);
+
+ // Validate flags - PRIMARY KEY, UNIQUE and GENERATED constrains are not allowed to be altered
+ // TODO: figure out more illegal combinations to validate
+ rc = renameParseSql(&sPostAlterParse, zDb, db, (const char *)sqlite3_value_text((sqlite3_value *)context->pOut), bTemp);
+ Table *pNewTab = sPostAlterParse.pNewTable;
+ int iNewCol;
+ for (iNewCol = 0; iNewCol < pNewTab->nCol; iNewCol++) {
+ if (sqlite3StrICmp(pNewTab->aCol[iNewCol].zCnName, zOld) == 0) break;
+ }
+ if (iNewCol == pNewTab->nCol) {
+ sParse.zErrMsg = sqlite3MPrintf(sParse.db, "no such column: \"%T\"", zOld);
+ goto alterColumnFunc_done;
+ }
+ u16 primkey_differs = (iColFlags & COLFLAG_PRIMKEY) != (pNewTab->aCol[iNewCol].colFlags & COLFLAG_PRIMKEY);
+ u16 unique_differs = (iColFlags & COLFLAG_UNIQUE) != (pNewTab->aCol[iNewCol].colFlags & COLFLAG_UNIQUE);
+ u16 generated_differs = (iColFlags & COLFLAG_GENERATED) != (pNewTab->aCol[iNewCol].colFlags & COLFLAG_GENERATED);
+ renameParseCleanup(&sPostAlterParse);
+
+ if (primkey_differs) {
+ rc = SQLITE_ERROR;
+ sParse.zErrMsg = sqlite3MPrintf(sParse.db, "PRIMARY KEY constraint cannot be altered");
+ goto alterColumnFunc_done;
+ } else if (unique_differs) {
+ rc = SQLITE_ERROR;
+ sParse.zErrMsg = sqlite3MPrintf(sParse.db, "UNIQUE constraint cannot be altered");
+ goto alterColumnFunc_done;
+ } else if (generated_differs) {
+ rc = SQLITE_ERROR;
+ sParse.zErrMsg = sqlite3MPrintf(sParse.db, "GENERATED constraint cannot be altered");
+ goto alterColumnFunc_done;
+ }
+
+alterColumnFunc_done:
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_ERROR && sqlite3WritableSchema(db) ){
+ sqlite3_result_value(context, argv[0]);
+ }else if( sParse.zErrMsg ){
+ char *zErr = sqlite3MPrintf(sParse.db, "error in adding %s to %s: %s",
+ zNew,
+ zTable,
+ sParse.zErrMsg
+ );
+ sqlite3_result_error(context, zErr, -1);
+ sqlite3DbFree(sParse.db, zErr);
+ }else{
+ sqlite3_result_error_code(context, rc);
+ }
+ }
+
+ renameParseCleanup(&sParse);
+ renameTokenFree(db, sCtx.pList);
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ db->xAuth = xAuth;
+#endif
+ sqlite3BtreeLeaveAll(db);
+}
+
/*
** Walker expression callback used by "RENAME TABLE".
*/
@@ -115608,6 +118358,8 @@ SQLITE_PRIVATE void sqlite3AlterFunctions(void){
INTERNAL_FUNCTION(sqlite_rename_test, 7, renameTableTest),
INTERNAL_FUNCTION(sqlite_drop_column, 3, dropColumnFunc),
INTERNAL_FUNCTION(sqlite_rename_quotefix,2, renameQuotefixFunc),
+ // libSQL extensions
+ INTERNAL_FUNCTION(libsql_alter_column, 8, alterColumnFunc),
};
sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
}
@@ -116611,11 +119363,15 @@ static void analyzeOneTable(
int regIdxname = iMem++; /* Register containing index name */
int regStat1 = iMem++; /* Value for the stat column of sqlite_stat1 */
int regPrev = iMem; /* MUST BE LAST (see below) */
+#ifdef SQLITE_ENABLE_STAT4
+ int doOnce = 1; /* Flag for a one-time computation */
+#endif
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
Table *pStat1 = 0;
#endif
- pParse->nMem = MAX(pParse->nMem, iMem);
+ sqlite3TouchRegister(pParse, iMem);
+ assert( sqlite3NoTempsInRange(pParse, regNewRowid, iMem) );
v = sqlite3GetVdbe(pParse);
if( v==0 || NEVER(pTab==0) ){
return;
@@ -116721,7 +119477,7 @@ static void analyzeOneTable(
** the regPrev array and a trailing rowid (the rowid slot is required
** when building a record to insert into the sample column of
** the sqlite_stat4 table. */
- pParse->nMem = MAX(pParse->nMem, regPrev+nColTest);
+ sqlite3TouchRegister(pParse, regPrev+nColTest);
/* Open a read-only cursor on the index being analyzed. */
assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) );
@@ -116893,7 +119649,35 @@ static void analyzeOneTable(
int addrIsNull;
u8 seekOp = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
- pParse->nMem = MAX(pParse->nMem, regCol+nCol);
+ if( doOnce ){
+ int mxCol = nCol;
+ Index *pX;
+
+ /* Compute the maximum number of columns in any index */
+ for(pX=pTab->pIndex; pX; pX=pX->pNext){
+ int nColX; /* Number of columns in pX */
+ if( !HasRowid(pTab) && IsPrimaryKeyIndex(pX) ){
+ nColX = pX->nKeyCol;
+ }else{
+ nColX = pX->nColumn;
+ }
+ if( nColX>mxCol ) mxCol = nColX;
+ }
+
+ /* Allocate space to compute results for the largest index */
+ sqlite3TouchRegister(pParse, regCol+mxCol);
+ doOnce = 0;
+#ifdef SQLITE_DEBUG
+ /* Verify that the call to sqlite3ClearTempRegCache() below
+ ** really is needed.
+ ** https://sqlite.org/forum/forumpost/83cb4a95a0 (2023-03-25)
+ */
+ testcase( !sqlite3NoTempsInRange(pParse, regEq, regCol+mxCol) );
+#endif
+ sqlite3ClearTempRegCache(pParse); /* tag-20230325-1 */
+ assert( sqlite3NoTempsInRange(pParse, regEq, regCol+mxCol) );
+ }
+ assert( sqlite3NoTempsInRange(pParse, regEq, regCol+nCol) );
addrNext = sqlite3VdbeCurrentAddr(v);
callStatGet(pParse, regStat, STAT_GET_ROWID, regSampleRowid);
@@ -116974,6 +119758,11 @@ static void analyzeDatabase(Parse *pParse, int iDb){
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
Table *pTab = (Table*)sqliteHashData(k);
analyzeOneTable(pParse, pTab, 0, iStatCur, iMem, iTab);
+#ifdef SQLITE_ENABLE_STAT4
+ iMem = sqlite3FirstAvailableRegister(pParse, iMem);
+#else
+ assert( iMem==sqlite3FirstAvailableRegister(pParse,iMem) );
+#endif
}
loadAnalysis(pParse, iDb);
}
@@ -117361,6 +120150,10 @@ static int loadStatTbl(
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
assert( pIdx==0 || pIdx->nSample==0 );
if( pIdx==0 ) continue;
+ if( pIdx->aSample!=0 ){
+ /* The same index appears in sqlite_stat4 under multiple names */
+ continue;
+ }
assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 );
if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
nIdxCol = pIdx->nKeyCol;
@@ -117368,6 +120161,7 @@ static int loadStatTbl(
nIdxCol = pIdx->nColumn;
}
pIdx->nSampleCol = nIdxCol;
+ pIdx->mxSample = nSample;
nByte = sizeof(IndexSample) * nSample;
nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample;
nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */
@@ -117407,6 +120201,11 @@ static int loadStatTbl(
if( zIndex==0 ) continue;
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
if( pIdx==0 ) continue;
+ if( pIdx->nSample>=pIdx->mxSample ){
+ /* Too many slots used because the same index appears in
+ ** sqlite_stat4 using multiple names */
+ continue;
+ }
/* This next condition is true if data has already been loaded from
** the sqlite_stat4 table. */
nCol = pIdx->nSampleCol;
@@ -117419,14 +120218,15 @@ static int loadStatTbl(
decodeIntArray((char*)sqlite3_column_text(pStmt,2),nCol,pSample->anLt,0,0);
decodeIntArray((char*)sqlite3_column_text(pStmt,3),nCol,pSample->anDLt,0,0);
- /* Take a copy of the sample. Add two 0x00 bytes the end of the buffer.
+ /* Take a copy of the sample. Add 8 extra 0x00 bytes the end of the buffer.
** This is in case the sample record is corrupted. In that case, the
** sqlite3VdbeRecordCompare() may read up to two varints past the
** end of the allocated buffer before it realizes it is dealing with
- ** a corrupt record. Adding the two 0x00 bytes prevents this from causing
+ ** a corrupt record. Or it might try to read a large integer from the
+ ** buffer. In any case, eight 0x00 bytes prevents this from causing
** a buffer overread. */
pSample->n = sqlite3_column_bytes(pStmt, 4);
- pSample->p = sqlite3DbMallocZero(db, pSample->n + 2);
+ pSample->p = sqlite3DbMallocZero(db, pSample->n + 8);
if( pSample->p==0 ){
sqlite3_finalize(pStmt);
return SQLITE_NOMEM_BKPT;
@@ -117450,11 +120250,12 @@ static int loadStat4(sqlite3 *db, const char *zDb){
const Table *pStat4;
assert( db->lookaside.bDisable );
- if( (pStat4 = sqlite3FindTable(db, "sqlite_stat4", zDb))!=0
+ if( OptimizationEnabled(db, SQLITE_Stat4)
+ && (pStat4 = sqlite3FindTable(db, "sqlite_stat4", zDb))!=0
&& IsOrdinaryTable(pStat4)
){
rc = loadStatTbl(db,
- "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
+ "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx COLLATE nocase",
"SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4",
zDb
);
@@ -117616,6 +120417,10 @@ SQLITE_PRIVATE int sqlite3DbIsNamed(sqlite3 *db, int iDb, const char *zName){
);
}
+#ifdef LIBSQL_EXTRA_URI_PARAMS
+int libsql_handle_extra_attach_params(sqlite3* db, const char* zName, const char* zPath, sqlite3_value* pKey, char** zErrDyn);
+#endif
+
/*
** An SQL user-function registered to do the work of an ATTACH statement. The
** three arguments to the function come directly from an attach statement:
@@ -117648,7 +120453,6 @@ static void attachFunc(
Db *pNew = 0; /* Db object for the newly attached database */
char *zErrDyn = 0;
sqlite3_vfs *pVfs;
- libsql_wal_methods *pWal;
UNUSED_PARAMETER(NotUsed);
zFile = (const char *)sqlite3_value_text(argv[0]);
@@ -117668,9 +120472,8 @@ static void attachFunc(
** reopen it as a MemDB */
Btree *pNewBt = 0;
pVfs = sqlite3_vfs_find("memdb");
- pWal = libsql_wal_methods_find(NULL);
if( pVfs==0 ) return;
- rc = sqlite3BtreeOpen(pVfs, pWal, "x\0", db, &pNewBt, 0, SQLITE_OPEN_MAIN_DB);
+ rc = sqlite3BtreeOpen(pVfs, "x\0", db, &pNewBt, 0, SQLITE_OPEN_MAIN_DB);
if( rc==SQLITE_OK ){
Schema *pNewSchema = sqlite3SchemaGet(db, pNewBt);
if( pNewSchema ){
@@ -117730,7 +120533,7 @@ static void attachFunc(
** or may not be initialized.
*/
flags = db->openFlags;
- rc = sqlite3ParseUri(db->pVfs->zName, db->pWalMethods->zName, zFile, &flags, &pVfs, &pWal, &zPath, &zErr);
+ rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
sqlite3_result_error(context, zErr, -1);
@@ -117739,7 +120542,7 @@ static void attachFunc(
}
assert( pVfs );
flags |= SQLITE_OPEN_MAIN_DB;
- rc = sqlite3BtreeOpen(pVfs, pWal, zPath, db, &pNew->pBt, 0, flags);
+ rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags);
db->nDb++;
pNew->zDbSName = sqlite3DbStrDup(db, zName);
}
@@ -117772,6 +120575,11 @@ static void attachFunc(
if( rc==SQLITE_OK && pNew->zDbSName==0 ){
rc = SQLITE_NOMEM_BKPT;
}
+#ifdef LIBSQL_EXTRA_URI_PARAMS
+ if (rc == SQLITE_OK) {
+ rc = libsql_handle_extra_attach_params(db, zName, zPath, argv, &zErrDyn);
+ }
+#endif
sqlite3_free_filename( zPath );
/* If the file was opened successfully, read the schema for the new database.
@@ -118386,7 +121194,7 @@ SQLITE_PRIVATE int sqlite3AuthCheck(
sqlite3 *db = pParse->db;
int rc;
- /* Don't do any authorization checks if the database is initialising
+ /* Don't do any authorization checks if the database is initializing
** or if the parser is being invoked from within sqlite3_declare_vtab.
*/
assert( !IN_RENAME_OBJECT || db->xAuth==0 );
@@ -118687,29 +121495,26 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
pParse->nVtabLock = 0;
#endif
+#ifndef SQLITE_OMIT_SHARED_CACHE
/* Once all the cookies have been verified and transactions opened,
** obtain the required table-locks. This is a no-op unless the
** shared-cache feature is enabled.
*/
- codeTableLocks(pParse);
+ if( pParse->nTableLock ) codeTableLocks(pParse);
+#endif
/* Initialize any AUTOINCREMENT data structures required.
*/
- sqlite3AutoincrementBegin(pParse);
+ if( pParse->pAinc ) sqlite3AutoincrementBegin(pParse);
- /* Code constant expressions that where factored out of inner loops.
- **
- ** The pConstExpr list might also contain expressions that we simply
- ** want to keep around until the Parse object is deleted. Such
- ** expressions have iConstExprReg==0. Do not generate code for
- ** those expressions, of course.
+ /* Code constant expressions that were factored out of inner loops.
*/
if( pParse->pConstExpr ){
ExprList *pEL = pParse->pConstExpr;
pParse->okConstFactor = 0;
for(i=0; inExpr; i++){
- int iReg = pEL->a[i].u.iConstExprReg;
- sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg);
+ assert( pEL->a[i].u.iConstExprReg>0 );
+ sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg);
}
}
@@ -119208,7 +122013,7 @@ SQLITE_PRIVATE void sqlite3ColumnSetColl(
}
/*
-** Return the collating squence name for a column
+** Return the collating sequence name for a column
*/
SQLITE_PRIVATE const char *sqlite3ColumnColl(Column *pCol){
const char *z;
@@ -119301,7 +122106,7 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
if( IsOrdinaryTable(pTable) ){
sqlite3FkDelete(db, pTable);
}
-#ifndef SQLITE_OMIT_VIRTUAL_TABLE
+#ifndef SQLITE_OMIT_VIRTUALTABLE
else if( IsVirtual(pTable) ){
sqlite3VtabClear(db, pTable);
}
@@ -119863,20 +122668,13 @@ SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){
}
#endif
-/*
-** Name of the special TEMP trigger used to implement RETURNING. The
-** name begins with "sqlite_" so that it is guaranteed not to collide
-** with any application-generated triggers.
-*/
-#define RETURNING_TRIGGER_NAME "sqlite_returning"
-
/*
** Clean up the data structures associated with the RETURNING clause.
*/
static void sqlite3DeleteReturning(sqlite3 *db, Returning *pRet){
Hash *pHash;
pHash = &(db->aDb[1].pSchema->trigHash);
- sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, 0);
+ sqlite3HashInsert(pHash, pRet->zName, 0);
sqlite3ExprListDelete(db, pRet->pReturnEL);
sqlite3DbFree(db, pRet);
}
@@ -119904,7 +122702,7 @@ SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){
if( pParse->pNewTrigger ){
sqlite3ErrorMsg(pParse, "cannot use RETURNING in a trigger");
}else{
- assert( pParse->bReturning==0 );
+ assert( pParse->bReturning==0 || pParse->ifNotExists );
}
pParse->bReturning = 1;
pRet = sqlite3DbMallocZero(db, sizeof(*pRet));
@@ -119919,7 +122717,9 @@ SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){
(void(*)(sqlite3*,void*))sqlite3DeleteReturning, pRet);
testcase( pParse->earlyCleanup );
if( db->mallocFailed ) return;
- pRet->retTrig.zName = RETURNING_TRIGGER_NAME;
+ sqlite3_snprintf(sizeof(pRet->zName), pRet->zName,
+ "sqlite_returning_%p", pParse);
+ pRet->retTrig.zName = pRet->zName;
pRet->retTrig.op = TK_RETURNING;
pRet->retTrig.tr_tm = TRIGGER_AFTER;
pRet->retTrig.bReturning = 1;
@@ -119930,8 +122730,9 @@ SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){
pRet->retTStep.pTrig = &pRet->retTrig;
pRet->retTStep.pExprList = pList;
pHash = &(db->aDb[1].pSchema->trigHash);
- assert( sqlite3HashFind(pHash, RETURNING_TRIGGER_NAME)==0 || pParse->nErr );
- if( sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, &pRet->retTrig)
+ assert( sqlite3HashFind(pHash, pRet->zName)==0
+ || pParse->nErr || pParse->ifNotExists );
+ if( sqlite3HashInsert(pHash, pRet->zName, &pRet->retTrig)
==&pRet->retTrig ){
sqlite3OomFault(db);
}
@@ -119965,7 +122766,7 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){
}
if( !IN_RENAME_OBJECT ) sqlite3DequoteToken(&sName);
- /* Because keywords GENERATE ALWAYS can be converted into indentifiers
+ /* Because keywords GENERATE ALWAYS can be converted into identifiers
** by the parser, we can sometimes end up with a typename that ends
** with "generated always". Check for this case and omit the surplus
** text. */
@@ -120186,7 +122987,7 @@ SQLITE_PRIVATE void sqlite3AddDefaultValue(
Parse *pParse, /* Parsing context */
Expr *pExpr, /* The parsed expression of the default value */
const char *zStart, /* Start of the default value text */
- const char *zEnd /* First character past end of defaut value text */
+ const char *zEnd /* First character past end of default value text */
){
Table *p;
Column *pCol;
@@ -120534,7 +123335,7 @@ static int identLength(const char *z){
** to the specified offset in the buffer and updates *pIdx to refer
** to the first byte after the last byte written before returning.
**
-** If the string zSignedIdent consists entirely of alpha-numeric
+** If the string zSignedIdent consists entirely of alphanumeric
** characters, does not begin with a digit and is not an SQL keyword,
** then it is copied to the output buffer exactly as it is. Otherwise,
** it is quoted using double-quotes.
@@ -120686,7 +123487,7 @@ static void estimateIndexWidth(Index *pIdx){
for(i=0; inColumn; i++){
i16 x = pIdx->aiColumn[i];
assert( xpTable->nCol );
- wIndex += x<0 ? 1 : aCol[pIdx->aiColumn[i]].szEst;
+ wIndex += x<0 ? 1 : aCol[x].szEst;
}
pIdx->szIdxRow = sqlite3LogEst(wIndex*4);
}
@@ -121384,6 +124185,17 @@ SQLITE_PRIVATE void sqlite3EndTable(
/* Reparse everything to update our internal data structures */
sqlite3VdbeAddParseSchemaOp(v, iDb,
sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0);
+
+ /* Test for cycles in generated columns and illegal expressions
+ ** in CHECK constraints and in DEFAULT clauses. */
+ if( p->tabFlags & TF_HasGenerated ){
+ sqlite3VdbeAddOp4(v, OP_SqlExec, 1, 0, 0,
+ sqlite3MPrintf(db, "SELECT*FROM\"%w\".\"%w\"",
+ db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC);
+ }
+ sqlite3VdbeAddOp4(v, OP_SqlExec, 1, 0, 0,
+ sqlite3MPrintf(db, "PRAGMA \"%w\".integrity_check(%Q)",
+ db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC);
}
/* Add the table to the in-memory representation of the database.
@@ -122433,7 +125245,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
#ifndef SQLITE_OMIT_TEMPDB
/* If the index name was unqualified, check if the table
** is a temp table. If so, set the database to 1. Do not do this
- ** if initialising a database schema.
+ ** if initializing a database schema.
*/
if( !db->init.busy ){
pTab = sqlite3SrcListLookup(pParse, pTblName);
@@ -123672,7 +126484,7 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){
SQLITE_OPEN_DELETEONCLOSE |
SQLITE_OPEN_TEMP_DB;
- rc = sqlite3BtreeOpen(db->pVfs, db->pWalMethods, 0, db, &pBt, 0, flags);
+ rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pBt, 0, flags);
if( rc!=SQLITE_OK ){
sqlite3ErrorMsg(pParse, "unable to open a temporary database "
"file for storing temporary tables");
@@ -124090,7 +126902,7 @@ SQLITE_PRIVATE void sqlite3CteDelete(sqlite3 *db, Cte *pCte){
/*
** This routine is invoked once per CTE by the parser while parsing a
-** WITH clause. The CTE described by teh third argument is added to
+** WITH clause. The CTE described by the third argument is added to
** the WITH clause of the second argument. If the second argument is
** NULL, then a new WITH argument is created.
*/
@@ -124286,6 +127098,7 @@ void libsql_drop_function(
}
#endif
+
/************** End of build.c ***********************************************/
/************** Begin file callback.c ****************************************/
/*
@@ -124475,6 +127288,7 @@ SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8 enc){
** strings is BINARY.
*/
db->pDfltColl = sqlite3FindCollSeq(db, enc, sqlite3StrBINARY, 0);
+ sqlite3ExpirePreparedStatements(db, 1);
}
/*
@@ -124865,8 +127679,9 @@ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
Table *pTab;
assert( pItem && pSrc->nSrc>=1 );
pTab = sqlite3LocateTableItem(pParse, 0, pItem);
- sqlite3DeleteTable(pParse->db, pItem->pTab);
+ if( pItem->pTab ) sqlite3DeleteTable(pParse->db, pItem->pTab);
pItem->pTab = pTab;
+ pItem->fg.notCte = 1;
if( pTab ){
pTab->nTabRef++;
if( pItem->fg.isIndexedBy && sqlite3IndexedByLookup(pParse, pItem) ){
@@ -124946,13 +127761,15 @@ static int tabIsReadOnly(Parse *pParse, Table *pTab){
** If pTab is writable but other errors have occurred -> return 1.
** If pTab is writable and no prior errors -> return 0;
*/
-SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
+SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, Trigger *pTrigger){
if( tabIsReadOnly(pParse, pTab) ){
sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
return 1;
}
#ifndef SQLITE_OMIT_VIEW
- if( !viewOk && IsView(pTab) ){
+ if( IsView(pTab)
+ && (pTrigger==0 || (pTrigger->bReturning && pTrigger->pNext==0))
+ ){
sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
return 1;
}
@@ -125017,7 +127834,7 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
sqlite3 *db = pParse->db;
Expr *pLhs = NULL; /* LHS of IN(SELECT...) operator */
Expr *pInClause = NULL; /* WHERE rowid IN ( select ) */
- ExprList *pEList = NULL; /* Expression list contaning only pSelectRowid */
+ ExprList *pEList = NULL; /* Expression list containing only pSelectRowid*/
SrcList *pSelectSrc = NULL; /* SELECT rowid FROM x ... (dup of pSrc) */
Select *pSelect = NULL; /* Complete SELECT tree */
Table *pTab;
@@ -125055,14 +127872,20 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
);
}else{
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
+ assert( pPk!=0 );
+ assert( pPk->nKeyCol>=1 );
if( pPk->nKeyCol==1 ){
- const char *zName = pTab->aCol[pPk->aiColumn[0]].zCnName;
+ const char *zName;
+ assert( pPk->aiColumn[0]>=0 && pPk->aiColumn[0]nCol );
+ zName = pTab->aCol[pPk->aiColumn[0]].zCnName;
pLhs = sqlite3Expr(db, TK_ID, zName);
pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, zName));
}else{
int i;
for(i=0; inKeyCol; i++){
- Expr *p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zCnName);
+ Expr *p;
+ assert( pPk->aiColumn[i]>=0 && pPk->aiColumn[i]nCol );
+ p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zCnName);
pEList = sqlite3ExprListAppend(pParse, pEList, p);
}
pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
@@ -125091,7 +127914,7 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
pOrderBy,0,pLimit
);
- /* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
+ /* now generate the new WHERE rowid IN clause for the DELETE/UPDATE */
pInClause = sqlite3PExpr(pParse, TK_IN, pLhs, 0);
sqlite3PExprAddSelect(pParse, pInClause, pSelect);
return pInClause;
@@ -125206,7 +128029,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
goto delete_from_cleanup;
}
- if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
+ if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
goto delete_from_cleanup;
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -125315,12 +128138,12 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
#endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
{
u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK;
- if( sNC.ncFlags & NC_VarSelect ) bComplex = 1;
+ if( sNC.ncFlags & NC_Subquery ) bComplex = 1;
wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW);
if( HasRowid(pTab) ){
/* For a rowid table, initialize the RowSet to an empty set */
pPk = 0;
- nPk = 1;
+ assert( nPk==1 );
iRowSet = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
}else{
@@ -125348,7 +128171,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
if( pWInfo==0 ) goto delete_from_cleanup;
eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI );
- assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF );
+ assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF
+ || OptimizationDisabled(db, SQLITE_OnePass) );
if( eOnePass!=ONEPASS_SINGLE ) sqlite3MultiWrite(pParse);
if( sqlite3WhereUsesDeferredSeek(pWInfo) ){
sqlite3VdbeAddOp1(v, OP_FinishSeek, iTabCur);
@@ -125685,9 +128509,11 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
sqlite3FkActions(pParse, pTab, 0, iOld, 0, 0);
/* Invoke AFTER DELETE trigger programs. */
- sqlite3CodeRowTrigger(pParse, pTrigger,
- TK_DELETE, 0, TRIGGER_AFTER, pTab, iOld, onconf, iLabel
- );
+ if( pTrigger ){
+ sqlite3CodeRowTrigger(pParse, pTrigger,
+ TK_DELETE, 0, TRIGGER_AFTER, pTab, iOld, onconf, iLabel
+ );
+ }
/* Jump here if the row had already been deleted before any BEFORE
** trigger programs were invoked. Or if a trigger program throws a
@@ -126004,6 +128830,42 @@ static void lengthFunc(
}
}
+/*
+** Implementation of the octet_length() function
+*/
+static void bytelengthFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ assert( argc==1 );
+ UNUSED_PARAMETER(argc);
+ switch( sqlite3_value_type(argv[0]) ){
+ case SQLITE_BLOB: {
+ sqlite3_result_int(context, sqlite3_value_bytes(argv[0]));
+ break;
+ }
+ case SQLITE_INTEGER:
+ case SQLITE_FLOAT: {
+ i64 m = sqlite3_context_db_handle(context)->enc<=SQLITE_UTF8 ? 1 : 2;
+ sqlite3_result_int64(context, sqlite3_value_bytes(argv[0])*m);
+ break;
+ }
+ case SQLITE_TEXT: {
+ if( sqlite3_value_encoding(argv[0])<=SQLITE_UTF8 ){
+ sqlite3_result_int(context, sqlite3_value_bytes(argv[0]));
+ }else{
+ sqlite3_result_int(context, sqlite3_value_bytes16(argv[0]));
+ }
+ break;
+ }
+ default: {
+ sqlite3_result_null(context);
+ break;
+ }
+ }
+}
+
/*
** Implementation of the abs() function.
**
@@ -126280,7 +129142,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}else if( n==0 ){
r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5)));
}else{
- zBuf = sqlite3_mprintf("%.*f",n,r);
+ zBuf = sqlite3_mprintf("%!.*f",n,r);
if( zBuf==0 ){
sqlite3_result_error_nomem(context);
return;
@@ -126480,7 +129342,7 @@ struct compareInfo {
/*
** For LIKE and GLOB matching on EBCDIC machines, assume that every
-** character is exactly one byte in size. Also, provde the Utf8Read()
+** character is exactly one byte in size. Also, provide the Utf8Read()
** macro for fast reading of the next character in the common case where
** the next character is ASCII.
*/
@@ -126713,7 +129575,7 @@ SQLITE_API int sqlite3_like_count = 0;
/*
** Implementation of the like() SQL function. This function implements
-** the build-in LIKE operator. The first argument to the function is the
+** the built-in LIKE operator. The first argument to the function is the
** pattern and the second argument is the string. So, the SQL statements:
**
** A LIKE B
@@ -127046,6 +129908,7 @@ static void charFunc(
*zOut++ = 0x80 + (u8)(c & 0x3F);
} \
}
+ *zOut = 0;
sqlite3_result_text64(context, (char*)z, zOut-z, sqlite3_free, SQLITE_UTF8);
}
@@ -127074,7 +129937,8 @@ static void hexFunc(
*(z++) = hexdigits[c&0xf];
}
*z = 0;
- sqlite3_result_text(context, zHex, n*2, sqlite3_free);
+ sqlite3_result_text64(context, zHex, (u64)(z-zHex),
+ sqlite3_free, SQLITE_UTF8);
}
}
@@ -127099,7 +129963,7 @@ static int strContainsChar(const u8 *zStr, int nStr, u32 ch){
** decoded and returned as a blob.
**
** If there is only a single argument, then it must consist only of an
-** even number of hexadeximal digits. Otherwise, return NULL.
+** even number of hexadecimal digits. Otherwise, return NULL.
**
** Or, if there is a second argument, then any character that appears in
** the second argument is also allowed to appear between pairs of hexadecimal
@@ -127368,12 +130232,87 @@ static void trimFunc(
sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT);
}
+/* The core implementation of the CONCAT(...) and CONCAT_WS(SEP,...)
+** functions.
+**
+** Return a string value that is the concatenation of all non-null
+** entries in argv[]. Use zSep as the separator.
+*/
+static void concatFuncCore(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv,
+ int nSep,
+ const char *zSep
+){
+ i64 j, k, n = 0;
+ int i;
+ char *z;
+ for(i=0; i0 ){
+ const char *v = (const char*)sqlite3_value_text(argv[i]);
+ if( v!=0 ){
+ if( j>0 && nSep>0 ){
+ memcpy(&z[j], zSep, nSep);
+ j += nSep;
+ }
+ memcpy(&z[j], v, k);
+ j += k;
+ }
+ }
+ }
+ z[j] = 0;
+ assert( j<=n );
+ sqlite3_result_text64(context, z, j, sqlite3_free, SQLITE_UTF8);
+}
+
+/*
+** The CONCAT(...) function. Generate a string result that is the
+** concatentation of all non-null arguments.
+*/
+static void concatFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ concatFuncCore(context, argc, argv, 0, "");
+}
+
+/*
+** The CONCAT_WS(separator, ...) function.
+**
+** Generate a string that is the concatenation of 2nd through the Nth
+** argument. Use the first argument (which must be non-NULL) as the
+** separator.
+*/
+static void concatwsFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ int nSep = sqlite3_value_bytes(argv[0]);
+ const char *zSep = (const char*)sqlite3_value_text(argv[0]);
+ if( zSep==0 ) return;
+ concatFuncCore(context, argc-1, argv+1, nSep, zSep);
+}
+
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
/*
** The "unknown" function is automatically substituted in place of
** any unrecognized function name when doing an EXPLAIN or EXPLAIN QUERY PLAN
-** when the SQLITE_ENABLE_UNKNOWN_FUNCTION compile-time option is used.
+** when the SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION compile-time option is used.
** When the "sqlite3" command-line shell is built using this functionality,
** that allows an EXPLAIN or EXPLAIN QUERY PLAN for complex queries
** involving application-defined functions to be examined in a generic
@@ -127489,13 +130428,68 @@ static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){
*/
typedef struct SumCtx SumCtx;
struct SumCtx {
- double rSum; /* Floating point sum */
- i64 iSum; /* Integer sum */
+ double rSum; /* Running sum as as a double */
+ double rErr; /* Error term for Kahan-Babushka-Neumaier summation */
+ i64 iSum; /* Running sum as a signed integer */
i64 cnt; /* Number of elements summed */
- u8 overflow; /* True if integer overflow seen */
- u8 approx; /* True if non-integer value was input to the sum */
+ u8 approx; /* True if any non-integer value was input to the sum */
+ u8 ovrfl; /* Integer overflow seen */
};
+/*
+** Do one step of the Kahan-Babushka-Neumaier summation.
+**
+** https://en.wikipedia.org/wiki/Kahan_summation_algorithm
+**
+** Variables are marked "volatile" to defeat c89 x86 floating point
+** optimizations can mess up this algorithm.
+*/
+static void kahanBabuskaNeumaierStep(
+ volatile SumCtx *pSum,
+ volatile double r
+){
+ volatile double s = pSum->rSum;
+ volatile double t = s + r;
+ if( fabs(s) > fabs(r) ){
+ pSum->rErr += (s - t) + r;
+ }else{
+ pSum->rErr += (r - t) + s;
+ }
+ pSum->rSum = t;
+}
+
+/*
+** Add a (possibly large) integer to the running sum.
+*/
+static void kahanBabuskaNeumaierStepInt64(volatile SumCtx *pSum, i64 iVal){
+ if( iVal<=-4503599627370496LL || iVal>=+4503599627370496LL ){
+ i64 iBig, iSm;
+ iSm = iVal % 16384;
+ iBig = iVal - iSm;
+ kahanBabuskaNeumaierStep(pSum, iBig);
+ kahanBabuskaNeumaierStep(pSum, iSm);
+ }else{
+ kahanBabuskaNeumaierStep(pSum, (double)iVal);
+ }
+}
+
+/*
+** Initialize the Kahan-Babaska-Neumaier sum from a 64-bit integer
+*/
+static void kahanBabuskaNeumaierInit(
+ volatile SumCtx *p,
+ i64 iVal
+){
+ if( iVal<=-4503599627370496LL || iVal>=+4503599627370496LL ){
+ i64 iSm = iVal % 16384;
+ p->rSum = (double)(iVal - iSm);
+ p->rErr = (double)iSm;
+ }else{
+ p->rSum = (double)iVal;
+ p->rErr = 0.0;
+ }
+}
+
/*
** Routines used to compute the sum, average, and total.
**
@@ -127515,15 +130509,29 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
type = sqlite3_value_numeric_type(argv[0]);
if( p && type!=SQLITE_NULL ){
p->cnt++;
- if( type==SQLITE_INTEGER ){
- i64 v = sqlite3_value_int64(argv[0]);
- p->rSum += v;
- if( (p->approx|p->overflow)==0 && sqlite3AddInt64(&p->iSum, v) ){
- p->approx = p->overflow = 1;
+ if( p->approx==0 ){
+ if( type!=SQLITE_INTEGER ){
+ kahanBabuskaNeumaierInit(p, p->iSum);
+ p->approx = 1;
+ kahanBabuskaNeumaierStep(p, sqlite3_value_double(argv[0]));
+ }else{
+ i64 x = p->iSum;
+ if( sqlite3AddInt64(&x, sqlite3_value_int64(argv[0]))==0 ){
+ p->iSum = x;
+ }else{
+ p->ovrfl = 1;
+ kahanBabuskaNeumaierInit(p, p->iSum);
+ p->approx = 1;
+ kahanBabuskaNeumaierStepInt64(p, sqlite3_value_int64(argv[0]));
+ }
}
}else{
- p->rSum += sqlite3_value_double(argv[0]);
- p->approx = 1;
+ if( type==SQLITE_INTEGER ){
+ kahanBabuskaNeumaierStepInt64(p, sqlite3_value_int64(argv[0]));
+ }else{
+ p->ovrfl = 0;
+ kahanBabuskaNeumaierStep(p, sqlite3_value_double(argv[0]));
+ }
}
}
}
@@ -127540,13 +130548,18 @@ static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){
if( ALWAYS(p) && type!=SQLITE_NULL ){
assert( p->cnt>0 );
p->cnt--;
- assert( type==SQLITE_INTEGER || p->approx );
- if( type==SQLITE_INTEGER && p->approx==0 ){
- i64 v = sqlite3_value_int64(argv[0]);
- p->rSum -= v;
- p->iSum -= v;
+ if( !p->approx ){
+ p->iSum -= sqlite3_value_int64(argv[0]);
+ }else if( type==SQLITE_INTEGER ){
+ i64 iVal = sqlite3_value_int64(argv[0]);
+ if( iVal!=SMALLEST_INT64 ){
+ kahanBabuskaNeumaierStepInt64(p, -iVal);
+ }else{
+ kahanBabuskaNeumaierStepInt64(p, LARGEST_INT64);
+ kahanBabuskaNeumaierStepInt64(p, 1);
+ }
}else{
- p->rSum -= sqlite3_value_double(argv[0]);
+ kahanBabuskaNeumaierStep(p, -sqlite3_value_double(argv[0]));
}
}
}
@@ -127557,10 +130570,14 @@ static void sumFinalize(sqlite3_context *context){
SumCtx *p;
p = sqlite3_aggregate_context(context, 0);
if( p && p->cnt>0 ){
- if( p->overflow ){
- sqlite3_result_error(context,"integer overflow",-1);
- }else if( p->approx ){
- sqlite3_result_double(context, p->rSum);
+ if( p->approx ){
+ if( p->ovrfl ){
+ sqlite3_result_error(context,"integer overflow",-1);
+ }else if( !sqlite3IsNaN(p->rErr) ){
+ sqlite3_result_double(context, p->rSum+p->rErr);
+ }else{
+ sqlite3_result_double(context, p->rSum);
+ }
}else{
sqlite3_result_int64(context, p->iSum);
}
@@ -127570,14 +130587,29 @@ static void avgFinalize(sqlite3_context *context){
SumCtx *p;
p = sqlite3_aggregate_context(context, 0);
if( p && p->cnt>0 ){
- sqlite3_result_double(context, p->rSum/(double)p->cnt);
+ double r;
+ if( p->approx ){
+ r = p->rSum;
+ if( !sqlite3IsNaN(p->rErr) ) r += p->rErr;
+ }else{
+ r = (double)(p->iSum);
+ }
+ sqlite3_result_double(context, r/(double)p->cnt);
}
}
static void totalFinalize(sqlite3_context *context){
SumCtx *p;
+ double r = 0.0;
p = sqlite3_aggregate_context(context, 0);
- /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
- sqlite3_result_double(context, p ? p->rSum : (double)0);
+ if( p ){
+ if( p->approx ){
+ r = p->rSum;
+ if( !sqlite3IsNaN(p->rErr) ) r += p->rErr;
+ }else{
+ r = (double)(p->iSum);
+ }
+ }
+ sqlite3_result_double(context, r);
}
/*
@@ -127696,6 +130728,7 @@ static void minMaxFinalize(sqlite3_context *context){
/*
** group_concat(EXPR, ?SEPARATOR?)
+** string_agg(EXPR, SEPARATOR)
**
** The SEPARATOR goes before the EXPR string. This is tragic. The
** groupConcatInverse() implementation would have been easier if the
@@ -127799,7 +130832,7 @@ static void groupConcatInverse(
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC));
/* pGCC is always non-NULL since groupConcatStep() will have always
- ** run frist to initialize it */
+ ** run first to initialize it */
if( ALWAYS(pGCC) ){
int nVS;
/* Must call sqlite3_value_text() to convert the argument into text prior
@@ -127883,8 +130916,10 @@ SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){
** sensitive.
*/
SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
+ FuncDef *pDef;
struct compareInfo *pInfo;
int flags;
+ int nArg;
if( caseSensitive ){
pInfo = (struct compareInfo*)&likeInfoAlt;
flags = SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE;
@@ -127892,10 +130927,13 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive)
pInfo = (struct compareInfo*)&likeInfoNorm;
flags = SQLITE_FUNC_LIKE;
}
- sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0);
- sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0);
- sqlite3FindFunction(db, "like", 2, SQLITE_UTF8, 0)->funcFlags |= flags;
- sqlite3FindFunction(db, "like", 3, SQLITE_UTF8, 0)->funcFlags |= flags;
+ for(nArg=2; nArg<=3; nArg++){
+ sqlite3CreateFunc(db, "like", nArg, SQLITE_UTF8, pInfo, likeFunc,
+ 0, 0, 0, 0, 0);
+ pDef = sqlite3FindFunction(db, "like", nArg, SQLITE_UTF8, 0);
+ pDef->funcFlags |= flags;
+ pDef->funcFlags &= ~SQLITE_FUNC_UNSAFE;
+ }
}
/*
@@ -128285,9 +131323,9 @@ int libsql_try_initialize_wasm_func_table(sqlite3 *db) {
sqlite3_finalize(stmt);
return rc;
}
- const char *pName = sqlite3_column_text(stmt, 0);
+ const unsigned char *pName = sqlite3_column_text(stmt, 0);
const void *pBody = body_type == SQLITE_TEXT ? sqlite3_column_text(stmt, 1) : sqlite3_column_blob(stmt, 1);
- try_instantiate_wasm_function(db, pName, name_size, pBody, body_size, -1, NULL);
+ try_instantiate_wasm_function(db, (const char *)pName, name_size, pBody, body_size, -1, NULL);
}
}
sqlite3_finalize(stmt);
@@ -128298,6 +131336,37 @@ int libsql_try_initialize_wasm_func_table(sqlite3 *db) {
#endif // LIBSQL_ENABLE_WASM_RUNTIME
+#ifdef SQLITE_DEBUG
+/*
+** Implementation of fpdecode(x,y,z) function.
+**
+** x is a real number that is to be decoded. y is the precision.
+** z is the maximum real precision.
+*/
+static void fpdecodeFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ FpDecode s;
+ double x;
+ int y, z;
+ char zBuf[100];
+ UNUSED_PARAMETER(argc);
+ assert( argc==3 );
+ x = sqlite3_value_double(argv[0]);
+ y = sqlite3_value_int(argv[1]);
+ z = sqlite3_value_int(argv[2]);
+ sqlite3FpDecode(&s, x, y, z);
+ if( s.isSpecial==2 ){
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "NaN");
+ }else{
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%c%.*s/%d", s.sign, s.n, s.z, s.iDP);
+ }
+ sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
+}
+#endif /* SQLITE_DEBUG */
+
/*
** All of the FuncDef structures in the aBuiltinFunc[] array above
** to the global function hash table. This occurs at start-time (as
@@ -128362,12 +131431,16 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(subtype, 1, 0, 0, subtypeFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
+ FUNCTION2(octet_length, 1, 0, 0, bytelengthFunc,SQLITE_FUNC_BYTELEN),
FUNCTION(instr, 2, 0, 0, instrFunc ),
FUNCTION(printf, -1, 0, 0, printfFunc ),
FUNCTION(format, -1, 0, 0, printfFunc ),
FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
FUNCTION(char, -1, 0, 0, charFunc ),
FUNCTION(abs, 1, 0, 0, absFunc ),
+#ifdef SQLITE_DEBUG
+ FUNCTION(fpdecode, 3, 0, 0, fpdecodeFunc ),
+#endif
#ifndef SQLITE_OMIT_FLOATING_POINT
FUNCTION(round, 1, 0, 0, roundFunc ),
FUNCTION(round, 2, 0, 0, roundFunc ),
@@ -128377,6 +131450,11 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(hex, 1, 0, 0, hexFunc ),
FUNCTION(unhex, 1, 0, 0, unhexFunc ),
FUNCTION(unhex, 2, 0, 0, unhexFunc ),
+ FUNCTION(concat, -1, 0, 0, concatFunc ),
+ FUNCTION(concat, 0, 0, 0, 0 ),
+ FUNCTION(concat_ws, -1, 0, 0, concatwsFunc ),
+ FUNCTION(concat_ws, 0, 0, 0, 0 ),
+ FUNCTION(concat_ws, 1, 0, 0, 0 ),
INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ),
VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
@@ -128406,6 +131484,8 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep,
groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
+ WAGGREGATE(string_agg, 2, 0, 0, groupConcatStep,
+ groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
#ifdef SQLITE_CASE_SENSITIVE_LIKE
@@ -129348,6 +132428,7 @@ static int isSetNullAction(Parse *pParse, FKey *pFKey){
if( (p==pFKey->apTrigger[0] && pFKey->aAction[0]==OE_SetNull)
|| (p==pFKey->apTrigger[1] && pFKey->aAction[1]==OE_SetNull)
){
+ assert( (pTop->db->flags & SQLITE_FkNoAction)==0 );
return 1;
}
}
@@ -129542,6 +132623,8 @@ SQLITE_PRIVATE void sqlite3FkCheck(
}
if( regOld!=0 ){
int eAction = pFKey->aAction[aChange!=0];
+ if( (db->flags & SQLITE_FkNoAction) ) eAction = OE_None;
+
fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regOld, 1);
/* If this is a deferred FK constraint, or a CASCADE or SET NULL
** action applies, then any foreign key violations caused by
@@ -129657,7 +132740,11 @@ SQLITE_PRIVATE int sqlite3FkRequired(
/* Check if any parent key columns are being modified. */
for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
if( fkParentIsModified(pTab, p, aChange, chngRowid) ){
- if( p->aAction[1]!=OE_None ) return 2;
+ if( (pParse->db->flags & SQLITE_FkNoAction)==0
+ && p->aAction[1]!=OE_None
+ ){
+ return 2;
+ }
bHaveFK = 1;
}
}
@@ -129707,6 +132794,7 @@ static Trigger *fkActionTrigger(
int iAction = (pChanges!=0); /* 1 for UPDATE, 0 for DELETE */
action = pFKey->aAction[iAction];
+ if( (db->flags & SQLITE_FkNoAction) ) action = OE_None;
if( action==OE_Restrict && (db->flags & SQLITE_DeferFKs) ){
return 0;
}
@@ -129807,22 +132895,22 @@ static Trigger *fkActionTrigger(
if( action==OE_Restrict ){
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
- Token tFrom;
- Token tDb;
+ SrcList *pSrc;
Expr *pRaise;
- tFrom.z = zFrom;
- tFrom.n = nFrom;
- tDb.z = db->aDb[iDb].zDbSName;
- tDb.n = sqlite3Strlen30(tDb.z);
-
pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed");
if( pRaise ){
pRaise->affExpr = OE_Abort;
}
+ pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
+ if( pSrc ){
+ assert( pSrc->nSrc==1 );
+ pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom);
+ pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
+ }
pSelect = sqlite3SelectNew(pParse,
sqlite3ExprListAppend(pParse, 0, pRaise),
- sqlite3SrcListAppend(pParse, 0, &tDb, &tFrom),
+ pSrc,
pWhere,
0, 0, 0, 0, 0
);
@@ -129938,9 +133026,8 @@ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){
if( pFKey->pPrevTo ){
pFKey->pPrevTo->pNextTo = pFKey->pNextTo;
}else{
- void *p = (void *)pFKey->pNextTo;
- const char *z = (p ? pFKey->pNextTo->zTo : pFKey->zTo);
- sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, p);
+ const char *z = (pFKey->pNextTo ? pFKey->pNextTo->zTo : pFKey->zTo);
+ sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, pFKey->pNextTo);
}
if( pFKey->pNextTo ){
pFKey->pNextTo->pPrevTo = pFKey->pPrevTo;
@@ -130003,8 +133090,10 @@ SQLITE_PRIVATE void sqlite3OpenTable(
assert( pParse->pVdbe!=0 );
v = pParse->pVdbe;
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
- sqlite3TableLock(pParse, iDb, pTab->tnum,
- (opcode==OP_OpenWrite)?1:0, pTab->zName);
+ if( !pParse->db->noSharedCache ){
+ sqlite3TableLock(pParse, iDb, pTab->tnum,
+ (opcode==OP_OpenWrite)?1:0, pTab->zName);
+ }
if( HasRowid(pTab) ){
sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nNVCol);
VdbeComment((v, "%s", pTab->zName));
@@ -130133,7 +133222,7 @@ SQLITE_PRIVATE char *sqlite3TableAffinityStr(sqlite3 *db, const Table *pTab){
** For STRICT tables:
** ------------------
**
-** Generate an appropropriate OP_TypeCheck opcode that will verify the
+** Generate an appropriate OP_TypeCheck opcode that will verify the
** datatypes against the column definitions in pTab. If iReg==0, that
** means an OP_MakeRecord opcode has already been generated and should be
** the last opcode generated. The new OP_TypeCheck needs to be inserted
@@ -130764,7 +133853,7 @@ SQLITE_PRIVATE void sqlite3Insert(
/* Cannot insert into a read-only table.
*/
- if( sqlite3IsReadOnly(pParse, pTab, tmask) ){
+ if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
goto insert_cleanup;
}
@@ -131214,7 +134303,7 @@ SQLITE_PRIVATE void sqlite3Insert(
}
/* Copy the new data already generated. */
- assert( pTab->nNVCol>0 );
+ assert( pTab->nNVCol>0 || pParse->nErr>0 );
sqlite3VdbeAddOp3(v, OP_Copy, regRowid+1, regCols+1, pTab->nNVCol-1);
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
@@ -131428,7 +134517,7 @@ SQLITE_PRIVATE void sqlite3Insert(
/* This is the Walker callback from sqlite3ExprReferencesUpdatedColumn().
* Set bit 0x01 of pWalker->eCode if pWalker->eCode to 0 and if this
** expression node references any of the
-** columns that are being modifed by an UPDATE statement.
+** columns that are being modified by an UPDATE statement.
*/
static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_COLUMN ){
@@ -131651,7 +134740,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
int *aiChng, /* column i is unchanged if aiChng[i]<0 */
Upsert *pUpsert /* ON CONFLICT clauses, if any. NULL otherwise */
){
- Vdbe *v; /* VDBE under constrution */
+ Vdbe *v; /* VDBE under construction */
Index *pIdx; /* Pointer to one of the indices */
Index *pPk = 0; /* The PRIMARY KEY index for WITHOUT ROWID tables */
sqlite3 *db; /* Database connection */
@@ -132134,7 +135223,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
pIdx;
pIdx = indexIteratorNext(&sIdxIter, &ix)
){
- int regIdx; /* Range of registers hold conent for pIdx */
+ int regIdx; /* Range of registers holding content for pIdx */
int regR; /* Range of registers holding conflicting PK */
int iThisCur; /* Cursor for this UNIQUE index */
int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */
@@ -132629,6 +135718,8 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
assert( op==OP_OpenRead || op==OP_OpenWrite );
assert( op==OP_OpenWrite || p5==0 );
+ assert( piDataCur!=0 );
+ assert( piIdxCur!=0 );
if( IsVirtual(pTab) ){
/* This routine is a no-op for virtual tables. Leave the output
** variables *piDataCur and *piIdxCur set to illegal cursor numbers
@@ -132641,18 +135732,18 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
assert( v!=0 );
if( iBase<0 ) iBase = pParse->nTab;
iDataCur = iBase++;
- if( piDataCur ) *piDataCur = iDataCur;
+ *piDataCur = iDataCur;
if( HasRowid(pTab) && (aToOpen==0 || aToOpen[0]) ){
sqlite3OpenTable(pParse, iDataCur, iDb, pTab, op);
- }else{
+ }else if( pParse->db->noSharedCache==0 ){
sqlite3TableLock(pParse, iDb, pTab->tnum, op==OP_OpenWrite, pTab->zName);
}
- if( piIdxCur ) *piIdxCur = iBase;
+ *piIdxCur = iBase;
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
int iIdxCur = iBase++;
assert( pIdx->pSchema==pTab->pSchema );
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
- if( piDataCur ) *piDataCur = iIdxCur;
+ *piDataCur = iIdxCur;
p5 = 0;
}
if( aToOpen==0 || aToOpen[i+1] ){
@@ -132950,7 +136041,7 @@ static int xferOptimization(
}
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
- /* Disallow the transfer optimization if the destination table constains
+ /* Disallow the transfer optimization if the destination table contains
** any foreign key constraints. This is more restrictive than necessary.
** But the main beneficiary of the transfer optimization is the VACUUM
** command, and the VACUUM command disables foreign key constraints. So
@@ -133028,7 +136119,7 @@ static int xferOptimization(
}
autoIncStep(pParse, regNextRowid, regRowid);
}else if( pDest->pIndex==0 && !(db->mDbFlags & DBFLAG_VacuumInto) ){
- addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid);
+ addr1 = sqlite3VdbeAddOp3(v, OP_NewRowid, iDest, regRowid, regNextRowid);
}else{
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
assert( (pDest->tabFlags & TF_Autoincrement)==0 );
@@ -133663,14 +136754,16 @@ struct sqlite3_api_routines {
int (*value_encoding)(sqlite3_value*);
/* Version 3.41.0 and later */
int (*is_interrupted)(sqlite3*);
-
+ /* Version 3.43.0 and later */
+ int (*stmt_explain)(sqlite3_stmt*,int);
+ /* Version 3.44.0 and later */
+ void *(*get_clientdata)(sqlite3*,const char*);
+ int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
};
struct libsql_api_routines {
- /* libSQL 0.1.1 */
- struct libsql_wal_methods *(*wal_methods_find)(const char *);
- int (*wal_methods_register)(struct libsql_wal_methods*);
- int (*wal_methods_unregister)(struct libsql_wal_methods*);
+ /* libSQL 0.2.3 */
+ void *(*close_hook)(sqlite3*, void(*)(void*,sqlite3*), void *pArg);
};
/*
@@ -134000,10 +137093,13 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_value_encoding sqlite3_api->value_encoding
/* Version 3.41.0 and later */
#define sqlite3_is_interrupted sqlite3_api->is_interrupted
-/* libSQL 0.1.1 */
-#define libsql_wal_methods_find libsql_api->wal_methods_find
-#define libsql_wal_methods_register libsql_api->wal_methods_register
-#define libsql_wal_methods_unregister libsql_api->wal_methods_unregister
+/* Version 3.43.0 and later */
+#define sqlite3_stmt_explain sqlite3_api->stmt_explain
+/* libSQL 0.2.3 */
+#define libsql_close_hook libsql_api->close_hook
+/* Version 3.44.0 and later */
+#define sqlite3_get_clientdata sqlite3_api->get_clientdata
+#define sqlite3_set_clientdata sqlite3_api->set_clientdata
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
@@ -134531,14 +137627,16 @@ static const sqlite3_api_routines sqlite3Apis = {
/* Version 3.40.0 and later */
sqlite3_value_encoding,
/* Version 3.41.0 and later */
- sqlite3_is_interrupted
+ sqlite3_is_interrupted,
+ /* Version 3.43.0 and later */
+ sqlite3_stmt_explain,
+ /* Version 3.44.0 and later */
+ sqlite3_get_clientdata,
+ sqlite3_set_clientdata
};
static const libsql_api_routines libsqlApis = {
- /* libSQL 0.1.1 */
- libsql_wal_methods_find,
- libsql_wal_methods_register,
- libsql_wal_methods_unregister
+ libsql_close_hook,
};
/* True if x is the directory separator character
*/
@@ -134610,15 +137708,25 @@ static int sqlite3LoadExtension(
/* tag-20210611-1. Some dlopen() implementations will segfault if given
** an oversize filename. Most filesystems have a pathname limit of 4K,
** so limit the extension filename length to about twice that.
- ** https://sqlite.org/forum/forumpost/08a0d6d9bf */
+ ** https://sqlite.org/forum/forumpost/08a0d6d9bf
+ **
+ ** Later (2023-03-25): Save an extra 6 bytes for the filename suffix.
+ ** See https://sqlite.org/forum/forumpost/24083b579d.
+ */
if( nMsg>SQLITE_MAX_PATHLEN ) goto extension_not_found;
+ /* Do not allow sqlite3_load_extension() to link to a copy of the
+ ** running application, by passing in an empty filename. */
+ if( nMsg==0 ) goto extension_not_found;
+
handle = sqlite3OsDlOpen(pVfs, zFile);
#if SQLITE_OS_UNIX || SQLITE_OS_WIN
for(ii=0; iimutex);
if( onoff ){
db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc;
@@ -134792,6 +137903,9 @@ SQLITE_API int sqlite3_auto_extension(
void (*xInit)(void)
){
int rc = SQLITE_OK;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( xInit==0 ) return SQLITE_MISUSE_BKPT;
+#endif
#ifndef SQLITE_OMIT_AUTOINIT
rc = sqlite3_initialize();
if( rc ){
@@ -134844,6 +137958,9 @@ SQLITE_API int sqlite3_cancel_auto_extension(
int i;
int n = 0;
wsdAutoextInit;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( xInit==0 ) return 0;
+#endif
sqlite3_mutex_enter(mutex);
for(i=(int)wsdAutoext.nExt-1; i>=0; i--){
if( wsdAutoext.aExt[i]==xInit ){
@@ -135954,6 +139071,10 @@ static int integrityCheckResultRow(Vdbe *v){
return addr;
}
+#ifdef LIBSQL_EXTRA_PRAGMAS
+int libsql_extra_pragma(sqlite3* db, const char* zDbName, void* pArg);
+#endif
+
/*
** Process a pragma statement.
**
@@ -136040,6 +139161,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
aFcntl[3] = 0;
db->busyHandler.nBusy = 0;
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl);
+#ifdef LIBSQL_EXTRA_PRAGMAS
+ if(rc == SQLITE_NOTFOUND) {
+ rc = libsql_extra_pragma(db, zDb, (void*)aFcntl);
+ }
+#endif
if( rc==SQLITE_OK ){
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, aFcntl[0], SQLITE_TRANSIENT);
@@ -136445,7 +139571,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
**
** The first form reports the current local setting for the
** page cache spill size. The second form turns cache spill on
- ** or off. When turnning cache spill on, the size is set to the
+ ** or off. When turning cache spill on, the size is set to the
** current cache_size. The third form sets a spill size that
** may be different form the cache size.
** If N is positive then that is the
@@ -136715,7 +139841,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
#endif
if( sqlite3GetBoolean(zRight, 0) ){
- db->flags |= mask;
+ if( (mask & SQLITE_WriteSchema)==0
+ || (db->flags & SQLITE_Defensive)==0
+ ){
+ db->flags |= mask;
+ }
}else{
db->flags &= ~mask;
if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0;
@@ -137115,7 +140245,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
zDb = db->aDb[iDb].zDbSName;
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
- if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow;
+ sqlite3TouchRegister(pParse, pTab->nCol+regRow);
sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead);
sqlite3VdbeLoadString(v, regResult, pTab->zName);
assert( IsOrdinaryTable(pTab) );
@@ -137156,7 +140286,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
** regRow..regRow+n. If any of the child key values are NULL, this
** row cannot cause an FK violation. Jump directly to addrOk in
** this case. */
- if( regRow+pFK->nCol>pParse->nMem ) pParse->nMem = regRow+pFK->nCol;
+ sqlite3TouchRegister(pParse, regRow + pFK->nCol);
for(j=0; jnCol; j++){
int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom;
sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j);
@@ -137223,9 +140353,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
** The "quick_check" is reduced version of
** integrity_check designed to detect most database corruption
** without the overhead of cross-checking indexes. Quick_check
- ** is linear time wherease integrity_check is O(NlogN).
+ ** is linear time whereas integrity_check is O(NlogN).
**
- ** The maximum nubmer of errors is 100 by default. A different default
+ ** The maximum number of errors is 100 by default. A different default
** can be specified using a numeric parameter N.
**
** Or, the parameter N can be the name of a table. In that case, only
@@ -137285,6 +140415,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( iDb>=0 && i!=iDb ) continue;
sqlite3CodeVerifySchema(pParse, i);
+ pParse->okConstFactor = 0; /* tag-20230327-1 */
/* Do an integrity check of the B-Tree
**
@@ -137320,7 +140451,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
aRoot[0] = cnt;
/* Make sure sufficient number of registers have been allocated */
- pParse->nMem = MAX( pParse->nMem, 8+mxIdx );
+ sqlite3TouchRegister(pParse, 8+mxIdx);
sqlite3ClearTempRegCache(pParse);
/* Do the b-tree integrity checks */
@@ -137347,8 +140478,31 @@ SQLITE_PRIVATE void sqlite3Pragma(
int r2; /* Previous key for WITHOUT ROWID tables */
int mxCol; /* Maximum non-virtual column number */
- if( !IsOrdinaryTable(pTab) ) continue;
if( pObjTab && pObjTab!=pTab ) continue;
+ if( !IsOrdinaryTable(pTab) ){
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ sqlite3_vtab *pVTab;
+ int a1;
+ if( !IsVirtual(pTab) ) continue;
+ if( pTab->nCol<=0 ){
+ const char *zMod = pTab->u.vtab.azArg[0];
+ if( sqlite3HashFind(&db->aModule, zMod)==0 ) continue;
+ }
+ sqlite3ViewGetColumnNames(pParse, pTab);
+ if( pTab->u.vtab.p==0 ) continue;
+ pVTab = pTab->u.vtab.p->pVtab;
+ if( NEVER(pVTab==0) ) continue;
+ if( NEVER(pVTab->pModule==0) ) continue;
+ if( pVTab->pModule->iVersion<4 ) continue;
+ if( pVTab->pModule->xIntegrity==0 ) continue;
+ sqlite3VdbeAddOp3(v, OP_VCheck, i, 3, isQuick);
+ sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
+ a1 = sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v);
+ integrityCheckResultRow(v);
+ sqlite3VdbeJumpHere(v, a1);
+#endif
+ continue;
+ }
if( isQuick || HasRowid(pTab) ){
pPk = 0;
r2 = 0;
@@ -137470,15 +140624,29 @@ SQLITE_PRIVATE void sqlite3Pragma(
labelOk = sqlite3VdbeMakeLabel(pParse);
if( pCol->notNull ){
/* (1) NOT NULL columns may not contain a NULL */
+ int jmp3;
int jmp2 = sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
- sqlite3VdbeChangeP5(v, 0x0f);
VdbeCoverage(v);
+ if( p1<0 ){
+ sqlite3VdbeChangeP5(v, 0x0f); /* INT, REAL, TEXT, or BLOB */
+ jmp3 = jmp2;
+ }else{
+ sqlite3VdbeChangeP5(v, 0x0d); /* INT, TEXT, or BLOB */
+ /* OP_IsType does not detect NaN values in the database file
+ ** which should be treated as a NULL. So if the header type
+ ** is REAL, we have to load the actual data using OP_Column
+ ** to reliably determine if the value is a NULL. */
+ sqlite3VdbeAddOp3(v, OP_Column, p1, p3, 3);
+ jmp3 = sqlite3VdbeAddOp2(v, OP_NotNull, 3, labelOk);
+ VdbeCoverage(v);
+ }
zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
pCol->zCnName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
if( doTypeCheck ){
sqlite3VdbeGoto(v, labelError);
sqlite3VdbeJumpHere(v, jmp2);
+ sqlite3VdbeJumpHere(v, jmp3);
}else{
/* VDBE byte code will fall thru */
}
@@ -137968,7 +141136,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
Schema *pSchema; /* The current schema */
Table *pTab; /* A table in the schema */
Index *pIdx; /* An index of the table */
- LogEst szThreshold; /* Size threshold above which reanalysis is needd */
+ LogEst szThreshold; /* Size threshold above which reanalysis needed */
char *zSubSql; /* SQL statement for the OP_SqlExec opcode */
u32 opMask; /* Mask of operations to perform */
@@ -138460,7 +141628,8 @@ static const sqlite3_module pragmaVtabModule = {
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
/*
@@ -138792,7 +141961,9 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl
#else
encoding = SQLITE_UTF8;
#endif
- if( db->nVdbeActive>0 && encoding!=ENC(db) ){
+ if( db->nVdbeActive>0 && encoding!=ENC(db)
+ && (db->mDbFlags & DBFLAG_Vacuum)==0
+ ){
rc = SQLITE_LOCKED;
goto initone_error_out;
}else{
@@ -139082,8 +142253,6 @@ SQLITE_PRIVATE void sqlite3ParseObjectReset(Parse *pParse){
db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue;
assert( pParse->db->pParse==pParse );
db->pParse = pParse->pOuterParse;
- pParse->db = 0;
- pParse->disableLookaside = 0;
}
/*
@@ -139092,7 +142261,7 @@ SQLITE_PRIVATE void sqlite3ParseObjectReset(Parse *pParse){
** immediately.
**
** Use this mechanism for uncommon cleanups. There is a higher setup
-** cost for this mechansim (an extra malloc), so it should not be used
+** cost for this mechanism (an extra malloc), so it should not be used
** for common cleanups that happen on most calls. But for less
** common cleanups, we save a single NULL-pointer comparison in
** sqlite3ParseObjectReset(), which reduces the total CPU cycle count.
@@ -139184,9 +142353,18 @@ static int sqlite3Prepare(
sParse.pOuterParse = db->pParse;
db->pParse = &sParse;
sParse.db = db;
- sParse.pReprepare = pReprepare;
+ if( pReprepare ){
+ sParse.pReprepare = pReprepare;
+ sParse.explain = sqlite3_stmt_isexplain((sqlite3_stmt*)pReprepare);
+ }else{
+ assert( sParse.pReprepare==0 );
+ }
assert( ppStmt && *ppStmt==0 );
- if( db->mallocFailed ) sqlite3ErrorMsg(&sParse, "out of memory");
+ if( db->mallocFailed ){
+ sqlite3ErrorMsg(&sParse, "out of memory");
+ db->errCode = rc = SQLITE_NOMEM;
+ goto end_prepare;
+ }
assert( sqlite3_mutex_held(db->mutex) );
/* For a long-term use prepared statement avoid the use of
@@ -139790,7 +142968,7 @@ static Select *findRightmost(Select *p){
** NATURAL FULL OUTER JT_NATRUAL|JT_LEFT|JT_RIGHT
**
** To preserve historical compatibly, SQLite also accepts a variety
-** of other non-standard and in many cases non-sensical join types.
+** of other non-standard and in many cases nonsensical join types.
** This routine makes as much sense at it can from the nonsense join
** type and returns a result. Examples of accepted nonsense join types
** include but are not limited to:
@@ -140012,6 +143190,7 @@ static void unsetJoinExpr(Expr *p, int iTable, int nullable){
}
if( p->op==TK_FUNCTION ){
assert( ExprUseXList(p) );
+ assert( p->pLeft==0 );
if( p->x.pList ){
int i;
for(i=0; ix.pList->nExpr; i++){
@@ -140061,7 +143240,7 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){
if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue;
joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON;
- /* If this is a NATURAL join, synthesize an approprate USING clause
+ /* If this is a NATURAL join, synthesize an appropriate USING clause
** to specify which columns should be joined.
*/
if( pRight->fg.jointype & JT_NATURAL ){
@@ -140275,9 +143454,9 @@ static void pushOntoSorter(
** (2) All output columns are included in the sort record. In that
** case regData==regOrigData.
** (3) Some output columns are omitted from the sort record due to
- ** the SQLITE_ENABLE_SORTER_REFERENCE optimization, or due to the
+ ** the SQLITE_ENABLE_SORTER_REFERENCES optimization, or due to the
** SQLITE_ECEL_OMITREF optimization, or due to the
- ** SortCtx.pDeferredRowLoad optimiation. In any of these cases
+ ** SortCtx.pDeferredRowLoad optimization. In any of these cases
** regOrigData is 0 to prevent this routine from trying to copy
** values that might not yet exist.
*/
@@ -140333,7 +143512,7 @@ static void pushOntoSorter(
testcase( pKI->nAllField > pKI->nKeyField+2 );
pOp->p4.pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pSort->pOrderBy,nOBSat,
pKI->nAllField-pKI->nKeyField-1);
- pOp = 0; /* Ensure pOp not used after sqltie3VdbeAddOp3() */
+ pOp = 0; /* Ensure pOp not used after sqlite3VdbeAddOp3() */
addrJmp = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
pSort->labelBkOut = sqlite3VdbeMakeLabel(pParse);
@@ -140427,7 +143606,7 @@ static void codeOffset(
** The returned value in this case is a copy of parameter iTab.
**
** WHERE_DISTINCT_ORDERED:
-** In this case rows are being delivered sorted order. The ephermal
+** In this case rows are being delivered sorted order. The ephemeral
** table is not required. Instead, the current set of values
** is compared against previous row. If they match, the new row
** is not distinct and control jumps to VM address addrRepeat. Otherwise,
@@ -140856,6 +144035,16 @@ static void selectInnerLoop(
testcase( eDest==SRT_Fifo );
testcase( eDest==SRT_DistFifo );
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1+nPrefixReg);
+#if !defined(SQLITE_ENABLE_NULL_TRIM) && defined(SQLITE_DEBUG)
+ /* A destination of SRT_Table and a non-zero iSDParm2 parameter means
+ ** that this is an "UPDATE ... FROM" on a virtual table or view. In this
+ ** case set the p5 parameter of the OP_MakeRecord to OPFLAG_NOCHNG_MAGIC.
+ ** This does not affect operation in any way - it just allows MakeRecord
+ ** to process OPFLAG_NOCHANGE values without an assert() failing. */
+ if( eDest==SRT_Table && pDest->iSDParm2 ){
+ sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC);
+ }
+#endif
#ifndef SQLITE_OMIT_CTE
if( eDest==SRT_DistFifo ){
/* If the destination is DistFifo, then cursor (iParm+1) is open
@@ -141659,13 +144848,6 @@ SQLITE_PRIVATE void sqlite3GenerateColumnNames(
int fullName; /* TABLE.COLUMN if no AS clause and is a direct table ref */
int srcName; /* COLUMN or TABLE.COLUMN if no AS clause and is direct */
-#ifndef SQLITE_OMIT_EXPLAIN
- /* If this is an EXPLAIN, skip this step */
- if( pParse->explain ){
- return;
- }
-#endif
-
if( pParse->colNamesSet ) return;
/* Column names are determined by the left-most term of a compound select */
while( pSelect->pPrior ) pSelect = pSelect->pPrior;
@@ -141852,7 +145034,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
** kind (maybe a parenthesized subquery in the FROM clause of a larger
** query, or a VIEW, or a CTE). This routine computes type information
** for that Table object based on the Select object that implements the
-** subquery. For the purposes of this routine, "type infomation" means:
+** subquery. For the purposes of this routine, "type information" means:
**
** * The datatype name, as it might appear in a CREATE TABLE statement
** * Which collating sequence to use for the column
@@ -141876,7 +145058,7 @@ SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(
assert( (pSelect->selFlags & SF_Resolved)!=0 );
assert( pTab->nCol==pSelect->pEList->nExpr || pParse->nErr>0 );
assert( aff==SQLITE_AFF_NONE || aff==SQLITE_AFF_BLOB );
- if( db->mallocFailed ) return;
+ if( db->mallocFailed || IN_RENAME_OBJECT ) return;
while( pSelect->pPrior ) pSelect = pSelect->pPrior;
a = pSelect->pEList->a;
memset(&sNC, 0, sizeof(sNC));
@@ -141921,18 +145103,16 @@ SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(
break;
}
}
- }
- }
- if( zType ){
- i64 m = sqlite3Strlen30(zType);
- n = sqlite3Strlen30(pCol->zCnName);
- pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+m+2);
- if( pCol->zCnName ){
- memcpy(&pCol->zCnName[n+1], zType, m+1);
- pCol->colFlags |= COLFLAG_HASTYPE;
- }else{
- testcase( pCol->colFlags & COLFLAG_HASTYPE );
- pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL);
+ }
+ }
+ if( zType ){
+ i64 m = sqlite3Strlen30(zType);
+ n = sqlite3Strlen30(pCol->zCnName);
+ pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+m+2);
+ pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL);
+ if( pCol->zCnName ){
+ memcpy(&pCol->zCnName[n+1], zType, m+1);
+ pCol->colFlags |= COLFLAG_HASTYPE;
}
}
pColl = sqlite3ExprCollSeq(pParse, p);
@@ -142183,7 +145363,7 @@ static void generateWithRecursiveQuery(
int iQueue; /* The Queue table */
int iDistinct = 0; /* To ensure unique results if UNION */
int eDest = SRT_Fifo; /* How to write to Queue */
- SelectDest destQueue; /* SelectDest targetting the Queue table */
+ SelectDest destQueue; /* SelectDest targeting the Queue table */
int i; /* Loop counter */
int rc; /* Result code */
ExprList *pOrderBy; /* The ORDER BY clause */
@@ -142783,7 +145963,7 @@ SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p){
/*
** Code an output subroutine for a coroutine implementation of a
-** SELECT statment.
+** SELECT statement.
**
** The data to be output is contained in pIn->iSdst. There are
** pIn->nSdst columns to be output. pDest is where the output should
@@ -143005,7 +146185,7 @@ static int generateOutputSubroutine(
**
** We call AltB, AeqB, AgtB, EofA, and EofB "subroutines" but they are not
** actually called using Gosub and they do not Return. EofA and EofB loop
-** until all data is exhausted then jump to the "end" labe. AltB, AeqB,
+** until all data is exhausted then jump to the "end" label. AltB, AeqB,
** and AgtB jump to either L2 or to one of EofA or EofB.
*/
#ifndef SQLITE_OMIT_COMPOUND_SELECT
@@ -143042,7 +146222,7 @@ static int multiSelectOrderBy(
int savedOffset; /* Saved value of p->iOffset */
int labelCmpr; /* Label for the start of the merge algorithm */
int labelEnd; /* Label for the end of the overall SELECT stmt */
- int addr1; /* Jump instructions that get retargetted */
+ int addr1; /* Jump instructions that get retargeted */
int op; /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */
KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */
KeyInfo *pKeyMerge; /* Comparison information for merging rows */
@@ -143411,11 +146591,14 @@ static Expr *substExpr(
#endif
{
Expr *pNew;
- int iColumn = pExpr->iColumn;
- Expr *pCopy = pSubst->pEList->a[iColumn].pExpr;
+ int iColumn;
+ Expr *pCopy;
Expr ifNullRow;
+ iColumn = pExpr->iColumn;
+ assert( iColumn>=0 );
assert( pSubst->pEList!=0 && iColumnpEList->nExpr );
assert( pExpr->pRight==0 );
+ pCopy = pSubst->pEList->a[iColumn].pExpr;
if( sqlite3ExprIsVector(pCopy) ){
sqlite3VectorErrorMsg(pSubst->pParse, pCopy);
}else{
@@ -143764,7 +146947,7 @@ static int compoundHasDifferentAffinities(Select *p){
** (9) If the subquery uses LIMIT then the outer query may not be aggregate.
**
** (**) Restriction (10) was removed from the code on 2005-02-05 but we
-** accidently carried the comment forward until 2014-09-15. Original
+** accidentally carried the comment forward until 2014-09-15. Original
** constraint: "If the subquery is aggregate then the outer query
** may not use LIMIT."
**
@@ -143856,7 +147039,8 @@ static int compoundHasDifferentAffinities(Select *p){
** (27b) the subquery is a compound query and the RIGHT JOIN occurs
** in any arm of the compound query. (See also (17g).)
**
-** (28) The subquery is not a MATERIALIZED CTE.
+** (28) The subquery is not a MATERIALIZED CTE. (This is handled
+** in the caller before ever reaching this routine.)
**
**
** In this routine, the "p" parameter is a pointer to the outer query.
@@ -143966,9 +147150,9 @@ static int flattenSubquery(
if( iFrom>0 && (pSubSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){
return 0; /* Restriction (27a) */
}
- if( pSubitem->fg.isCte && pSubitem->u2.pCteUse->eM10d==M10d_Yes ){
- return 0; /* (28) */
- }
+
+ /* Condition (28) is blocked by the caller */
+ assert( !pSubitem->fg.isCte || pSubitem->u2.pCteUse->eM10d!=M10d_Yes );
/* Restriction (17): If the sub-query is a compound SELECT, then it must
** use only the UNION ALL operator. And none of the simple select queries
@@ -144038,7 +147222,7 @@ static int flattenSubquery(
testcase( i==SQLITE_DENY );
pParse->zAuthContext = zSavedAuthContext;
- /* Delete the transient structures associated with thesubquery */
+ /* Delete the transient structures associated with the subquery */
pSub1 = pSubitem->pSelect;
sqlite3DbFree(db, pSubitem->zDatabase);
sqlite3DbFree(db, pSubitem->zName);
@@ -144220,7 +147404,7 @@ static int flattenSubquery(
** ORDER BY column expression is identical to the iOrderByCol'th
** expression returned by SELECT statement pSub. Since these values
** do not necessarily correspond to columns in SELECT statement pParent,
- ** zero them before transfering the ORDER BY clause.
+ ** zero them before transferring the ORDER BY clause.
**
** Not doing this may cause an error if a subsequent call to this
** function attempts to flatten a compound sub-query into pParent
@@ -144280,8 +147464,7 @@ static int flattenSubquery(
}
}
- /* Finially, delete what is left of the subquery and return
- ** success.
+ /* Finally, delete what is left of the subquery and return success.
*/
sqlite3AggInfoPersistWalkerInit(&w, pParse);
sqlite3WalkSelect(&w,pSub1);
@@ -144316,7 +147499,7 @@ struct WhereConst {
/*
** Add a new entry to the pConst object. Except, do not add duplicate
-** pColumn entires. Also, do not add if doing so would not be appropriate.
+** pColumn entries. Also, do not add if doing so would not be appropriate.
**
** The caller guarantees the pColumn is a column and pValue is a constant.
** This routine has to do some additional checks before completing the
@@ -144502,7 +147685,7 @@ static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){
** SELECT * FROM t1 WHERE a=123 AND b=123;
**
** The two SELECT statements above should return different answers. b=a
-** is alway true because the comparison uses numeric affinity, but b=123
+** is always true because the comparison uses numeric affinity, but b=123
** is false because it uses text affinity and '0123' is not the same as '123'.
** To work around this, the expression tree is not actually changed from
** "b=a" to "b=123" but rather the "a" in "b=a" is tagged with EP_FixedCol
@@ -144586,7 +147769,7 @@ static int propagateConstants(
** At the time this function is called it is guaranteed that
**
** * the sub-query uses only one distinct window frame, and
-** * that the window frame has a PARTITION BY clase.
+** * that the window frame has a PARTITION BY clause.
*/
static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){
assert( pSubq->pWin->pPartition );
@@ -144667,6 +147850,24 @@ static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){
** or EXCEPT, then all of the result set columns for all arms of
** the compound must use the BINARY collating sequence.
**
+** (9) All three of the following are true:
+**
+** (9a) The WHERE clause expression originates in the ON or USING clause
+** of a join (either an INNER or an OUTER join), and
+**
+** (9b) The subquery is to the right of the ON/USING clause
+**
+** (9c) There is a RIGHT JOIN (or FULL JOIN) in between the ON/USING
+** clause and the subquery.
+**
+** Without this restriction, the push-down optimization might move
+** the ON/USING filter expression from the left side of a RIGHT JOIN
+** over to the right side, which leads to incorrect answers. See
+** also restriction (6) in sqlite3ExprIsSingleTableConstraint().
+**
+** (10) The inner query is not the right-hand table of a RIGHT JOIN.
+**
+** (11) The subquery is not a VALUES clause
**
** Return 0 if no changes are made and non-zero if one or more WHERE clause
** terms are duplicated into the subquery.
@@ -144675,13 +147876,20 @@ static int pushDownWhereTerms(
Parse *pParse, /* Parse context (for malloc() and error reporting) */
Select *pSubq, /* The subquery whose WHERE clause is to be augmented */
Expr *pWhere, /* The WHERE clause of the outer query */
- SrcItem *pSrc /* The subquery term of the outer FROM clause */
+ SrcList *pSrcList, /* The complete from clause of the outer query */
+ int iSrc /* Which FROM clause term to try to push into */
){
Expr *pNew;
+ SrcItem *pSrc; /* The subquery FROM term into which WHERE is pushed */
int nChng = 0;
+ pSrc = &pSrcList->a[iSrc];
if( pWhere==0 ) return 0;
- if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ) return 0;
- if( pSrc->fg.jointype & (JT_LTORJ|JT_RIGHT) ) return 0;
+ if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ){
+ return 0; /* restrictions (2) and (11) */
+ }
+ if( pSrc->fg.jointype & (JT_LTORJ|JT_RIGHT) ){
+ return 0; /* restrictions (10) */
+ }
if( pSubq->pPrior ){
Select *pSel;
@@ -144736,11 +147944,28 @@ static int pushDownWhereTerms(
return 0; /* restriction (3) */
}
while( pWhere->op==TK_AND ){
- nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, pSrc);
+ nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, pSrcList, iSrc);
pWhere = pWhere->pLeft;
}
-#if 0 /* Legacy code. Checks now done by sqlite3ExprIsTableConstraint() */
+#if 0 /* These checks now done by sqlite3ExprIsSingleTableConstraint() */
+ if( ExprHasProperty(pWhere, EP_OuterON|EP_InnerON) /* (9a) */
+ && (pSrcList->a[0].fg.jointype & JT_LTORJ)!=0 /* Fast pre-test of (9c) */
+ ){
+ int jj;
+ for(jj=0; jjw.iJoin==pSrcList->a[jj].iCursor ){
+ /* If we reach this point, both (9a) and (9b) are satisfied.
+ ** The following loop checks (9c):
+ */
+ for(jj++; jja[jj].fg.jointype & JT_RIGHT)!=0 ){
+ return 0; /* restriction (9) */
+ }
+ }
+ }
+ }
+ }
if( isLeftJoin
&& (ExprHasProperty(pWhere,EP_OuterON)==0
|| pWhere->w.iJoin!=iCursor)
@@ -144754,7 +147979,7 @@ static int pushDownWhereTerms(
}
#endif
- if( sqlite3ExprIsTableConstraint(pWhere, pSrc) ){
+ if( sqlite3ExprIsSingleTableConstraint(pWhere, pSrcList, iSrc) ){
nChng++;
pSubq->selFlags |= SF_PushDown;
while( pSubq ){
@@ -144813,22 +148038,24 @@ static int disableUnusedSubqueryResultColumns(SrcItem *pItem){
assert( pItem->pSelect!=0 );
pSub = pItem->pSelect;
assert( pSub->pEList->nExpr==pTab->nCol );
- if( (pSub->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){
- testcase( pSub->selFlags & SF_Distinct );
- testcase( pSub->selFlags & SF_Aggregate );
- return 0;
- }
for(pX=pSub; pX; pX=pX->pPrior){
+ if( (pX->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){
+ testcase( pX->selFlags & SF_Distinct );
+ testcase( pX->selFlags & SF_Aggregate );
+ return 0;
+ }
if( pX->pPrior && pX->op!=TK_ALL ){
/* This optimization does not work for compound subqueries that
** use UNION, INTERSECT, or EXCEPT. Only UNION ALL is allowed. */
return 0;
}
+#ifndef SQLITE_OMIT_WINDOWFUNC
if( pX->pWin ){
/* This optimization does not work for subqueries that use window
** functions. */
return 0;
}
+#endif
}
colUsed = pItem->colUsed;
if( pSub->pOrderBy ){
@@ -145622,12 +148849,20 @@ static int selectExpander(Walker *pWalker, Select *p){
** expanded. */
int tableSeen = 0; /* Set to 1 when TABLE matches */
char *zTName = 0; /* text of name of TABLE */
+ int iErrOfst;
if( pE->op==TK_DOT ){
+ assert( (selFlags & SF_NestedFrom)==0 );
assert( pE->pLeft!=0 );
assert( !ExprHasProperty(pE->pLeft, EP_IntValue) );
zTName = pE->pLeft->u.zToken;
+ assert( ExprUseWOfst(pE->pLeft) );
+ iErrOfst = pE->pRight->w.iOfst;
+ }else{
+ assert( ExprUseWOfst(pE) );
+ iErrOfst = pE->w.iOfst;
}
for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){
+ int nAdd; /* Number of cols including rowid */
Table *pTab = pFrom->pTab; /* Table for this data source */
ExprList *pNestedFrom; /* Result-set of a nested FROM clause */
char *zTabName; /* AS name for this data source */
@@ -145645,6 +148880,7 @@ static int selectExpander(Walker *pWalker, Select *p){
pNestedFrom = pFrom->pSelect->pEList;
assert( pNestedFrom!=0 );
assert( pNestedFrom->nExpr==pTab->nCol );
+ assert( VisibleRowid(pTab)==0 );
}else{
if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
continue;
@@ -145662,6 +148898,7 @@ static int selectExpander(Walker *pWalker, Select *p){
for(ii=0; iinId; ii++){
const char *zUName = pUsing->a[ii].zName;
pRight = sqlite3Expr(db, TK_ID, zUName);
+ sqlite3ExprSetErrorOffset(pRight, iErrOfst);
pNew = sqlite3ExprListAppend(pParse, pNew, pRight);
if( pNew ){
struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
@@ -145674,33 +148911,48 @@ static int selectExpander(Walker *pWalker, Select *p){
}else{
pUsing = 0;
}
- for(j=0; jnCol; j++){
- char *zName = pTab->aCol[j].zCnName;
+
+ nAdd = pTab->nCol + (VisibleRowid(pTab) && (selFlags&SF_NestedFrom));
+ for(j=0; ja[j], 0, zTName, 0)==0
- ){
- continue;
- }
+ if( j==pTab->nCol ){
+ zName = sqlite3RowidAlias(pTab);
+ if( zName==0 ) continue;
+ }else{
+ zName = pTab->aCol[j].zCnName;
- /* If a column is marked as 'hidden', omit it from the expanded
- ** result-set list unless the SELECT has the SF_IncludeHidden
- ** bit set.
- */
- if( (p->selFlags & SF_IncludeHidden)==0
- && IsHiddenColumn(&pTab->aCol[j])
- ){
- continue;
- }
- if( (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0
- && zTName==0
- && (selFlags & (SF_NestedFrom))==0
- ){
- continue;
+ /* If pTab is actually an SF_NestedFrom sub-select, do not
+ ** expand any ENAME_ROWID columns. */
+ if( pNestedFrom && pNestedFrom->a[j].fg.eEName==ENAME_ROWID ){
+ continue;
+ }
+
+ if( zTName
+ && pNestedFrom
+ && sqlite3MatchEName(&pNestedFrom->a[j], 0, zTName, 0, 0)==0
+ ){
+ continue;
+ }
+
+ /* If a column is marked as 'hidden', omit it from the expanded
+ ** result-set list unless the SELECT has the SF_IncludeHidden
+ ** bit set.
+ */
+ if( (p->selFlags & SF_IncludeHidden)==0
+ && IsHiddenColumn(&pTab->aCol[j])
+ ){
+ continue;
+ }
+ if( (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0
+ && zTName==0
+ && (selFlags & (SF_NestedFrom))==0
+ ){
+ continue;
+ }
}
+ assert( zName );
tableSeen = 1;
if( i>0 && zTName==0 && (selFlags & SF_NestedFrom)==0 ){
@@ -145734,6 +148986,7 @@ static int selectExpander(Walker *pWalker, Select *p){
}else{
pExpr = pRight;
}
+ sqlite3ExprSetErrorOffset(pExpr, iErrOfst);
pNew = sqlite3ExprListAppend(pParse, pNew, pExpr);
if( pNew==0 ){
break; /* OOM */
@@ -145749,11 +149002,11 @@ static int selectExpander(Walker *pWalker, Select *p){
zSchemaName, zTabName, zName);
testcase( pX->zEName==0 );
}
- pX->fg.eEName = ENAME_TAB;
+ pX->fg.eEName = (j==pTab->nCol ? ENAME_ROWID : ENAME_TAB);
if( (pFrom->fg.isUsing
&& sqlite3IdListIndex(pFrom->u3.pUsing, zName)>=0)
|| (pUsing && sqlite3IdListIndex(pUsing, zName)>=0)
- || (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0
+ || (jnCol && (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND))
){
pX->fg.bNoExpand = 1;
}
@@ -145974,8 +149227,14 @@ static void analyzeAggFuncArgs(
pNC->ncFlags |= NC_InAggFunc;
for(i=0; inFunc; i++){
Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
+ assert( pExpr->op==TK_FUNCTION || pExpr->op==TK_AGG_FUNCTION );
assert( ExprUseXList(pExpr) );
sqlite3ExprAnalyzeAggList(pNC, pExpr->x.pList);
+ if( pExpr->pLeft ){
+ assert( pExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pExpr->pLeft) );
+ sqlite3ExprAnalyzeAggList(pNC, pExpr->pLeft->x.pList);
+ }
#ifndef SQLITE_OMIT_WINDOWFUNC
assert( !IsWindowFunc(pExpr) );
if( ExprHasProperty(pExpr, EP_WinFunc) ){
@@ -146004,12 +149263,13 @@ static void optimizeAggregateUseOfIndexedExpr(
assert( pSelect->pGroupBy!=0 );
pAggInfo->nColumn = pAggInfo->nAccumulator;
if( ALWAYS(pAggInfo->nSortingColumn>0) ){
- if( pAggInfo->nColumn==0 ){
- pAggInfo->nSortingColumn = pSelect->pGroupBy->nExpr;
- }else{
- pAggInfo->nSortingColumn =
- pAggInfo->aCol[pAggInfo->nColumn-1].iSorterColumn+1;
+ int mx = pSelect->pGroupBy->nExpr - 1;
+ int j, k;
+ for(j=0; jnColumn; j++){
+ k = pAggInfo->aCol[j].iSorterColumn;
+ if( k>mx ) mx = k;
}
+ pAggInfo->nSortingColumn = mx+1;
}
analyzeAggFuncArgs(pAggInfo, pNC);
#if TREETRACE_ENABLED
@@ -146043,11 +149303,13 @@ static int aggregateIdxEprRefToColCallback(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_AGG_FUNCTION ) return WRC_Continue;
if( pExpr->op==TK_IF_NULL_ROW ) return WRC_Continue;
pAggInfo = pExpr->pAggInfo;
- assert( pExpr->iAgg>=0 && pExpr->iAggnColumn );
+ if( NEVER(pExpr->iAgg>=pAggInfo->nColumn) ) return WRC_Continue;
+ assert( pExpr->iAgg>=0 );
pCol = &pAggInfo->aCol[pExpr->iAgg];
pExpr->op = TK_AGG_COLUMN;
pExpr->iTable = pCol->iTable;
pExpr->iColumn = pCol->iColumn;
+ ExprClearProperty(pExpr, EP_Skip|EP_Collate|EP_Unlikely);
return WRC_Prune;
}
@@ -146078,7 +149340,7 @@ static void aggregateConvertIndexedExprRefToColumn(AggInfo *pAggInfo){
** * The aCol[] and aFunc[] arrays may be modified
** * The AggInfoColumnReg() and AggInfoFuncReg() macros may not be used
**
-** After clling this routine:
+** After calling this routine:
**
** * The aCol[] and aFunc[] arrays are fixed
** * The AggInfoColumnReg() and AggInfoFuncReg() macros may be used
@@ -146127,6 +149389,32 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
pFunc->pFunc->zName));
}
}
+ if( pFunc->iOBTab>=0 ){
+ ExprList *pOBList;
+ KeyInfo *pKeyInfo;
+ int nExtra = 0;
+ assert( pFunc->pFExpr->pLeft!=0 );
+ assert( pFunc->pFExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pFunc->pFExpr->pLeft) );
+ pOBList = pFunc->pFExpr->pLeft->x.pList;
+ if( !pFunc->bOBUnique ){
+ nExtra++; /* One extra column for the OP_Sequence */
+ }
+ if( pFunc->bOBPayload ){
+ /* extra columns for the function arguments */
+ assert( ExprUseXList(pFunc->pFExpr) );
+ nExtra += pFunc->pFExpr->x.pList->nExpr;
+ }
+ pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOBList, 0, nExtra);
+ if( !pFunc->bOBUnique && pParse->nErr==0 ){
+ pKeyInfo->nKeyField++;
+ }
+ sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
+ pFunc->iOBTab, pOBList->nExpr+nExtra, 0,
+ (char*)pKeyInfo, P4_KEYINFO);
+ ExplainQueryPlan((pParse, 0, "USE TEMP B-TREE FOR %s(ORDER BY)",
+ pFunc->pFunc->zName));
+ }
}
}
@@ -146142,13 +149430,46 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
ExprList *pList;
assert( ExprUseXList(pF->pFExpr) );
pList = pF->pFExpr->x.pList;
+ if( pF->iOBTab>=0 ){
+ /* For an ORDER BY aggregate, calls to OP_AggStep where deferred and
+ ** all content was stored in emphermal table pF->iOBTab. Extract that
+ ** content now (in ORDER BY order) and make all calls to OP_AggStep
+ ** before doing the OP_AggFinal call. */
+ int iTop; /* Start of loop for extracting columns */
+ int nArg; /* Number of columns to extract */
+ int nKey; /* Key columns to be skipped */
+ int regAgg; /* Extract into this array */
+ int j; /* Loop counter */
+
+ nArg = pList->nExpr;
+ regAgg = sqlite3GetTempRange(pParse, nArg);
+
+ if( pF->bOBPayload==0 ){
+ nKey = 0;
+ }else{
+ assert( pF->pFExpr->pLeft!=0 );
+ assert( ExprUseXList(pF->pFExpr->pLeft) );
+ assert( pF->pFExpr->pLeft->x.pList!=0 );
+ nKey = pF->pFExpr->pLeft->x.pList->nExpr;
+ if( ALWAYS(!pF->bOBUnique) ) nKey++;
+ }
+ iTop = sqlite3VdbeAddOp1(v, OP_Rewind, pF->iOBTab); VdbeCoverage(v);
+ for(j=nArg-1; j>=0; j--){
+ sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, nKey+j, regAgg+j);
+ }
+ sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i));
+ sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
+ sqlite3VdbeChangeP5(v, (u8)nArg);
+ sqlite3VdbeAddOp2(v, OP_Next, pF->iOBTab, iTop+1); VdbeCoverage(v);
+ sqlite3VdbeJumpHere(v, iTop);
+ sqlite3ReleaseTempRange(pParse, regAgg, nArg);
+ }
sqlite3VdbeAddOp2(v, OP_AggFinal, AggInfoFuncReg(pAggInfo,i),
pList ? pList->nExpr : 0);
sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
}
}
-
/*
** Generate code that will update the accumulator memory cells for an
** aggregate based on the current cursor position.
@@ -146157,6 +149478,13 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
** in pAggInfo, then only populate the pAggInfo->nAccumulator accumulator
** registers if register regAcc contains 0. The caller will take care
** of setting and clearing regAcc.
+**
+** For an ORDER BY aggregate, the actual accumulator memory cell update
+** is deferred until after all input rows have been received, so that they
+** can be run in the requested order. In that case, instead of invoking
+** OP_AggStep to update the accumulator, just add the arguments that would
+** have been passed into OP_AggStep into the sorting ephemeral table
+** (along with the appropriate sort key).
*/
static void updateAccumulator(
Parse *pParse,
@@ -146178,6 +149506,8 @@ static void updateAccumulator(
int nArg;
int addrNext = 0;
int regAgg;
+ int regAggSz = 0;
+ int regDistinct = 0;
ExprList *pList;
assert( ExprUseXList(pF->pFExpr) );
assert( !IsWindowFunc(pF->pFExpr) );
@@ -146204,9 +149534,44 @@ static void updateAccumulator(
addrNext = sqlite3VdbeMakeLabel(pParse);
sqlite3ExprIfFalse(pParse, pFilter, addrNext, SQLITE_JUMPIFNULL);
}
- if( pList ){
+ if( pF->iOBTab>=0 ){
+ /* Instead of invoking AggStep, we must push the arguments that would
+ ** have been passed to AggStep onto the sorting table. */
+ int jj; /* Registered used so far in building the record */
+ ExprList *pOBList; /* The ORDER BY clause */
+ assert( pList!=0 );
+ nArg = pList->nExpr;
+ assert( nArg>0 );
+ assert( pF->pFExpr->pLeft!=0 );
+ assert( pF->pFExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pF->pFExpr->pLeft) );
+ pOBList = pF->pFExpr->pLeft->x.pList;
+ assert( pOBList!=0 );
+ assert( pOBList->nExpr>0 );
+ regAggSz = pOBList->nExpr;
+ if( !pF->bOBUnique ){
+ regAggSz++; /* One register for OP_Sequence */
+ }
+ if( pF->bOBPayload ){
+ regAggSz += nArg;
+ }
+ regAggSz++; /* One extra register to hold result of MakeRecord */
+ regAgg = sqlite3GetTempRange(pParse, regAggSz);
+ regDistinct = regAgg;
+ sqlite3ExprCodeExprList(pParse, pOBList, regAgg, 0, SQLITE_ECEL_DUP);
+ jj = pOBList->nExpr;
+ if( !pF->bOBUnique ){
+ sqlite3VdbeAddOp2(v, OP_Sequence, pF->iOBTab, regAgg+jj);
+ jj++;
+ }
+ if( pF->bOBPayload ){
+ regDistinct = regAgg+jj;
+ sqlite3ExprCodeExprList(pParse, pList, regDistinct, 0, SQLITE_ECEL_DUP);
+ }
+ }else if( pList ){
nArg = pList->nExpr;
regAgg = sqlite3GetTempRange(pParse, nArg);
+ regDistinct = regAgg;
sqlite3ExprCodeExprList(pParse, pList, regAgg, 0, SQLITE_ECEL_DUP);
}else{
nArg = 0;
@@ -146217,26 +149582,37 @@ static void updateAccumulator(
addrNext = sqlite3VdbeMakeLabel(pParse);
}
pF->iDistinct = codeDistinct(pParse, eDistinctType,
- pF->iDistinct, addrNext, pList, regAgg);
- }
- if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
- CollSeq *pColl = 0;
- struct ExprList_item *pItem;
- int j;
- assert( pList!=0 ); /* pList!=0 if pF->pFunc has NEEDCOLL */
- for(j=0, pItem=pList->a; !pColl && jpExpr);
- }
- if( !pColl ){
- pColl = pParse->db->pDfltColl;
+ pF->iDistinct, addrNext, pList, regDistinct);
+ }
+ if( pF->iOBTab>=0 ){
+ /* Insert a new record into the ORDER BY table */
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regAgg, regAggSz-1,
+ regAgg+regAggSz-1);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pF->iOBTab, regAgg+regAggSz-1,
+ regAgg, regAggSz-1);
+ sqlite3ReleaseTempRange(pParse, regAgg, regAggSz);
+ }else{
+ /* Invoke the AggStep function */
+ if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
+ CollSeq *pColl = 0;
+ struct ExprList_item *pItem;
+ int j;
+ assert( pList!=0 ); /* pList!=0 if pF->pFunc has NEEDCOLL */
+ for(j=0, pItem=pList->a; !pColl && jpExpr);
+ }
+ if( !pColl ){
+ pColl = pParse->db->pDfltColl;
+ }
+ if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
+ sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0,
+ (char *)pColl, P4_COLLSEQ);
}
- if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
- sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ);
+ sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i));
+ sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
+ sqlite3VdbeChangeP5(v, (u8)nArg);
+ sqlite3ReleaseTempRange(pParse, regAgg, nArg);
}
- sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i));
- sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
- sqlite3VdbeChangeP5(v, (u8)nArg);
- sqlite3ReleaseTempRange(pParse, regAgg, nArg);
if( addrNext ){
sqlite3VdbeResolveLabel(v, addrNext);
}
@@ -146428,6 +149804,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */
if( p->pEList->nExpr!=1 ) return 0; /* Single result column */
if( p->pWhere ) return 0;
+ if( p->pHaving ) return 0;
if( p->pGroupBy ) return 0;
if( p->pOrderBy ) return 0;
pExpr = p->pEList->a[0].pExpr;
@@ -146447,7 +149824,8 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
if( pSub->pWhere ) return 0; /* No WHERE clause */
if( pSub->pLimit ) return 0; /* No LIMIT clause */
if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */
- pSub = pSub->pPrior; /* Repeat over compound */
+ assert( pSub->pHaving==0 ); /* Due to the previous */
+ pSub = pSub->pPrior; /* Repeat over compound */
}while( pSub );
/* If we reach this point then it is OK to perform the transformation */
@@ -146730,22 +150108,59 @@ SQLITE_PRIVATE int sqlite3Select(
** to a real table */
assert( pTab!=0 );
- /* Convert LEFT JOIN into JOIN if there are terms of the right table
- ** of the LEFT JOIN used in the WHERE clause.
+ /* Try to simplify joins:
+ **
+ ** LEFT JOIN -> JOIN
+ ** RIGHT JOIN -> JOIN
+ ** FULL JOIN -> RIGHT JOIN
+ **
+ ** If terms of the i-th table are used in the WHERE clause in such a
+ ** way that the i-th table cannot be the NULL row of a join, then
+ ** perform the appropriate simplification. This is called
+ ** "OUTER JOIN strength reduction" in the SQLite documentation.
*/
- if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==JT_LEFT
- && sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor)
+ if( (pItem->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
+ && sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor,
+ pItem->fg.jointype & JT_LTORJ)
&& OptimizationEnabled(db, SQLITE_SimplifyJoin)
){
- TREETRACE(0x1000,pParse,p,
- ("LEFT-JOIN simplifies to JOIN on term %d\n",i));
- pItem->fg.jointype &= ~(JT_LEFT|JT_OUTER);
+ if( pItem->fg.jointype & JT_LEFT ){
+ if( pItem->fg.jointype & JT_RIGHT ){
+ TREETRACE(0x1000,pParse,p,
+ ("FULL-JOIN simplifies to RIGHT-JOIN on term %d\n",i));
+ pItem->fg.jointype &= ~JT_LEFT;
+ }else{
+ TREETRACE(0x1000,pParse,p,
+ ("LEFT-JOIN simplifies to JOIN on term %d\n",i));
+ pItem->fg.jointype &= ~(JT_LEFT|JT_OUTER);
+ }
+ }
+ if( pItem->fg.jointype & JT_LTORJ ){
+ for(j=i+1; jnSrc; j++){
+ SrcItem *pI2 = &pTabList->a[j];
+ if( pI2->fg.jointype & JT_RIGHT ){
+ if( pI2->fg.jointype & JT_LEFT ){
+ TREETRACE(0x1000,pParse,p,
+ ("FULL-JOIN simplifies to LEFT-JOIN on term %d\n",j));
+ pI2->fg.jointype &= ~JT_RIGHT;
+ }else{
+ TREETRACE(0x1000,pParse,p,
+ ("RIGHT-JOIN simplifies to JOIN on term %d\n",j));
+ pI2->fg.jointype &= ~(JT_RIGHT|JT_OUTER);
+ }
+ }
+ }
+ for(j=pTabList->nSrc-1; j>=i; j--){
+ pTabList->a[j].fg.jointype &= ~JT_LTORJ;
+ if( pTabList->a[j].fg.jointype & JT_RIGHT ) break;
+ }
+ }
assert( pItem->iCursor>=0 );
unsetJoinExpr(p->pWhere, pItem->iCursor,
pTabList->a[0].fg.jointype & JT_LTORJ);
}
- /* No futher action if this term of the FROM clause is no a subquery */
+ /* No further action if this term of the FROM clause is not a subquery */
if( pSub==0 ) continue;
/* Catch mismatch in the declared columns of a view and the number of
@@ -146756,6 +150171,14 @@ SQLITE_PRIVATE int sqlite3Select(
goto select_end;
}
+ /* Do not attempt the usual optimizations (flattening and ORDER BY
+ ** elimination) on a MATERIALIZED common table expression because
+ ** a MATERIALIZED common table expression is an optimization fence.
+ */
+ if( pItem->fg.isCte && pItem->u2.pCteUse->eM10d==M10d_Yes ){
+ continue;
+ }
+
/* Do not try to flatten an aggregate subquery.
**
** Flattening an aggregate subquery is only possible if the outer query
@@ -146785,6 +150208,8 @@ SQLITE_PRIVATE int sqlite3Select(
** (a) The outer query has a different ORDER BY clause
** (b) The subquery is part of a join
** See forum post 062d576715d277c8
+ **
+ ** Also retain the ORDER BY if the OmitOrderBy optimization is disabled.
*/
if( pSub->pOrderBy!=0
&& (p->pOrderBy!=0 || pTabList->nSrc>1) /* Condition (5) */
@@ -146942,7 +150367,7 @@ SQLITE_PRIVATE int sqlite3Select(
if( OptimizationEnabled(db, SQLITE_PushDown)
&& (pItem->fg.isCte==0
|| (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2))
- && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem)
+ && pushDownWhereTerms(pParse, pSub, p->pWhere, pTabList, i)
){
#if TREETRACE_ENABLED
if( sqlite3TreeTrace & 0x4000 ){
@@ -146999,7 +150424,7 @@ SQLITE_PRIVATE int sqlite3Select(
}else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){
/* This is a CTE for which materialization code has already been
** generated. Invoke the subroutine to compute the materialization,
- ** the make the pItem->iCursor be a copy of the ephemerial table that
+ ** the make the pItem->iCursor be a copy of the ephemeral table that
** holds the result of the materialization. */
CteUse *pCteUse = pItem->u2.pCteUse;
sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e);
@@ -147382,7 +150807,7 @@ SQLITE_PRIVATE int sqlite3Select(
*/
if( pGroupBy ){
KeyInfo *pKeyInfo; /* Keying information for the group by clause */
- int addr1; /* A-vs-B comparision jump */
+ int addr1; /* A-vs-B comparison jump */
int addrOutputRow; /* Start of subroutine that outputs a result row */
int regOutputRow; /* Return address register for output subroutine */
int addrSetAbort; /* Set the abort flag and return */
@@ -147473,9 +150898,13 @@ SQLITE_PRIVATE int sqlite3Select(
int nCol;
int nGroupBy;
- explainTempTable(pParse,
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ int addrExp; /* Address of OP_Explain instruction */
+#endif
+ ExplainQueryPlan2(addrExp, (pParse, 0, "USE TEMP B-TREE FOR %s",
(sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ?
- "DISTINCT" : "GROUP BY");
+ "DISTINCT" : "GROUP BY"
+ ));
groupBySort = 1;
nGroupBy = pGroupBy->nExpr;
@@ -147500,18 +150929,23 @@ SQLITE_PRIVATE int sqlite3Select(
}
pAggInfo->directMode = 0;
regRecord = sqlite3GetTempReg(pParse);
+ sqlite3VdbeScanStatusCounters(v, addrExp, 0, sqlite3VdbeCurrentAddr(v));
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord);
+ sqlite3VdbeScanStatusRange(v, addrExp, sqlite3VdbeCurrentAddr(v)-2, -1);
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3ReleaseTempRange(pParse, regBase, nCol);
TREETRACE(0x2,pParse,p,("WhereEnd\n"));
sqlite3WhereEnd(pWInfo);
pAggInfo->sortingIdxPTab = sortPTab = pParse->nTab++;
sortOut = sqlite3GetTempReg(pParse);
+ sqlite3VdbeScanStatusCounters(v, addrExp, sqlite3VdbeCurrentAddr(v), 0);
sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol);
sqlite3VdbeAddOp2(v, OP_SorterSort, pAggInfo->sortingIdx, addrEnd);
VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v);
pAggInfo->useSortingIdx = 1;
+ sqlite3VdbeScanStatusRange(v, addrExp, -1, sortPTab);
+ sqlite3VdbeScanStatusRange(v, addrExp, -1, pAggInfo->sortingIdx);
}
/* If there are entries in pAgggInfo->aFunc[] that contain subexpressions
@@ -148239,6 +151673,10 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables");
goto trigger_orphan_error;
}
+ if( (pTab->tabFlags & TF_Shadow)!=0 && sqlite3ReadOnlyShadowTables(db) ){
+ sqlite3ErrorMsg(pParse, "cannot create triggers on shadow tables");
+ goto trigger_orphan_error;
+ }
/* Check that the trigger name is not reserved and that no trigger of the
** specified name exists */
@@ -148258,6 +151696,7 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
}else{
assert( !db->init.busy );
sqlite3CodeVerifySchema(pParse, iDb);
+ VVA_ONLY( pParse->ifNotExists = 1; )
}
goto trigger_cleanup;
}
@@ -149021,10 +152460,17 @@ static void codeReturningTrigger(
SrcList sFrom;
assert( v!=0 );
- assert( pParse->bReturning );
+ if( !pParse->bReturning ){
+ /* This RETURNING trigger must be for a different statement as
+ ** this statement lacks a RETURNING clause. */
+ return;
+ }
assert( db->pParse==pParse );
pReturning = pParse->u1.pReturning;
- assert( pTrigger == &(pReturning->retTrig) );
+ if( pTrigger != &(pReturning->retTrig) ){
+ /* This RETURNING trigger is for a different statement */
+ return;
+ }
memset(&sSelect, 0, sizeof(sSelect));
memset(&sFrom, 0, sizeof(sFrom));
sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0);
@@ -149508,6 +152954,9 @@ SQLITE_PRIVATE u32 sqlite3TriggerColmask(
Trigger *p;
assert( isNew==1 || isNew==0 );
+ if( IsView(pTab) ){
+ return 0xffffffff;
+ }
for(p=pTrigger; p; p=p->pNext){
if( p->op==op
&& (tr_tm&p->tr_tm)
@@ -149758,7 +153207,7 @@ static void updateFromSelect(
assert( pTabList->nSrc>1 );
if( pSrc ){
- pSrc->a[0].fg.notCte = 1;
+ assert( pSrc->a[0].fg.notCte );
pSrc->a[0].iCursor = -1;
pSrc->a[0].pTab->nTabRef--;
pSrc->a[0].pTab = 0;
@@ -149942,7 +153391,7 @@ SQLITE_PRIVATE void sqlite3Update(
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto update_cleanup;
}
- if( sqlite3IsReadOnly(pParse, pTab, tmask) ){
+ if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
goto update_cleanup;
}
@@ -150261,12 +153710,22 @@ SQLITE_PRIVATE void sqlite3Update(
/* Begin the database scan.
**
** Do not consider a single-pass strategy for a multi-row update if
- ** there are any triggers or foreign keys to process, or rows may
- ** be deleted as a result of REPLACE conflict handling. Any of these
- ** things might disturb a cursor being used to scan through the table
- ** or index, causing a single-pass approach to malfunction. */
+ ** there is anything that might disrupt the cursor being used to do
+ ** the UPDATE:
+ ** (1) This is a nested UPDATE
+ ** (2) There are triggers
+ ** (3) There are FOREIGN KEY constraints
+ ** (4) There are REPLACE conflict handlers
+ ** (5) There are subqueries in the WHERE clause
+ */
flags = WHERE_ONEPASS_DESIRED;
- if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
+ if( !pParse->nested
+ && !pTrigger
+ && !hasFK
+ && !chngKey
+ && !bReplace
+ && (pWhere==0 || !ExprHasProperty(pWhere, EP_Subquery))
+ ){
flags |= WHERE_ONEPASS_MULTIROW;
}
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,0,0,flags,iIdxCur);
@@ -150337,6 +153796,8 @@ SQLITE_PRIVATE void sqlite3Update(
if( !isView ){
int addrOnce = 0;
+ int iNotUsed1 = 0;
+ int iNotUsed2 = 0;
/* Open every index that needs updating. */
if( eOnePass!=ONEPASS_OFF ){
@@ -150348,7 +153809,7 @@ SQLITE_PRIVATE void sqlite3Update(
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur,
- aToOpen, 0, 0);
+ aToOpen, &iNotUsed1, &iNotUsed2);
if( addrOnce ){
sqlite3VdbeJumpHereOrPopInst(v, addrOnce);
}
@@ -150639,8 +154100,10 @@ SQLITE_PRIVATE void sqlite3Update(
sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
}
- sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
- TRIGGER_AFTER, pTab, regOldRowid, onError, labelContinue);
+ if( pTrigger ){
+ sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
+ TRIGGER_AFTER, pTab, regOldRowid, onError, labelContinue);
+ }
/* Repeat the above with the next record to be updated, until
** all record selected by the WHERE clause have been updated.
@@ -150735,7 +154198,7 @@ static void updateVirtualTable(
int nArg = 2 + pTab->nCol; /* Number of arguments to VUpdate */
int regArg; /* First register in VUpdate arg array */
int regRec; /* Register in which to assemble record */
- int regRowid; /* Register for ephem table rowid */
+ int regRowid; /* Register for ephemeral table rowid */
int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */
int aDummy[2]; /* Unused arg for sqlite3WhereOkOnePass() */
int eOnePass; /* True to use onepass strategy */
@@ -150779,7 +154242,9 @@ static void updateVirtualTable(
sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0)
);
}else{
- pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i));
+ Expr *pRowExpr = exprRowColumn(pParse, i);
+ if( pRowExpr ) pRowExpr->op2 = OPFLAG_NOCHNG;
+ pList = sqlite3ExprListAppend(pParse, pList, pRowExpr);
}
}
@@ -150856,7 +154321,7 @@ static void updateVirtualTable(
sqlite3WhereEnd(pWInfo);
}
- /* Begin scannning through the ephemeral table. */
+ /* Begin scanning through the ephemeral table. */
addr = sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v);
/* Extract arguments from the current row of the ephemeral table and
@@ -151064,7 +154529,7 @@ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(
pExpr = &sCol[0];
}
for(jj=0; jja[jj].pExpr,pExpr,iCursor)<2 ){
+ if( sqlite3ExprCompare(0,pTarget->a[jj].pExpr,pExpr,iCursor)<2 ){
break; /* Column ii of the index matches column jj of target */
}
}
@@ -151413,7 +154878,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
** (possibly synchronous) transaction opened on the main database before
** sqlite3BtreeCopyFile() is called.
**
- ** An optimisation would be to use a non-journaled pager.
+ ** An optimization would be to use a non-journaled pager.
** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but
** that actually made the VACUUM run slower. Very little journalling
** actually occurs when doing a vacuum since the vacuum_db is initially
@@ -151658,11 +155123,11 @@ struct VtabCtx {
** If pModule==0, then delete the module zName if it exists.
*/
SQLITE_PRIVATE Module *sqlite3VtabCreateModule(
- sqlite3 *db, /* Database in which module is registered */
- const char *zName, /* Name assigned to this module */
- const sqlite3_module *pModule, /* The definition of the module */
- void *pAux, /* Context pointer for xCreate/xConnect */
- void (*xDestroy)(void *) /* Module destructor function */
+ sqlite3 *db, /* Database in which module is registered */
+ const char *zName, /* Name assigned to this module */
+ const sqlite3_module *pModule, /* The definition of the module */
+ void *pAux, /* Context pointer for xCreate/xConnect */
+ void (*xDestroy)(void *) /* Module destructor function */
){
Module *pMod;
Module *pDel;
@@ -151706,11 +155171,11 @@ SQLITE_PRIVATE Module *sqlite3VtabCreateModule(
** sqlite3_create_module_v2() interfaces.
*/
static int createModule(
- sqlite3 *db, /* Database in which module is registered */
- const char *zName, /* Name assigned to this module */
- const sqlite3_module *pModule, /* The definition of the module */
- void *pAux, /* Context pointer for xCreate/xConnect */
- void (*xDestroy)(void *) /* Module destructor function */
+ sqlite3 *db, /* Database in which module is registered */
+ const char *zName, /* Name assigned to this module */
+ const sqlite3_module *pModule, /* The definition of the module */
+ void *pAux, /* Context pointer for xCreate/xConnect */
+ void (*xDestroy)(void *) /* Module destructor function */
){
int rc = SQLITE_OK;
@@ -151744,7 +155209,7 @@ SQLITE_API int sqlite3_create_module(
SQLITE_API int sqlite3_create_module_v2(
sqlite3 *db, /* Database in which module is registered */
const char *zName, /* Name assigned to this module */
- const sqlite3_module *pModule, /* The definition of the module */
+ const sqlite3_module *pModule, /* The definition of the libSQL module */
void *pAux, /* Context pointer for xCreate/xConnect */
void (*xDestroy)(void *) /* Module destructor function */
){
@@ -152102,7 +155567,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
** the information we've collected.
**
** The VM register number pParse->regRowid holds the rowid of an
- ** entry in the sqlite_schema table tht was created for this vtab
+ ** entry in the sqlite_schema table that was created for this vtab
** by sqlite3StartTable().
*/
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -152231,7 +155696,9 @@ static int vtabCallConstructor(
sCtx.pPrior = db->pVtabCtx;
sCtx.bDeclared = 0;
db->pVtabCtx = &sCtx;
+ pTab->nTabRef++;
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
+ sqlite3DeleteTable(db, pTab);
db->pVtabCtx = sCtx.pPrior;
if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
assert( sCtx.pTab==pTab );
@@ -152440,7 +155907,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
sqlite3_mutex_enter(db->mutex);
pCtx = db->pVtabCtx;
if( !pCtx || pCtx->bDeclared ){
- sqlite3Error(db, SQLITE_MISUSE);
+ sqlite3Error(db, SQLITE_MISUSE_BKPT);
sqlite3_mutex_leave(db->mutex);
return SQLITE_MISUSE_BKPT;
}
@@ -152721,7 +156188,10 @@ SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){
break;
}
if( xMethod && pVTab->iSavepoint>iSavepoint ){
+ u64 savedFlags = (db->flags & SQLITE_Defensive);
+ db->flags &= ~(u64)SQLITE_Defensive;
rc = xMethod(pVTab->pVtab, iSavepoint);
+ db->flags |= savedFlags;
}
sqlite3VtabUnlock(pVTab);
}
@@ -152841,7 +156311,7 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
**
** An eponymous virtual table instance is one that is named after its
** module, and more importantly, does not require a CREATE VIRTUAL TABLE
-** statement in order to come into existance. Eponymous virtual table
+** statement in order to come into existence. Eponymous virtual table
** instances always exist. They cannot be DROP-ed.
**
** Any virtual table module for which xConnect and xCreate are the same
@@ -152950,6 +156420,10 @@ SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){
p->pVTable->eVtabRisk = SQLITE_VTABRISK_High;
break;
}
+ case SQLITE_VTAB_USES_ALL_SCHEMAS: {
+ p->pVTable->bAllSchemas = 1;
+ break;
+ }
default: {
rc = SQLITE_MISUSE_BKPT;
break;
@@ -153028,7 +156502,7 @@ typedef struct WhereRightJoin WhereRightJoin;
/*
** This object is a header on a block of allocated memory that will be
-** automatically freed when its WInfo oject is destructed.
+** automatically freed when its WInfo object is destructed.
*/
struct WhereMemBlock {
WhereMemBlock *pNext; /* Next block in the chain */
@@ -153089,7 +156563,7 @@ struct WhereLevel {
int iCur; /* The VDBE cursor used by this IN operator */
int addrInTop; /* Top of the IN loop */
int iBase; /* Base register of multi-key index record */
- int nPrefix; /* Number of prior entires in the key */
+ int nPrefix; /* Number of prior entries in the key */
u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */
} *aInLoop; /* Information about each nested IN operator */
} in; /* Used when pWLoop->wsFlags&WHERE_IN_ABLE */
@@ -153339,7 +156813,7 @@ struct WhereClause {
int nTerm; /* Number of terms */
int nSlot; /* Number of entries in a[] */
int nBase; /* Number of terms through the last non-Virtual */
- WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */
+ WhereTerm *a; /* Each a[] describes a term of the WHERE clause */
#if defined(SQLITE_SMALL_STACK)
WhereTerm aStatic[1]; /* Initial static space for a[] */
#else
@@ -153624,7 +157098,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*);
#define WHERE_BLOOMFILTER 0x00400000 /* Consider using a Bloom-filter */
#define WHERE_SELFCULL 0x00800000 /* nOut reduced by extra WHERE terms */
#define WHERE_OMIT_OFFSET 0x01000000 /* Set offset counter to zero */
-#define WHERE_VIEWSCAN 0x02000000 /* A full-scan of a VIEW or subquery */
+ /* 0x02000000 -- available for reuse */
#define WHERE_EXPRIDX 0x04000000 /* Uses an index-on-expressions */
#endif /* !defined(SQLITE_WHEREINT_H) */
@@ -153927,6 +157401,12 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
if( wsFlags & WHERE_INDEXED ){
sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
}
+ }else{
+ int addr = pSrclist->a[pLvl->iFrom].addrFillSub;
+ VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1);
+ assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine );
+ assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr );
+ sqlite3VdbeScanStatusRange(v, addrExplain, addr, pOp->p2-1);
}
}
}
@@ -154424,7 +157904,7 @@ static int codeAllEqualityTerms(
/* Figure out how many memory cells we will need then allocate them.
*/
regBase = pParse->nMem + 1;
- nReg = pLoop->u.btree.nEq + nExtraReg;
+ nReg = nEq + nExtraReg;
pParse->nMem += nReg;
zAff = sqlite3DbStrDup(pParse->db,sqlite3IndexAffinityStr(pParse->db,pIdx));
@@ -154471,9 +157951,6 @@ static int codeAllEqualityTerms(
sqlite3VdbeAddOp2(v, OP_Copy, r1, regBase+j);
}
}
- }
- for(j=nSkip; jaLTerm[j];
if( pTerm->eOperator & WO_IN ){
if( pTerm->pExpr->flags & EP_xIsSelect ){
/* No affinity ever needs to be (or should be) applied to a value
@@ -154616,18 +158093,19 @@ static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
** 2) transform the expression node to a TK_REGISTER node that reads
** from the newly populated register.
**
-** Also, if the node is a TK_COLUMN that does access the table idenified
+** Also, if the node is a TK_COLUMN that does access the table identified
** by pCCurHint.iTabCur, and an index is being used (which we will
** know because CCurHint.pIdx!=0) then transform the TK_COLUMN into
** an access of the index rather than the original table.
*/
static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
int rc = WRC_Continue;
+ int reg;
struct CCurHint *pHint = pWalker->u.pCCurHint;
if( pExpr->op==TK_COLUMN ){
if( pExpr->iTable!=pHint->iTabCur ){
- int reg = ++pWalker->pParse->nMem; /* Register for column value */
- sqlite3ExprCode(pWalker->pParse, pExpr, reg);
+ reg = ++pWalker->pParse->nMem; /* Register for column value */
+ reg = sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg);
pExpr->op = TK_REGISTER;
pExpr->iTable = reg;
}else if( pHint->pIdx!=0 ){
@@ -154635,15 +158113,15 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
pExpr->iColumn = sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn);
assert( pExpr->iColumn>=0 );
}
- }else if( pExpr->op==TK_AGG_FUNCTION ){
- /* An aggregate function in the WHERE clause of a query means this must
- ** be a correlated sub-query, and expression pExpr is an aggregate from
- ** the parent context. Do not walk the function arguments in this case.
- **
- ** todo: It should be possible to replace this node with a TK_REGISTER
- ** expression, as the result of the expression must be stored in a
- ** register at this point. The same holds for TK_AGG_COLUMN nodes. */
+ }else if( pExpr->pAggInfo ){
rc = WRC_Prune;
+ reg = ++pWalker->pParse->nMem; /* Register for column value */
+ reg = sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg);
+ pExpr->op = TK_REGISTER;
+ pExpr->iTable = reg;
+ }else if( pExpr->op==TK_TRUEFALSE ){
+ /* Do not walk disabled expressions. tag-20230504-1 */
+ return WRC_Prune;
}
return rc;
}
@@ -154745,7 +158223,7 @@ static void codeCursorHint(
}
if( pExpr!=0 ){
sWalker.xExprCallback = codeCursorHintFixExpr;
- sqlite3WalkExpr(&sWalker, pExpr);
+ if( pParse->nErr==0 ) sqlite3WalkExpr(&sWalker, pExpr);
sqlite3VdbeAddOp4(v, OP_CursorHint,
(sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0,
(const char*)pExpr, P4_EXPR);
@@ -155235,7 +158713,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
};
assert( TK_LE==TK_GT+1 ); /* Make sure the ordering.. */
assert( TK_LT==TK_GT+2 ); /* ... of the TK_xx values... */
- assert( TK_GE==TK_GT+3 ); /* ... is correcct. */
+ assert( TK_GE==TK_GT+3 ); /* ... is correct. */
assert( (pStart->wtFlags & TERM_VNULL)==0 );
testcase( pStart->wtFlags & TERM_VIRTUAL );
@@ -155541,7 +159019,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
** guess. */
addrSeekScan = sqlite3VdbeAddOp1(v, OP_SeekScan,
(pIdx->aiRowLogEst[0]+9)/10);
- if( pRangeStart ){
+ if( pRangeStart || pRangeEnd ){
sqlite3VdbeChangeP5(v, 1);
sqlite3VdbeChangeP2(v, addrSeekScan, sqlite3VdbeCurrentAddr(v)+1);
addrSeekScan = 0;
@@ -155582,16 +159060,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
assert( pLevel->p2==0 );
if( pRangeEnd ){
Expr *pRight = pRangeEnd->pExpr->pRight;
- if( addrSeekScan ){
- /* For a seek-scan that has a range on the lowest term of the index,
- ** we have to make the top of the loop be code that sets the end
- ** condition of the range. Otherwise, the OP_SeekScan might jump
- ** over that initialization, leaving the range-end value set to the
- ** range-start value, resulting in a wrong answer.
- ** See ticket 5981a8c041a3c2f3 (2021-11-02).
- */
- pLevel->p2 = sqlite3VdbeCurrentAddr(v);
- }
+ assert( addrSeekScan==0 );
codeExprOrVector(pParse, pRight, regBase+nEq, nTop);
whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
if( (pRangeEnd->wtFlags & TERM_VNULL)==0
@@ -155625,7 +159094,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
if( zEndAff ) sqlite3DbNNFreeNN(db, zEndAff);
/* Top of the loop body */
- if( pLevel->p2==0 ) pLevel->p2 = sqlite3VdbeCurrentAddr(v);
+ pLevel->p2 = sqlite3VdbeCurrentAddr(v);
/* Check if the index cursor is past the end of the range. */
if( nConstraint ){
@@ -156424,7 +159893,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
** the WHERE clause of SQL statements.
**
** This file was originally part of where.c but was split out to improve
-** readability and editabiliity. This file contains utility routines for
+** readability and editability. This file contains utility routines for
** analyzing Expr objects in the WHERE clause.
*/
/* #include "sqliteInt.h" */
@@ -156640,7 +160109,7 @@ static int isLikeOrGlob(
** range search. The third is because the caller assumes that the pattern
** consists of at least one character after all escapes have been
** removed. */
- if( cnt!=0 && 255!=(u8)z[cnt-1] && (cnt>1 || z[0]!=wc[3]) ){
+ if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && 255!=(u8)z[cnt-1] ){
Expr *pPrefix;
/* A "complete" match if the pattern ends with "*" or "%" */
@@ -157213,7 +160682,7 @@ static void exprAnalyzeOrTerm(
pOrTerm->leftCursor))==0 ){
/* This term must be of the form t1.a==t2.b where t2 is in the
** chngToIN set but t1 is not. This term will be either preceded
- ** or follwed by an inverted copy (t2.b==t1.a). Skip this term
+ ** or followed by an inverted copy (t2.b==t1.a). Skip this term
** and use its inversion. */
testcase( pOrTerm->wtFlags & TERM_COPIED );
testcase( pOrTerm->wtFlags & TERM_VIRTUAL );
@@ -157475,8 +160944,8 @@ static void exprAnalyze(
WhereTerm *pTerm; /* The term to be analyzed */
WhereMaskSet *pMaskSet; /* Set of table index masks */
Expr *pExpr; /* The expression to be analyzed */
- Bitmask prereqLeft; /* Prerequesites of the pExpr->pLeft */
- Bitmask prereqAll; /* Prerequesites of pExpr */
+ Bitmask prereqLeft; /* Prerequisites of the pExpr->pLeft */
+ Bitmask prereqAll; /* Prerequisites of pExpr */
Bitmask extraRight = 0; /* Extra dependencies on LEFT JOIN */
Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */
int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */
@@ -157622,7 +161091,7 @@ static void exprAnalyze(
&& 0==sqlite3ExprCanBeNull(pLeft)
){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
- pExpr->op = TK_TRUEFALSE;
+ pExpr->op = TK_TRUEFALSE; /* See tag-20230504-1 */
pExpr->u.zToken = "false";
ExprSetProperty(pExpr, EP_IsFalse);
pTerm->prereqAll = 0;
@@ -159154,8 +162623,7 @@ static void explainAutomaticIndex(
*/
static SQLITE_NOINLINE void constructAutomaticIndex(
Parse *pParse, /* The parsing context */
- const WhereClause *pWC, /* The WHERE clause */
- const SrcItem *pSrc, /* The FROM clause term to get the next index */
+ WhereClause *pWC, /* The WHERE clause */
const Bitmask notReady, /* Mask of cursors that are not available */
WhereLevel *pLevel /* Write new index here */
){
@@ -159180,7 +162648,8 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
u8 useBloomFilter = 0; /* True to also add a Bloom filter */
Expr *pPartial = 0; /* Partial Index Expression */
int iContinue = 0; /* Jump here to skip excluded rows */
- SrcItem *pTabItem; /* FROM clause term being indexed */
+ SrcList *pTabList; /* The complete FROM clause */
+ SrcItem *pSrc; /* The FROM clause term to get the next index */
int addrCounter = 0; /* Address where integer counter is initialized */
int regBase; /* Array of registers where record is assembled */
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
@@ -159196,6 +162665,8 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
/* Count the number of columns that will be added to the index
** and used to match WHERE clause constraints */
nKeyCol = 0;
+ pTabList = pWC->pWInfo->pTabList;
+ pSrc = &pTabList->a[pLevel->iFrom];
pTable = pSrc->pTab;
pWCEnd = &pWC->a[pWC->nTerm];
pLoop = pLevel->pWLoop;
@@ -159206,7 +162677,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
** WHERE clause (or the ON clause of a LEFT join) that constrain which
** rows of the target table (pSrc) that can be used. */
if( (pTerm->wtFlags & TERM_VIRTUAL)==0
- && sqlite3ExprIsTableConstraint(pExpr, pSrc)
+ && sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, pLevel->iFrom)
){
pPartial = sqlite3ExprAnd(pParse, pPartial,
sqlite3ExprDup(pParse->db, pExpr, 0));
@@ -159247,7 +162718,11 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
** original table changes and the index and table cannot both be used
** if they go out of sync.
*/
- extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1));
+ if( IsView(pTable) ){
+ extraCols = ALLBITS;
+ }else{
+ extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1));
+ }
mxBitCol = MIN(BMS-1,pTable->nCol);
testcase( pTable->nCol==BMS-1 );
testcase( pTable->nCol==BMS-2 );
@@ -159332,14 +162807,14 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
}
/* Fill the automatic index with content */
- pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom];
- if( pTabItem->fg.viaCoroutine ){
- int regYield = pTabItem->regReturn;
+ assert( pSrc == &pWC->pWInfo->pTabList->a[pLevel->iFrom] );
+ if( pSrc->fg.viaCoroutine ){
+ int regYield = pSrc->regReturn;
addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0);
- sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
+ sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSrc->addrFillSub);
addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
VdbeCoverage(v);
- VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
+ VdbeComment((v, "next row of %s", pSrc->pTab->zName));
}else{
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
}
@@ -159360,14 +162835,14 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
- if( pTabItem->fg.viaCoroutine ){
+ if( pSrc->fg.viaCoroutine ){
sqlite3VdbeChangeP2(v, addrCounter, regBase+n);
testcase( pParse->db->mallocFailed );
assert( pLevel->iIdxCur>0 );
translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
- pTabItem->regResult, pLevel->iIdxCur);
+ pSrc->regResult, pLevel->iIdxCur);
sqlite3VdbeGoto(v, addrTop);
- pTabItem->fg.viaCoroutine = 0;
+ pSrc->fg.viaCoroutine = 0;
}else{
sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
@@ -159419,16 +162894,26 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
Vdbe *v = pParse->pVdbe; /* VDBE under construction */
WhereLoop *pLoop = pLevel->pWLoop; /* The loop being coded */
int iCur; /* Cursor for table getting the filter */
+ IndexedExpr *saved_pIdxEpr; /* saved copy of Parse.pIdxEpr */
+ IndexedExpr *saved_pIdxPartExpr; /* saved copy of Parse.pIdxPartExpr */
+
+ saved_pIdxEpr = pParse->pIdxEpr;
+ saved_pIdxPartExpr = pParse->pIdxPartExpr;
+ pParse->pIdxEpr = 0;
+ pParse->pIdxPartExpr = 0;
assert( pLoop!=0 );
assert( v!=0 );
assert( pLoop->wsFlags & WHERE_BLOOMFILTER );
+ assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 );
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
do{
+ const SrcList *pTabList;
const SrcItem *pItem;
const Table *pTab;
u64 sz;
+ int iSrc;
sqlite3WhereExplainBloomFilter(pParse, pWInfo, pLevel);
addrCont = sqlite3VdbeMakeLabel(pParse);
iCur = pLevel->iTabCur;
@@ -159442,7 +162927,9 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
** testing complicated. By basing the blob size on the value in the
** sqlite_stat1 table, testing is much easier.
*/
- pItem = &pWInfo->pTabList->a[pLevel->iFrom];
+ pTabList = pWInfo->pTabList;
+ iSrc = pLevel->iFrom;
+ pItem = &pTabList->a[iSrc];
assert( pItem!=0 );
pTab = pItem->pTab;
assert( pTab!=0 );
@@ -159459,7 +162946,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
for(pTerm=pWInfo->sWC.a; pTermpExpr;
if( (pTerm->wtFlags & TERM_VIRTUAL)==0
- && sqlite3ExprIsTableConstraint(pExpr, pItem)
+ && sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, iSrc)
){
sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
}
@@ -159475,9 +162962,8 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
int r1 = sqlite3GetTempRange(pParse, n);
int jj;
for(jj=0; jjaiColumn[jj];
assert( pIdx->pTable==pItem->pTab );
- sqlite3ExprCodeGetColumnOfTable(v, pIdx->pTable, iCur, iCol,r1+jj);
+ sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj);
}
sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n);
sqlite3ReleaseTempRange(pParse, r1, n);
@@ -159508,6 +162994,8 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
}
}while( iLevel < pWInfo->nLevel );
sqlite3VdbeJumpHere(v, addrOnce);
+ pParse->pIdxEpr = saved_pIdxEpr;
+ pParse->pIdxPartExpr = saved_pIdxPartExpr;
}
@@ -159763,6 +163251,9 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg);
}
}
+ if( pTab->u.vtab.p->bAllSchemas ){
+ sqlite3VtabUsesAllSchemas(pParse);
+ }
sqlite3_free(pVtab->zErrMsg);
pVtab->zErrMsg = 0;
return rc;
@@ -159807,6 +163298,7 @@ static int whereKeyStats(
assert( pIdx->nSample>0 );
assert( pRec->nField>0 );
+
/* Do a binary search to find the first sample greater than or equal
** to pRec. If pRec contains a single field, the set of samples to search
** is simply the aSample[] array. If the samples in aSample[] contain more
@@ -159851,7 +163343,12 @@ static int whereKeyStats(
** it is extended to two fields. The duplicates that this creates do not
** cause any problems.
*/
- nField = MIN(pRec->nField, pIdx->nSample);
+ if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
+ nField = pIdx->nKeyCol;
+ }else{
+ nField = pIdx->nColumn;
+ }
+ nField = MIN(pRec->nField, nField);
iCol = 0;
iSample = pIdx->nSample * nField;
do{
@@ -160014,7 +163511,7 @@ SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCo
** Value pLoop->nOut is currently set to the estimated number of rows
** visited for scanning (a=? AND b=?). This function reduces that estimate
** by some factor to account for the (c BETWEEN ? AND ?) expression based
-** on the stat4 data for the index. this scan will be peformed multiple
+** on the stat4 data for the index. this scan will be performed multiple
** times (once for each (a,b) combination that matches a=?) is dealt with
** by the caller.
**
@@ -160287,7 +163784,7 @@ static int whereRangeScanEst(
UNUSED_PARAMETER(pBuilder);
assert( pLower || pUpper );
#endif
- assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 );
+ assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 || pParse->nErr>0 );
nNew = whereRangeAdjust(pLower, nOut);
nNew = whereRangeAdjust(pUpper, nNew);
@@ -160769,7 +164266,7 @@ static WhereLoop **whereLoopFindLesser(
** rSetup. Call this SETUP-INVARIANT */
assert( p->rSetup>=pTemplate->rSetup );
- /* Any loop using an appliation-defined index (or PRIMARY KEY or
+ /* Any loop using an application-defined index (or PRIMARY KEY or
** UNIQUE constraint) with one or more == constraints is better
** than an automatic index. Unless it is a skip-scan. */
if( (p->wsFlags & WHERE_AUTO_INDEX)!=0
@@ -160796,7 +164293,7 @@ static WhereLoop **whereLoopFindLesser(
/* If pTemplate is always better than p, then cause p to be overwritten
** with pTemplate. pTemplate is better than p if:
- ** (1) pTemplate has no more dependences than p, and
+ ** (1) pTemplate has no more dependencies than p, and
** (2) pTemplate has an equal or lower cost than p.
*/
if( (p->prereq & pTemplate->prereq)==pTemplate->prereq /* (1) */
@@ -160914,7 +164411,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
}else{
/* We will be overwriting WhereLoop p[]. But before we do, first
** go through the rest of the list and delete any other entries besides
- ** p[] that are also supplated by pTemplate */
+ ** p[] that are also supplanted by pTemplate */
WhereLoop **ppTail = &p->pNextLoop;
WhereLoop *pToDel;
while( *ppTail ){
@@ -161114,7 +164611,7 @@ static int whereRangeVectorLen(
}
/*
-** Adjust the cost C by the costMult facter T. This only occurs if
+** Adjust the cost C by the costMult factor T. This only occurs if
** compiled with -DSQLITE_ENABLE_COSTMULT
*/
#ifdef SQLITE_ENABLE_COSTMULT
@@ -161141,7 +164638,7 @@ static int whereLoopAddBtreeIndex(
Index *pProbe, /* An index on pSrc */
LogEst nInMul /* log(Number of iterations due to IN) */
){
- WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyse context */
+ WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyze context */
Parse *pParse = pWInfo->pParse; /* Parsing context */
sqlite3 *db = pParse->db; /* Database connection malloc context */
WhereLoop *pNew; /* Template WhereLoop under construction */
@@ -161451,7 +164948,7 @@ static int whereLoopAddBtreeIndex(
assert( pSrc->pTab->szTabRow>0 );
if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
/* The pProbe->szIdxRow is low for an IPK table since the interior
- ** pages are small. Thuse szIdxRow gives a good estimate of seek cost.
+ ** pages are small. Thus szIdxRow gives a good estimate of seek cost.
** But the leaf pages are full-size, so pProbe->szIdxRow would badly
** under-estimate the scanning cost. */
rCostIdx = pNew->nOut + 16;
@@ -161758,6 +165255,100 @@ static SQLITE_NOINLINE u32 whereIsCoveringIndex(
return rc;
}
+/*
+** This is an sqlite3ParserAddCleanup() callback that is invoked to
+** free the Parse->pIdxEpr list when the Parse object is destroyed.
+*/
+static void whereIndexedExprCleanup(sqlite3 *db, void *pObject){
+ IndexedExpr **pp = (IndexedExpr**)pObject;
+ while( *pp!=0 ){
+ IndexedExpr *p = *pp;
+ *pp = p->pIENext;
+ sqlite3ExprDelete(db, p->pExpr);
+ sqlite3DbFreeNN(db, p);
+ }
+}
+
+/*
+** This function is called for a partial index - one with a WHERE clause - in
+** two scenarios. In both cases, it determines whether or not the WHERE
+** clause on the index implies that a column of the table may be safely
+** replaced by a constant expression. For example, in the following
+** SELECT:
+**
+** CREATE INDEX i1 ON t1(b, c) WHERE a=;
+** SELECT a, b, c FROM t1 WHERE a= AND b=?;
+**
+** The "a" in the select-list may be replaced by , iff:
+**
+** (a) is a constant expression, and
+** (b) The (a=) comparison uses the BINARY collation sequence, and
+** (c) Column "a" has an affinity other than NONE or BLOB.
+**
+** If argument pItem is NULL, then pMask must not be NULL. In this case this
+** function is being called as part of determining whether or not pIdx
+** is a covering index. This function clears any bits in (*pMask)
+** corresponding to columns that may be replaced by constants as described
+** above.
+**
+** Otherwise, if pItem is not NULL, then this function is being called
+** as part of coding a loop that uses index pIdx. In this case, add entries
+** to the Parse.pIdxPartExpr list for each column that can be replaced
+** by a constant.
+*/
+static void wherePartIdxExpr(
+ Parse *pParse, /* Parse context */
+ Index *pIdx, /* Partial index being processed */
+ Expr *pPart, /* WHERE clause being processed */
+ Bitmask *pMask, /* Mask to clear bits in */
+ int iIdxCur, /* Cursor number for index */
+ SrcItem *pItem /* The FROM clause entry for the table */
+){
+ assert( pItem==0 || (pItem->fg.jointype & JT_RIGHT)==0 );
+ assert( (pItem==0 || pMask==0) && (pMask!=0 || pItem!=0) );
+
+ if( pPart->op==TK_AND ){
+ wherePartIdxExpr(pParse, pIdx, pPart->pRight, pMask, iIdxCur, pItem);
+ pPart = pPart->pLeft;
+ }
+
+ if( (pPart->op==TK_EQ || pPart->op==TK_IS) ){
+ Expr *pLeft = pPart->pLeft;
+ Expr *pRight = pPart->pRight;
+ u8 aff;
+
+ if( pLeft->op!=TK_COLUMN ) return;
+ if( !sqlite3ExprIsConstant(pRight) ) return;
+ if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pParse, pPart)) ) return;
+ if( pLeft->iColumn<0 ) return;
+ aff = pIdx->pTable->aCol[pLeft->iColumn].affinity;
+ if( aff>=SQLITE_AFF_TEXT ){
+ if( pItem ){
+ sqlite3 *db = pParse->db;
+ IndexedExpr *p = (IndexedExpr*)sqlite3DbMallocRaw(db, sizeof(*p));
+ if( p ){
+ int bNullRow = (pItem->fg.jointype&(JT_LEFT|JT_LTORJ))!=0;
+ p->pExpr = sqlite3ExprDup(db, pRight, 0);
+ p->iDataCur = pItem->iCursor;
+ p->iIdxCur = iIdxCur;
+ p->iIdxCol = pLeft->iColumn;
+ p->bMaybeNullRow = bNullRow;
+ p->pIENext = pParse->pIdxPartExpr;
+ p->aff = aff;
+ pParse->pIdxPartExpr = p;
+ if( p->pIENext==0 ){
+ void *pArg = (void*)&pParse->pIdxPartExpr;
+ sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pArg);
+ }
+ }
+ }else if( pLeft->iColumn<(BMS-1) ){
+ *pMask &= ~((Bitmask)1 << pLeft->iColumn);
+ }
+ }
+ }
+}
+
+
/*
** Add all WhereLoop objects for a single table of the join where the table
** is identified by pBuilder->pNew->iTab. That table is guaranteed to be
@@ -161796,7 +165387,7 @@ static SQLITE_NOINLINE u32 whereIsCoveringIndex(
*/
static int whereLoopAddBtree(
WhereLoopBuilder *pBuilder, /* WHERE clause information */
- Bitmask mPrereq /* Extra prerequesites for using this table */
+ Bitmask mPrereq /* Extra prerequisites for using this table */
){
WhereInfo *pWInfo; /* WHERE analysis context */
Index *pProbe; /* An index we are evaluating */
@@ -161961,9 +165552,6 @@ static int whereLoopAddBtree(
#else
pNew->rRun = rSize + 16;
#endif
- if( IsView(pTab) || (pTab->tabFlags & TF_Ephemeral)!=0 ){
- pNew->wsFlags |= WHERE_VIEWSCAN;
- }
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
whereLoopOutputAdjust(pWC, pNew, rSize);
rc = whereLoopInsert(pBuilder, pNew);
@@ -161976,6 +165564,11 @@ static int whereLoopAddBtree(
pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
}else{
m = pSrc->colUsed & pProbe->colNotIdxed;
+ if( pProbe->pPartIdxWhere ){
+ wherePartIdxExpr(
+ pWInfo->pParse, pProbe, pProbe->pPartIdxWhere, &m, 0, 0
+ );
+ }
pNew->wsFlags = WHERE_INDEXED;
if( m==TOPBIT || (pProbe->bHasExpr && !pProbe->bHasVCol && m!=0) ){
u32 isCov = whereIsCoveringIndex(pWInfo, pProbe, pSrc->iCursor);
@@ -162303,7 +165896,7 @@ static int whereLoopAddVirtualOne(
**
** Return a pointer to the collation name:
**
-** 1. If there is an explicit COLLATE operator on the constaint, return it.
+** 1. If there is an explicit COLLATE operator on the constraint, return it.
**
** 2. Else, if the column has an alternative collation, return that.
**
@@ -162358,7 +165951,7 @@ SQLITE_API int sqlite3_vtab_rhs_value(
sqlite3_value *pVal = 0;
int rc = SQLITE_OK;
if( iCons<0 || iCons>=pIdxInfo->nConstraint ){
- rc = SQLITE_MISUSE; /* EV: R-30545-25046 */
+ rc = SQLITE_MISUSE_BKPT; /* EV: R-30545-25046 */
}else{
if( pH->aRhs[iCons]==0 ){
WhereTerm *pTerm = &pH->pWC->a[pIdxInfo->aConstraint[iCons].iTermOffset];
@@ -162388,8 +165981,6 @@ SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info *pIdxInfo){
return pHidden->eDistinct;
}
-#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
- && !defined(SQLITE_OMIT_VIRTUALTABLE)
/*
** Cause the prepared statement that is associated with a call to
** xBestIndex to potentially use all schemas. If the statement being
@@ -162399,9 +165990,7 @@ SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info *pIdxInfo){
**
** This is used by the (built-in) sqlite_dbpage virtual table.
*/
-SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(sqlite3_index_info *pIdxInfo){
- HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
- Parse *pParse = pHidden->pParse;
+SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(Parse *pParse){
int nDb = pParse->db->nDb;
int i;
for(i=0; ipTabList->nSrc );
- WHERETRACE(0x002, ("---- begin solver. (nRowEst=%d)\n", nRowEst));
+ WHERETRACE(0x002, ("---- begin solver. (nRowEst=%d, nQueryLoop=%d)\n",
+ nRowEst, pParse->nQueryLoop));
/* If nRowEst is zero and there is an ORDER BY clause, ignore it. In this
** case the purpose of this call is to estimate the number of rows returned
@@ -163372,7 +166961,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
);
}
/* TUNING: Add a small extra penalty (3) to sorting as an
- ** extra encouragment to the query planner to select a plan
+ ** extra encouragement to the query planner to select a plan
** where the rows emerge in the correct order without any sorting
** required. */
rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 3;
@@ -163386,13 +166975,6 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
rUnsorted -= 2; /* TUNING: Slight bias in favor of no-sort plans */
}
- /* TUNING: A full-scan of a VIEW or subquery in the outer loop
- ** is not so bad. */
- if( iLoop==0 && (pWLoop->wsFlags & WHERE_VIEWSCAN)!=0 ){
- rCost += -10;
- nOut += -30;
- }
-
/* Check to see if pWLoop should be added to the set of
** mxChoice best-so-far paths.
**
@@ -163579,6 +167161,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
}
+ if( pWInfo->pSelect->pOrderBy
+ && pWInfo->nOBSat > pWInfo->pSelect->pOrderBy->nExpr ){
+ pWInfo->nOBSat = pWInfo->pSelect->pOrderBy->nExpr;
+ }
}else{
pWInfo->revMask = pFrom->revLoop;
if( pWInfo->nOBSat<=0 ){
@@ -163790,6 +167376,13 @@ static void showAllWhereLoops(WhereInfo *pWInfo, WhereClause *pWC){
** at most a single row.
** 4) The table must not be referenced by any part of the query apart
** from its own USING or ON clause.
+** 5) The table must not have an inner-join ON or USING clause if there is
+** a RIGHT JOIN anywhere in the query. Otherwise the ON/USING clause
+** might move from the right side to the left side of the RIGHT JOIN.
+** Note: Due to (2), this condition can only arise if the table is
+** the right-most table of a subquery that was flattened into the
+** main query and that subquery was the right-hand operand of an
+** inner join that held an ON or USING clause.
**
** For example, given:
**
@@ -163815,6 +167408,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
){
int i;
Bitmask tabUsed;
+ int hasRightJoin;
/* Preconditions checked by the caller */
assert( pWInfo->nLevel>=2 );
@@ -163829,6 +167423,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
if( pWInfo->pOrderBy ){
tabUsed |= sqlite3WhereExprListUsage(&pWInfo->sMaskSet, pWInfo->pOrderBy);
}
+ hasRightJoin = (pWInfo->pTabList->a[0].fg.jointype & JT_LTORJ)!=0;
for(i=pWInfo->nLevel-1; i>=1; i--){
WhereTerm *pTerm, *pEnd;
SrcItem *pItem;
@@ -163851,6 +167446,12 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
break;
}
}
+ if( hasRightJoin
+ && ExprHasProperty(pTerm->pExpr, EP_InnerON)
+ && pTerm->pExpr->w.iJoin==pItem->iCursor
+ ){
+ break; /* restriction (5) */
+ }
}
if( pTerm drop loop %c not used\n", pLoop->cId));
@@ -163923,20 +167524,6 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
}
}
-/*
-** This is an sqlite3ParserAddCleanup() callback that is invoked to
-** free the Parse->pIdxEpr list when the Parse object is destroyed.
-*/
-static void whereIndexedExprCleanup(sqlite3 *db, void *pObject){
- Parse *pParse = (Parse*)pObject;
- while( pParse->pIdxEpr!=0 ){
- IndexedExpr *p = pParse->pIdxEpr;
- pParse->pIdxEpr = p->pIENext;
- sqlite3ExprDelete(db, p->pExpr);
- sqlite3DbFreeNN(db, p);
- }
-}
-
/*
** The index pIdx is used by a query and contains one or more expressions.
** In other words pIdx is an index on an expression. iIdxCur is the cursor
@@ -163998,7 +167585,30 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
#endif
pParse->pIdxEpr = p;
if( p->pIENext==0 ){
- sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pParse);
+ void *pArg = (void*)&pParse->pIdxEpr;
+ sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pArg);
+ }
+ }
+}
+
+/*
+** Set the reverse-scan order mask to one for all tables in the query
+** with the exception of MATERIALIZED common table expressions that have
+** their own internal ORDER BY clauses.
+**
+** This implements the PRAGMA reverse_unordered_selects=ON setting.
+** (Also SQLITE_DBCONFIG_REVERSE_SCANORDER).
+*/
+static SQLITE_NOINLINE void whereReverseScanOrder(WhereInfo *pWInfo){
+ int ii;
+ for(ii=0; iipTabList->nSrc; ii++){
+ SrcItem *pItem = &pWInfo->pTabList->a[ii];
+ if( !pItem->fg.isCte
+ || pItem->u2.pCteUse->eM10d!=M10d_Yes
+ || NEVER(pItem->pSelect==0)
+ || pItem->pSelect->pOrderBy==0
+ ){
+ pWInfo->revMask |= MASKBIT(ii);
}
}
}
@@ -164061,7 +167671,7 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
**
** OUTER JOINS
**
-** An outer join of tables t1 and t2 is conceptally coded as follows:
+** An outer join of tables t1 and t2 is conceptually coded as follows:
**
** foreach row1 in t1 do
** flag = 0
@@ -164216,7 +167826,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
**
** The N-th term of the FROM clause is assigned a bitmask of 1<nErr ) goto whereBeginError;
- /* Special case: WHERE terms that do not refer to any tables in the join
- ** (constant expressions). Evaluate each such term, and jump over all the
- ** generated code if the result is not true.
+ /* The False-WHERE-Term-Bypass optimization:
+ **
+ ** If there are WHERE terms that are false, then no rows will be output,
+ ** so skip over all of the code generated here.
**
- ** Do not do this if the expression contains non-deterministic functions
- ** that are not within a sub-select. This is not strictly required, but
- ** preserves SQLite's legacy behaviour in the following two cases:
+ ** Conditions:
**
- ** FROM ... WHERE random()>0; -- eval random() once per row
- ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall
+ ** (1) The WHERE term must not refer to any tables in the join.
+ ** (2) The term must not come from an ON clause on the
+ ** right-hand side of a LEFT or FULL JOIN.
+ ** (3) The term must not come from an ON clause, or there must be
+ ** no RIGHT or FULL OUTER joins in pTabList.
+ ** (4) If the expression contains non-deterministic functions
+ ** that are not within a sub-select. This is not required
+ ** for correctness but rather to preserves SQLite's legacy
+ ** behaviour in the following two cases:
+ **
+ ** WHERE random()>0; -- eval random() once per row
+ ** WHERE (SELECT random())>0; -- eval random() just once overall
+ **
+ ** Note that the Where term need not be a constant in order for this
+ ** optimization to apply, though it does need to be constant relative to
+ ** the current subquery (condition 1). The term might include variables
+ ** from outer queries so that the value of the term changes from one
+ ** invocation of the current subquery to the next.
*/
for(ii=0; iinBase; ii++){
- WhereTerm *pT = &sWLB.pWC->a[ii];
+ WhereTerm *pT = &sWLB.pWC->a[ii]; /* A term of the WHERE clause */
+ Expr *pX; /* The expression of pT */
if( pT->wtFlags & TERM_VIRTUAL ) continue;
- if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){
- sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL);
+ pX = pT->pExpr;
+ assert( pX!=0 );
+ assert( pT->prereqAll!=0 || !ExprHasProperty(pX, EP_OuterON) );
+ if( pT->prereqAll==0 /* Conditions (1) and (2) */
+ && (nTabList==0 || exprIsDeterministic(pX)) /* Condition (4) */
+ && !(ExprHasProperty(pX, EP_InnerON) /* Condition (3) */
+ && (pTabList->a[0].fg.jointype & JT_LTORJ)!=0 )
+ ){
+ sqlite3ExprIfFalse(pParse, pX, pWInfo->iBreak, SQLITE_JUMPIFNULL);
pT->wtFlags |= TERM_CODED;
}
}
@@ -164343,9 +167976,20 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
wherePathSolver(pWInfo, pWInfo->nRowOut+1);
if( db->mallocFailed ) goto whereBeginError;
}
+
+ /* TUNING: Assume that a DISTINCT clause on a subquery reduces
+ ** the output size by a factor of 8 (LogEst -30).
+ */
+ if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)!=0 ){
+ WHERETRACE(0x0080,("nRowOut reduced from %d to %d due to DISTINCT\n",
+ pWInfo->nRowOut, pWInfo->nRowOut-30));
+ pWInfo->nRowOut -= 30;
+ }
+
}
+ assert( pWInfo->pTabList!=0 );
if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){
- pWInfo->revMask = ALLBITS;
+ whereReverseScanOrder(pWInfo);
}
if( pParse->nErr ){
goto whereBeginError;
@@ -164445,6 +168089,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW)
&& !IsVirtual(pTabList->a[0].pTab)
&& (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK))
+ && OptimizationEnabled(db, SQLITE_OnePass)
)){
pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI;
if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){
@@ -164508,7 +168153,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
assert( n<=pTab->nCol );
}
#ifdef SQLITE_ENABLE_CURSOR_HINTS
- if( pLoop->u.btree.pIndex!=0 ){
+ if( pLoop->u.btree.pIndex!=0 && (pTab->tabFlags & TF_WithoutRowid)==0 ){
sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ|bFordelete);
}else
#endif
@@ -164553,6 +168198,11 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
if( pIx->bHasExpr && OptimizationEnabled(db, SQLITE_IndexedExpr) ){
whereAddIndexedExpr(pParse, pIx, iIndexCur, pTabItem);
}
+ if( pIx->pPartIdxWhere && (pTabItem->fg.jointype & JT_RIGHT)==0 ){
+ wherePartIdxExpr(
+ pParse, pIx, pIx->pPartIdxWhere, 0, iIndexCur, pTabItem
+ );
+ }
}
pLevel->iIdxCur = iIndexCur;
assert( pIx!=0 );
@@ -164645,11 +168295,11 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
sqlite3VdbeJumpHere(v, iOnce);
}
}
+ assert( pTabList == pWInfo->pTabList );
if( (wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))!=0 ){
if( (wsFlags & WHERE_AUTO_INDEX)!=0 ){
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
- constructAutomaticIndex(pParse, &pWInfo->sWC,
- &pTabList->a[pLevel->iFrom], notReady, pLevel);
+ constructAutomaticIndex(pParse, &pWInfo->sWC, notReady, pLevel);
#endif
}else{
sqlite3ConstructBloomFilter(pWInfo, ii, pLevel, notReady);
@@ -164966,7 +168616,8 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
k = pLevel->addrBody + 1;
#ifdef SQLITE_DEBUG
if( db->flags & SQLITE_VdbeAddopTrace ){
- printf("TRANSLATE opcodes in range %d..%d\n", k, last-1);
+ printf("TRANSLATE cursor %d->%d in opcode range %d..%d\n",
+ pLevel->iTabCur, pLevel->iIdxCur, k, last-1);
}
/* Proof that the "+1" on the k value above is safe */
pOp = sqlite3VdbeGetOp(v, k - 1);
@@ -165173,7 +168824,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
**
** These are the same built-in window functions supported by Postgres.
** Although the behaviour of aggregate window functions (functions that
-** can be used as either aggregates or window funtions) allows them to
+** can be used as either aggregates or window functions) allows them to
** be implemented using an API, built-in window functions are much more
** esoteric. Additionally, some window functions (e.g. nth_value())
** may only be implemented by caching the entire partition in memory.
@@ -165703,7 +169354,7 @@ static Window *windowFind(Parse *pParse, Window *pList, const char *zName){
** is the Window object representing the associated OVER clause. This
** function updates the contents of pWin as follows:
**
-** * If the OVER clause refered to a named window (as in "max(x) OVER win"),
+** * If the OVER clause referred to a named window (as in "max(x) OVER win"),
** search list pList for a matching WINDOW definition, and update pWin
** accordingly. If no such WINDOW clause can be found, leave an error
** in pParse.
@@ -165841,6 +169492,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
}
/* no break */ deliberate_fall_through
+ case TK_IF_NULL_ROW:
case TK_AGG_FUNCTION:
case TK_COLUMN: {
int iCol = -1;
@@ -166323,7 +169975,7 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble(
}
/*
-** Window *pWin has just been created from a WINDOW clause. Tokne pBase
+** Window *pWin has just been created from a WINDOW clause. Token pBase
** is the base window. Earlier windows from the same WINDOW clause are
** stored in the linked list starting at pWin->pNextWin. This function
** either updates *pWin according to the base specification, or else
@@ -166367,8 +170019,9 @@ SQLITE_PRIVATE void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){
if( p ){
assert( p->op==TK_FUNCTION );
assert( pWin );
+ assert( ExprIsFullSize(p) );
p->y.pWin = pWin;
- ExprSetProperty(p, EP_WinFunc);
+ ExprSetProperty(p, EP_WinFunc|EP_FullSize);
pWin->pOwner = p;
if( (p->flags & EP_Distinct) && pWin->eFrmType!=TK_FILTER ){
sqlite3ErrorMsg(pParse,
@@ -166629,7 +170282,7 @@ struct WindowCsrAndReg {
**
** (ORDER BY a, b GROUPS BETWEEN 2 PRECEDING AND 2 FOLLOWING)
**
-** The windows functions implmentation caches the input rows in a temp
+** The windows functions implementation caches the input rows in a temp
** table, sorted by "a, b" (it actually populates the cache lazily, and
** aggressively removes rows once they are no longer required, but that's
** a mere detail). It keeps three cursors open on the temp table. One
@@ -167638,7 +171291,7 @@ static int windowExprGtZero(Parse *pParse, Expr *pExpr){
**
** For the most part, the patterns above are adapted to support UNBOUNDED by
** assuming that it is equivalent to "infinity PRECEDING/FOLLOWING" and
-** CURRENT ROW by assuming that it is equivilent to "0 PRECEDING/FOLLOWING".
+** CURRENT ROW by assuming that it is equivalent to "0 PRECEDING/FOLLOWING".
** This is optimized of course - branches that will never be taken and
** conditions that are always true are omitted from the VM code. The only
** exceptional case is:
@@ -167917,7 +171570,7 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
}
/* Allocate registers for the array of values from the sub-query, the
- ** samve values in record form, and the rowid used to insert said record
+ ** same values in record form, and the rowid used to insert said record
** into the ephemeral table. */
regNew = pParse->nMem+1;
pParse->nMem += nInput;
@@ -168158,7 +171811,8 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
/************** End of window.c **********************************************/
/************** Begin file parse.c *******************************************/
/* This file is automatically generated by Lemon from input grammar
-** source file "parse.y". */
+** source file "parse.y".
+*/
/*
** 2001-09-15
**
@@ -168175,7 +171829,7 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
** The canonical source code to this file ("parse.y") is a Lemon grammar
** file that specifies the input grammar and actions to take while parsing.
** That input file is processed by Lemon to generate a C-language
-** implementation of a parser for the given grammer. You might be reading
+** implementation of a parser for the given grammar. You might be reading
** this comment as part of the translated C-code. Edits should be made
** to the original parse.y sources.
*/
@@ -168395,183 +172049,184 @@ static void updateDeleteLimitError(
#define TK_DEFERRED 7
#define TK_IMMEDIATE 8
#define TK_EXCLUSIVE 9
-#define TK_COMMIT 10
-#define TK_END 11
-#define TK_ROLLBACK 12
-#define TK_SAVEPOINT 13
-#define TK_RELEASE 14
-#define TK_TO 15
-#define TK_TABLE 16
-#define TK_CREATE 17
-#define TK_IF 18
-#define TK_NOT 19
-#define TK_EXISTS 20
-#define TK_TEMP 21
-#define TK_LP 22
-#define TK_RP 23
-#define TK_AS 24
-#define TK_COMMA 25
-#define TK_WITHOUT 26
-#define TK_RANDOM 27
-#define TK_ABORT 28
-#define TK_ACTION 29
-#define TK_AFTER 30
-#define TK_ANALYZE 31
-#define TK_ASC 32
-#define TK_ATTACH 33
-#define TK_BEFORE 34
-#define TK_BY 35
-#define TK_CASCADE 36
-#define TK_CAST 37
-#define TK_CONFLICT 38
-#define TK_DATABASE 39
-#define TK_DESC 40
-#define TK_DETACH 41
-#define TK_EACH 42
-#define TK_FAIL 43
-#define TK_FUNCTION 44
-#define TK_LANGUAGE 45
-#define TK_OR 46
-#define TK_AND 47
-#define TK_IS 48
-#define TK_MATCH 49
-#define TK_LIKE_KW 50
-#define TK_BETWEEN 51
-#define TK_IN 52
-#define TK_ISNULL 53
-#define TK_NOTNULL 54
-#define TK_NE 55
-#define TK_EQ 56
-#define TK_GT 57
-#define TK_LE 58
-#define TK_LT 59
-#define TK_GE 60
-#define TK_ESCAPE 61
-#define TK_ID 62
-#define TK_COLUMNKW 63
-#define TK_DO 64
-#define TK_FOR 65
-#define TK_IGNORE 66
-#define TK_INITIALLY 67
-#define TK_INSTEAD 68
-#define TK_NO 69
-#define TK_KEY 70
-#define TK_OF 71
-#define TK_OFFSET 72
-#define TK_PRAGMA 73
-#define TK_RAISE 74
-#define TK_RECURSIVE 75
-#define TK_REPLACE 76
-#define TK_RESTRICT 77
-#define TK_ROW 78
-#define TK_ROWS 79
-#define TK_TRIGGER 80
-#define TK_VACUUM 81
-#define TK_VIEW 82
-#define TK_VIRTUAL 83
-#define TK_WITH 84
-#define TK_NULLS 85
-#define TK_FIRST 86
-#define TK_LAST 87
-#define TK_CURRENT 88
-#define TK_FOLLOWING 89
-#define TK_PARTITION 90
-#define TK_PRECEDING 91
-#define TK_RANGE 92
-#define TK_UNBOUNDED 93
-#define TK_EXCLUDE 94
-#define TK_GROUPS 95
-#define TK_OTHERS 96
-#define TK_TIES 97
-#define TK_GENERATED 98
-#define TK_ALWAYS 99
-#define TK_MATERIALIZED 100
-#define TK_REINDEX 101
-#define TK_RENAME 102
-#define TK_CTIME_KW 103
-#define TK_ANY 104
-#define TK_BITAND 105
-#define TK_BITOR 106
-#define TK_LSHIFT 107
-#define TK_RSHIFT 108
-#define TK_PLUS 109
-#define TK_MINUS 110
-#define TK_STAR 111
-#define TK_SLASH 112
-#define TK_REM 113
-#define TK_CONCAT 114
-#define TK_PTR 115
-#define TK_COLLATE 116
-#define TK_BITNOT 117
-#define TK_ON 118
-#define TK_INDEXED 119
-#define TK_STRING 120
-#define TK_JOIN_KW 121
-#define TK_CONSTRAINT 122
-#define TK_DEFAULT 123
-#define TK_NULL 124
-#define TK_PRIMARY 125
-#define TK_UNIQUE 126
-#define TK_CHECK 127
-#define TK_REFERENCES 128
-#define TK_AUTOINCR 129
-#define TK_INSERT 130
-#define TK_DELETE 131
-#define TK_UPDATE 132
-#define TK_SET 133
-#define TK_DEFERRABLE 134
-#define TK_FOREIGN 135
-#define TK_DROP 136
-#define TK_BLOB 137
-#define TK_UNION 138
-#define TK_ALL 139
-#define TK_EXCEPT 140
-#define TK_INTERSECT 141
-#define TK_SELECT 142
-#define TK_VALUES 143
-#define TK_DISTINCT 144
-#define TK_DOT 145
-#define TK_FROM 146
-#define TK_JOIN 147
-#define TK_USING 148
-#define TK_ORDER 149
-#define TK_GROUP 150
-#define TK_HAVING 151
-#define TK_LIMIT 152
-#define TK_WHERE 153
-#define TK_RETURNING 154
-#define TK_INTO 155
-#define TK_NOTHING 156
-#define TK_FLOAT 157
-#define TK_INTEGER 158
-#define TK_VARIABLE 159
-#define TK_CASE 160
-#define TK_WHEN 161
-#define TK_THEN 162
-#define TK_ELSE 163
-#define TK_INDEX 164
-#define TK_ALTER 165
-#define TK_ADD 166
-#define TK_WINDOW 167
-#define TK_OVER 168
-#define TK_FILTER 169
-#define TK_COLUMN 170
-#define TK_AGG_FUNCTION 171
-#define TK_AGG_COLUMN 172
-#define TK_TRUEFALSE 173
-#define TK_ISNOT 174
-#define TK_UMINUS 175
-#define TK_UPLUS 176
-#define TK_TRUTH 177
-#define TK_REGISTER 178
-#define TK_VECTOR 179
-#define TK_SELECT_COLUMN 180
-#define TK_IF_NULL_ROW 181
-#define TK_ASTERISK 182
-#define TK_SPAN 183
-#define TK_ERROR 184
-#define TK_SPACE 185
-#define TK_ILLEGAL 186
+#define TK_READONLY 10
+#define TK_COMMIT 11
+#define TK_END 12
+#define TK_ROLLBACK 13
+#define TK_SAVEPOINT 14
+#define TK_RELEASE 15
+#define TK_TO 16
+#define TK_TABLE 17
+#define TK_CREATE 18
+#define TK_IF 19
+#define TK_NOT 20
+#define TK_EXISTS 21
+#define TK_TEMP 22
+#define TK_LP 23
+#define TK_RP 24
+#define TK_AS 25
+#define TK_COMMA 26
+#define TK_WITHOUT 27
+#define TK_RANDOM 28
+#define TK_ABORT 29
+#define TK_ACTION 30
+#define TK_AFTER 31
+#define TK_ANALYZE 32
+#define TK_ASC 33
+#define TK_ATTACH 34
+#define TK_BEFORE 35
+#define TK_BY 36
+#define TK_CASCADE 37
+#define TK_CAST 38
+#define TK_CONFLICT 39
+#define TK_DATABASE 40
+#define TK_DESC 41
+#define TK_DETACH 42
+#define TK_EACH 43
+#define TK_FAIL 44
+#define TK_FUNCTION 45
+#define TK_LANGUAGE 46
+#define TK_OR 47
+#define TK_AND 48
+#define TK_IS 49
+#define TK_MATCH 50
+#define TK_LIKE_KW 51
+#define TK_BETWEEN 52
+#define TK_IN 53
+#define TK_ISNULL 54
+#define TK_NOTNULL 55
+#define TK_NE 56
+#define TK_EQ 57
+#define TK_GT 58
+#define TK_LE 59
+#define TK_LT 60
+#define TK_GE 61
+#define TK_ESCAPE 62
+#define TK_ID 63
+#define TK_COLUMNKW 64
+#define TK_DO 65
+#define TK_FOR 66
+#define TK_IGNORE 67
+#define TK_INITIALLY 68
+#define TK_INSTEAD 69
+#define TK_NO 70
+#define TK_KEY 71
+#define TK_OF 72
+#define TK_OFFSET 73
+#define TK_PRAGMA 74
+#define TK_RAISE 75
+#define TK_RECURSIVE 76
+#define TK_REPLACE 77
+#define TK_RESTRICT 78
+#define TK_ROW 79
+#define TK_ROWS 80
+#define TK_TRIGGER 81
+#define TK_VACUUM 82
+#define TK_VIEW 83
+#define TK_VIRTUAL 84
+#define TK_WITH 85
+#define TK_NULLS 86
+#define TK_FIRST 87
+#define TK_LAST 88
+#define TK_CURRENT 89
+#define TK_FOLLOWING 90
+#define TK_PARTITION 91
+#define TK_PRECEDING 92
+#define TK_RANGE 93
+#define TK_UNBOUNDED 94
+#define TK_EXCLUDE 95
+#define TK_GROUPS 96
+#define TK_OTHERS 97
+#define TK_TIES 98
+#define TK_GENERATED 99
+#define TK_ALWAYS 100
+#define TK_MATERIALIZED 101
+#define TK_REINDEX 102
+#define TK_RENAME 103
+#define TK_CTIME_KW 104
+#define TK_ANY 105
+#define TK_BITAND 106
+#define TK_BITOR 107
+#define TK_LSHIFT 108
+#define TK_RSHIFT 109
+#define TK_PLUS 110
+#define TK_MINUS 111
+#define TK_STAR 112
+#define TK_SLASH 113
+#define TK_REM 114
+#define TK_CONCAT 115
+#define TK_PTR 116
+#define TK_COLLATE 117
+#define TK_BITNOT 118
+#define TK_ON 119
+#define TK_INDEXED 120
+#define TK_STRING 121
+#define TK_JOIN_KW 122
+#define TK_CONSTRAINT 123
+#define TK_DEFAULT 124
+#define TK_NULL 125
+#define TK_PRIMARY 126
+#define TK_UNIQUE 127
+#define TK_CHECK 128
+#define TK_REFERENCES 129
+#define TK_AUTOINCR 130
+#define TK_INSERT 131
+#define TK_DELETE 132
+#define TK_UPDATE 133
+#define TK_SET 134
+#define TK_DEFERRABLE 135
+#define TK_FOREIGN 136
+#define TK_DROP 137
+#define TK_BLOB 138
+#define TK_UNION 139
+#define TK_ALL 140
+#define TK_EXCEPT 141
+#define TK_INTERSECT 142
+#define TK_SELECT 143
+#define TK_VALUES 144
+#define TK_DISTINCT 145
+#define TK_DOT 146
+#define TK_FROM 147
+#define TK_JOIN 148
+#define TK_USING 149
+#define TK_ORDER 150
+#define TK_GROUP 151
+#define TK_HAVING 152
+#define TK_LIMIT 153
+#define TK_WHERE 154
+#define TK_RETURNING 155
+#define TK_INTO 156
+#define TK_NOTHING 157
+#define TK_FLOAT 158
+#define TK_INTEGER 159
+#define TK_VARIABLE 160
+#define TK_CASE 161
+#define TK_WHEN 162
+#define TK_THEN 163
+#define TK_ELSE 164
+#define TK_INDEX 165
+#define TK_ALTER 166
+#define TK_ADD 167
+#define TK_WINDOW 168
+#define TK_OVER 169
+#define TK_FILTER 170
+#define TK_COLUMN 171
+#define TK_AGG_FUNCTION 172
+#define TK_AGG_COLUMN 173
+#define TK_TRUEFALSE 174
+#define TK_ISNOT 175
+#define TK_UMINUS 176
+#define TK_UPLUS 177
+#define TK_TRUTH 178
+#define TK_REGISTER 179
+#define TK_VECTOR 180
+#define TK_SELECT_COLUMN 181
+#define TK_IF_NULL_ROW 182
+#define TK_ASTERISK 183
+#define TK_SPAN 184
+#define TK_ERROR 185
+#define TK_SPACE 186
+#define TK_ILLEGAL 187
#endif
/**************** End token definitions ***************************************/
@@ -168631,31 +172286,31 @@ static void updateDeleteLimitError(
#endif
/************* Begin control #defines *****************************************/
#define YYCODETYPE unsigned short int
-#define YYNOCODE 321
+#define YYNOCODE 322
#define YYACTIONTYPE unsigned short int
-#define YYWILDCARD 104
+#define YYWILDCARD 105
#define sqlite3ParserTOKENTYPE Token
typedef union {
int yyinit;
sqlite3ParserTOKENTYPE yy0;
- OnOrUsing yy5;
- Upsert* yy6;
- With* yy19;
- u32 yy135;
- Select* yy136;
- TriggerStep* yy137;
- Expr* yy224;
- struct {int value; int mask;} yy275;
- int yy436;
- u8 yy480;
- SrcList* yy493;
- struct TrigEvent yy510;
- struct FrameBound yy537;
- ExprList* yy586;
- Window* yy591;
- const char* yy594;
- IdList* yy600;
- Cte* yy615;
+ ExprList* yy14;
+ With* yy59;
+ Cte* yy67;
+ Upsert* yy122;
+ IdList* yy132;
+ int yy144;
+ const char* yy168;
+ SrcList* yy203;
+ Window* yy211;
+ OnOrUsing yy269;
+ struct TrigEvent yy286;
+ struct {int value; int mask;} yy383;
+ u32 yy391;
+ TriggerStep* yy427;
+ Expr* yy454;
+ u8 yy462;
+ struct FrameBound yy509;
+ Select* yy555;
} YYMINORTYPE;
#ifndef YYSTACKDEPTH
#define YYSTACKDEPTH 100
@@ -168671,18 +172326,18 @@ typedef union {
#define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse;
#define sqlite3ParserCTX_STORE yypParser->pParse=pParse;
#define YYFALLBACK 1
-#define YYNSTATE 585
-#define YYNRULE 409
+#define YYNSTATE 594
+#define YYNRULE 411
#define YYNRULE_WITH_ACTION 346
-#define YYNTOKEN 187
-#define YY_MAX_SHIFT 584
-#define YY_MIN_SHIFTREDUCE 848
-#define YY_MAX_SHIFTREDUCE 1256
-#define YY_ERROR_ACTION 1257
-#define YY_ACCEPT_ACTION 1258
-#define YY_NO_ACTION 1259
-#define YY_MIN_REDUCE 1260
-#define YY_MAX_REDUCE 1668
+#define YYNTOKEN 188
+#define YY_MAX_SHIFT 593
+#define YY_MIN_SHIFTREDUCE 858
+#define YY_MAX_SHIFTREDUCE 1268
+#define YY_ERROR_ACTION 1269
+#define YY_ACCEPT_ACTION 1270
+#define YY_NO_ACTION 1271
+#define YY_MIN_REDUCE 1272
+#define YY_MAX_REDUCE 1682
/************* End control #defines *******************************************/
#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))
@@ -168749,621 +172404,628 @@ typedef union {
** yy_default[] Default action for each state.
**
*********** Begin parsing tables **********************************************/
-#define YY_ACTTAB_COUNT (2096)
+#define YY_ACTTAB_COUNT (2115)
static const YYACTIONTYPE yy_action[] = {
- /* 0 */ 500, 481, 577, 283, 208, 118, 115, 229, 1258, 1,
- /* 10 */ 1, 584, 2, 1262, 118, 115, 229, 414, 321, 416,
- /* 20 */ 143, 1607, 584, 2, 1262, 41, 41, 1348, 1628, 321,
- /* 30 */ 1285, 143, 988, 405, 1440, 1547, 1304, 1294, 1348, 307,
- /* 40 */ 989, 307, 1282, 500, 532, 423, 125, 126, 80, 1234,
- /* 50 */ 1234, 1067, 1070, 1057, 1057, 123, 123, 124, 124, 124,
- /* 60 */ 124, 577, 288, 288, 118, 115, 229, 1297, 288, 288,
- /* 70 */ 208, 577, 383, 288, 288, 574, 296, 329, 577, 288,
- /* 80 */ 288, 574, 526, 403, 13, 13, 574, 176, 1546, 240,
- /* 90 */ 1296, 384, 574, 483, 51, 51, 262, 226, 479, 428,
- /* 100 */ 240, 41, 41, 456, 430, 122, 122, 122, 122, 121,
- /* 110 */ 121, 120, 120, 120, 119, 116, 451, 288, 288, 1664,
- /* 120 */ 401, 455, 129, 1588, 382, 416, 577, 118, 115, 229,
- /* 130 */ 574, 527, 455, 122, 122, 122, 122, 121, 121, 120,
- /* 140 */ 120, 120, 119, 116, 451, 416, 118, 115, 229, 41,
- /* 150 */ 41, 101, 125, 126, 80, 1234, 1234, 1067, 1070, 1057,
- /* 160 */ 1057, 123, 123, 124, 124, 124, 124, 1511, 1054, 1054,
- /* 170 */ 1068, 1071, 125, 126, 80, 1234, 1234, 1067, 1070, 1057,
- /* 180 */ 1057, 123, 123, 124, 124, 124, 124, 120, 120, 120,
- /* 190 */ 119, 116, 451, 481, 1285, 1180, 534, 1180, 127, 1590,
- /* 200 */ 451, 381, 524, 1582, 580, 1209, 580, 6, 176, 412,
- /* 210 */ 411, 122, 122, 122, 122, 121, 121, 120, 120, 120,
- /* 220 */ 119, 116, 451, 121, 121, 120, 120, 120, 119, 116,
- /* 230 */ 451, 122, 122, 122, 122, 121, 121, 120, 120, 120,
- /* 240 */ 119, 116, 451, 1058, 472, 347, 577, 1588, 546, 448,
- /* 250 */ 447, 416, 448, 447, 500, 124, 124, 124, 124, 117,
- /* 260 */ 1175, 1238, 1209, 1210, 1211, 552, 1240, 1024, 299, 70,
- /* 270 */ 70, 542, 1634, 1175, 1239, 144, 1175, 144, 125, 126,
- /* 280 */ 80, 1234, 1234, 1067, 1070, 1057, 1057, 123, 123, 124,
- /* 290 */ 124, 124, 124, 275, 274, 97, 535, 1241, 1241, 1510,
- /* 300 */ 1241, 1241, 82, 122, 122, 122, 122, 121, 121, 120,
- /* 310 */ 120, 120, 119, 116, 451, 425, 461, 124, 124, 124,
- /* 320 */ 124, 345, 416, 550, 1582, 536, 1024, 83, 6, 1209,
- /* 330 */ 541, 389, 1604, 320, 568, 320, 568, 122, 122, 122,
- /* 340 */ 122, 121, 121, 120, 120, 120, 119, 116, 451, 125,
- /* 350 */ 126, 80, 1234, 1234, 1067, 1070, 1057, 1057, 123, 123,
- /* 360 */ 124, 124, 124, 124, 416, 122, 122, 122, 122, 121,
- /* 370 */ 121, 120, 120, 120, 119, 116, 451, 100, 553, 1575,
- /* 380 */ 345, 467, 332, 577, 331, 197, 1209, 1210, 1211, 379,
- /* 390 */ 379, 125, 126, 80, 1234, 1234, 1067, 1070, 1057, 1057,
- /* 400 */ 123, 123, 124, 124, 124, 124, 13, 13, 122, 122,
- /* 410 */ 122, 122, 121, 121, 120, 120, 120, 119, 116, 451,
- /* 420 */ 144, 433, 531, 255, 933, 577, 513, 510, 509, 1209,
- /* 430 */ 1332, 1175, 1311, 224, 523, 416, 508, 1209, 154, 362,
- /* 440 */ 1332, 934, 146, 151, 1175, 16, 16, 1175, 71, 71,
- /* 450 */ 122, 122, 122, 122, 121, 121, 120, 120, 120, 119,
- /* 460 */ 116, 451, 125, 126, 80, 1234, 1234, 1067, 1070, 1057,
- /* 470 */ 1057, 123, 123, 124, 124, 124, 124, 416, 320, 568,
- /* 480 */ 1209, 514, 583, 878, 1262, 559, 1209, 1210, 1211, 321,
- /* 490 */ 552, 143, 425, 533, 1209, 1210, 1211, 377, 1348, 214,
- /* 500 */ 1574, 1573, 320, 568, 125, 126, 80, 1234, 1234, 1067,
- /* 510 */ 1070, 1057, 1057, 123, 123, 124, 124, 124, 124, 1337,
- /* 520 */ 1337, 122, 122, 122, 122, 121, 121, 120, 120, 120,
- /* 530 */ 119, 116, 451, 288, 288, 577, 435, 1209, 1210, 1211,
- /* 540 */ 255, 878, 208, 513, 510, 509, 574, 462, 416, 1209,
- /* 550 */ 394, 379, 890, 508, 1209, 408, 190, 379, 71, 71,
- /* 560 */ 240, 206, 148, 122, 122, 122, 122, 121, 121, 120,
- /* 570 */ 120, 120, 119, 116, 451, 125, 126, 80, 1234, 1234,
- /* 580 */ 1067, 1070, 1057, 1057, 123, 123, 124, 124, 124, 124,
- /* 590 */ 416, 577, 455, 1315, 883, 559, 1209, 12, 379, 157,
- /* 600 */ 571, 571, 571, 558, 1576, 153, 1209, 1210, 1211, 577,
- /* 610 */ 576, 1209, 1210, 1211, 71, 71, 906, 125, 126, 80,
- /* 620 */ 1234, 1234, 1067, 1070, 1057, 1057, 123, 123, 124, 124,
- /* 630 */ 124, 124, 133, 133, 122, 122, 122, 122, 121, 121,
- /* 640 */ 120, 120, 120, 119, 116, 451, 155, 85, 577, 517,
- /* 650 */ 373, 559, 425, 1209, 1210, 1211, 1110, 907, 1213, 525,
- /* 660 */ 372, 416, 1573, 1335, 1335, 1193, 191, 487, 1573, 1209,
- /* 670 */ 32, 71, 71, 1455, 5, 488, 122, 122, 122, 122,
- /* 680 */ 121, 121, 120, 120, 120, 119, 116, 451, 125, 126,
- /* 690 */ 80, 1234, 1234, 1067, 1070, 1057, 1057, 123, 123, 124,
- /* 700 */ 124, 124, 124, 416, 282, 282, 1209, 1045, 538, 1573,
- /* 710 */ 1209, 375, 1601, 438, 1209, 1583, 1213, 574, 954, 6,
- /* 720 */ 3, 207, 577, 449, 449, 449, 1209, 1210, 1211, 1314,
- /* 730 */ 125, 126, 80, 1234, 1234, 1067, 1070, 1057, 1057, 123,
- /* 740 */ 123, 124, 124, 124, 124, 71, 71, 122, 122, 122,
- /* 750 */ 122, 121, 121, 120, 120, 120, 119, 116, 451, 12,
- /* 760 */ 1209, 577, 380, 1209, 1210, 1211, 298, 1209, 1210, 1211,
- /* 770 */ 1175, 1209, 1210, 1211, 416, 1352, 472, 347, 1029, 1115,
- /* 780 */ 1115, 497, 316, 1175, 71, 71, 1175, 574, 294, 122,
- /* 790 */ 122, 122, 122, 121, 121, 120, 120, 120, 119, 116,
- /* 800 */ 451, 125, 126, 80, 1234, 1234, 1067, 1070, 1057, 1057,
- /* 810 */ 123, 123, 124, 124, 124, 124, 416, 1209, 1210, 1211,
- /* 820 */ 390, 317, 386, 288, 288, 289, 289, 537, 119, 116,
- /* 830 */ 451, 575, 203, 943, 943, 577, 574, 471, 574, 1373,
- /* 840 */ 315, 303, 227, 125, 126, 80, 1234, 1234, 1067, 1070,
- /* 850 */ 1057, 1057, 123, 123, 124, 124, 124, 124, 71, 71,
- /* 860 */ 122, 122, 122, 122, 121, 121, 120, 120, 120, 119,
- /* 870 */ 116, 451, 1209, 337, 481, 577, 288, 288, 460, 1313,
- /* 880 */ 1154, 1662, 1440, 1662, 853, 854, 855, 416, 440, 574,
- /* 890 */ 258, 257, 256, 366, 360, 446, 460, 459, 71, 71,
- /* 900 */ 477, 335, 122, 122, 122, 122, 121, 121, 120, 120,
- /* 910 */ 120, 119, 116, 451, 125, 126, 80, 1234, 1234, 1067,
- /* 920 */ 1070, 1057, 1057, 123, 123, 124, 124, 124, 124, 1209,
- /* 930 */ 1210, 1211, 577, 521, 1131, 450, 216, 333, 1371, 336,
- /* 940 */ 577, 1154, 1663, 481, 1663, 865, 1440, 400, 1254, 302,
- /* 950 */ 1132, 560, 431, 1286, 421, 13, 13, 976, 355, 104,
- /* 960 */ 358, 949, 1152, 71, 71, 1133, 948, 516, 351, 460,
- /* 970 */ 436, 505, 1454, 122, 122, 122, 122, 121, 121, 120,
- /* 980 */ 120, 120, 119, 116, 451, 437, 288, 288, 926, 1209,
- /* 990 */ 577, 273, 291, 374, 519, 369, 518, 260, 927, 574,
- /* 1000 */ 559, 259, 577, 365, 416, 464, 1175, 470, 561, 209,
- /* 1010 */ 375, 1601, 1440, 13, 13, 413, 432, 549, 304, 1175,
- /* 1020 */ 1209, 334, 1175, 1152, 416, 135, 135, 886, 306, 1255,
- /* 1030 */ 107, 125, 126, 80, 1234, 1234, 1067, 1070, 1057, 1057,
- /* 1040 */ 123, 123, 124, 124, 124, 124, 1209, 1210, 1211, 577,
- /* 1050 */ 1090, 125, 126, 80, 1234, 1234, 1067, 1070, 1057, 1057,
- /* 1060 */ 123, 123, 124, 124, 124, 124, 419, 1580, 1044, 388,
- /* 1070 */ 420, 6, 13, 13, 400, 1153, 540, 1209, 1210, 1211,
- /* 1080 */ 1557, 974, 496, 500, 886, 1035, 365, 200, 1503, 1034,
- /* 1090 */ 122, 122, 122, 122, 121, 121, 120, 120, 120, 119,
- /* 1100 */ 116, 451, 1034, 577, 1343, 975, 1516, 9, 577, 265,
- /* 1110 */ 122, 122, 122, 122, 121, 121, 120, 120, 120, 119,
- /* 1120 */ 116, 451, 1034, 1036, 1516, 1518, 13, 13, 1344, 1559,
- /* 1130 */ 416, 13, 13, 487, 1394, 285, 487, 974, 1440, 288,
- /* 1140 */ 288, 201, 570, 421, 320, 568, 554, 1230, 500, 492,
- /* 1150 */ 416, 577, 574, 489, 199, 534, 1255, 125, 114, 80,
- /* 1160 */ 1234, 1234, 1067, 1070, 1057, 1057, 123, 123, 124, 124,
- /* 1170 */ 124, 124, 577, 548, 55, 55, 577, 228, 126, 80,
- /* 1180 */ 1234, 1234, 1067, 1070, 1057, 1057, 123, 123, 124, 124,
- /* 1190 */ 124, 124, 547, 353, 1044, 56, 56, 1516, 1581, 15,
- /* 1200 */ 15, 1186, 6, 974, 457, 1230, 500, 1555, 444, 287,
- /* 1210 */ 226, 1035, 555, 324, 377, 1034, 122, 122, 122, 122,
- /* 1220 */ 121, 121, 120, 120, 120, 119, 116, 451, 1034, 1280,
- /* 1230 */ 149, 528, 344, 228, 562, 305, 122, 122, 122, 122,
- /* 1240 */ 121, 121, 120, 120, 120, 119, 116, 451, 1034, 1036,
- /* 1250 */ 577, 1340, 1131, 443, 1186, 535, 416, 577, 1579, 974,
- /* 1260 */ 422, 177, 6, 501, 288, 288, 288, 288, 1132, 288,
- /* 1270 */ 288, 233, 1112, 43, 43, 577, 1112, 574, 222, 574,
- /* 1280 */ 57, 57, 574, 1133, 577, 80, 1234, 1234, 1067, 1070,
- /* 1290 */ 1057, 1057, 123, 123, 124, 124, 124, 124, 44, 44,
- /* 1300 */ 577, 1578, 577, 222, 577, 6, 565, 58, 58, 577,
- /* 1310 */ 495, 111, 569, 577, 4, 577, 463, 577, 265, 1249,
- /* 1320 */ 463, 465, 100, 59, 59, 60, 60, 61, 61, 572,
- /* 1330 */ 297, 413, 62, 62, 297, 577, 45, 45, 46, 46,
- /* 1340 */ 47, 47, 122, 122, 122, 122, 121, 121, 120, 120,
- /* 1350 */ 120, 119, 116, 451, 452, 577, 1230, 577, 49, 49,
- /* 1360 */ 577, 474, 577, 478, 111, 569, 566, 4, 577, 988,
- /* 1370 */ 577, 413, 485, 413, 577, 325, 144, 989, 50, 50,
- /* 1380 */ 63, 63, 572, 64, 64, 65, 65, 86, 213, 319,
- /* 1390 */ 1229, 14, 14, 66, 66, 1044, 8, 131, 131, 413,
- /* 1400 */ 97, 109, 109, 1633, 259, 915, 98, 452, 108, 110,
- /* 1410 */ 106, 452, 579, 578, 1230, 113, 1034, 577, 949, 566,
- /* 1420 */ 577, 893, 577, 948, 217, 152, 897, 38, 530, 1034,
- /* 1430 */ 536, 328, 473, 544, 320, 568, 577, 1149, 543, 402,
- /* 1440 */ 132, 132, 290, 67, 67, 52, 52, 30, 1044, 1034,
- /* 1450 */ 1036, 1037, 27, 577, 109, 109, 342, 905, 904, 68,
- /* 1460 */ 68, 237, 110, 577, 452, 579, 578, 475, 343, 1034,
- /* 1470 */ 100, 1385, 486, 420, 293, 577, 69, 69, 17, 893,
- /* 1480 */ 1384, 31, 1034, 1606, 1197, 454, 53, 53, 292, 111,
- /* 1490 */ 569, 300, 4, 398, 398, 397, 277, 395, 163, 163,
- /* 1500 */ 862, 466, 1034, 1036, 1037, 27, 1347, 572, 323, 1158,
- /* 1510 */ 577, 217, 1562, 577, 234, 1026, 327, 264, 338, 577,
- /* 1520 */ 426, 480, 577, 264, 326, 577, 1535, 482, 577, 264,
- /* 1530 */ 1595, 577, 452, 164, 164, 1097, 76, 76, 577, 555,
- /* 1540 */ 912, 913, 54, 54, 566, 72, 72, 577, 134, 134,
- /* 1550 */ 564, 73, 73, 577, 161, 161, 236, 348, 544, 100,
- /* 1560 */ 280, 136, 136, 545, 169, 1621, 506, 142, 261, 1534,
- /* 1570 */ 130, 130, 577, 1044, 577, 399, 162, 162, 490, 109,
- /* 1580 */ 109, 577, 239, 363, 235, 100, 349, 110, 577, 452,
- /* 1590 */ 579, 578, 577, 1097, 1034, 156, 156, 140, 140, 111,
- /* 1600 */ 569, 1093, 4, 261, 139, 139, 493, 1034, 577, 991,
- /* 1610 */ 992, 137, 137, 577, 1038, 138, 138, 572, 979, 415,
- /* 1620 */ 264, 946, 876, 113, 150, 320, 568, 1034, 1036, 1037,
- /* 1630 */ 27, 75, 75, 947, 577, 113, 77, 77, 494, 577,
- /* 1640 */ 211, 577, 452, 1109, 1109, 1108, 1108, 1381, 458, 354,
- /* 1650 */ 357, 1364, 359, 361, 566, 1328, 1312, 74, 74, 368,
- /* 1660 */ 378, 1439, 42, 42, 48, 48, 1367, 1379, 544, 563,
- /* 1670 */ 1445, 1293, 1038, 543, 1284, 1197, 454, 1283, 312, 292,
- /* 1680 */ 1271, 313, 1270, 1044, 398, 398, 397, 277, 395, 109,
- /* 1690 */ 109, 862, 1272, 314, 1614, 11, 219, 110, 232, 452,
- /* 1700 */ 579, 578, 1426, 1421, 1034, 234, 295, 327, 1431, 1414,
- /* 1710 */ 340, 341, 484, 511, 1430, 326, 301, 1034, 1617, 1249,
- /* 1720 */ 406, 223, 1311, 371, 346, 179, 1507, 1506, 1376, 204,
- /* 1730 */ 1377, 567, 230, 268, 1554, 1246, 393, 1034, 1036, 1037,
- /* 1740 */ 27, 218, 1375, 1552, 292, 1374, 424, 236, 85, 398,
- /* 1750 */ 398, 397, 277, 395, 205, 169, 862, 215, 142, 111,
- /* 1760 */ 569, 174, 4, 188, 181, 468, 183, 469, 184, 241,
- /* 1770 */ 234, 504, 327, 35, 185, 235, 186, 572, 111, 569,
- /* 1780 */ 326, 4, 1427, 243, 98, 1512, 404, 1433, 1432, 81,
- /* 1790 */ 84, 36, 1435, 476, 407, 192, 572, 1501, 491, 91,
- /* 1800 */ 499, 247, 452, 249, 1523, 251, 352, 281, 196, 502,
- /* 1810 */ 415, 356, 236, 252, 566, 1273, 320, 568, 253, 520,
- /* 1820 */ 169, 452, 439, 142, 409, 93, 1331, 1330, 1329, 897,
- /* 1830 */ 224, 1600, 441, 566, 1301, 442, 266, 1632, 529, 458,
- /* 1840 */ 235, 410, 1631, 1044, 1322, 1300, 370, 1299, 1321, 109,
- /* 1850 */ 109, 953, 1630, 310, 311, 267, 376, 110, 1586, 452,
- /* 1860 */ 579, 578, 1044, 445, 1034, 128, 1585, 555, 109, 109,
- /* 1870 */ 79, 569, 385, 4, 1357, 415, 110, 1034, 452, 579,
- /* 1880 */ 578, 320, 568, 1034, 10, 387, 105, 1399, 572, 111,
- /* 1890 */ 569, 1398, 4, 1356, 99, 210, 1034, 1034, 1036, 1037,
- /* 1900 */ 27, 539, 391, 557, 458, 392, 318, 572, 1487, 34,
- /* 1910 */ 581, 1203, 276, 452, 279, 582, 1034, 1036, 1037, 27,
- /* 1920 */ 278, 1268, 1263, 165, 1539, 566, 1540, 1538, 147, 166,
- /* 1930 */ 849, 308, 452, 417, 453, 418, 212, 178, 1537, 167,
- /* 1940 */ 322, 145, 220, 231, 566, 221, 78, 1107, 330, 180,
- /* 1950 */ 1105, 170, 182, 238, 1044, 1229, 929, 242, 339, 1121,
- /* 1960 */ 109, 109, 187, 171, 172, 427, 189, 87, 110, 88,
- /* 1970 */ 452, 579, 578, 1044, 89, 1034, 429, 90, 173, 109,
- /* 1980 */ 109, 244, 1124, 245, 1120, 158, 18, 110, 1034, 452,
- /* 1990 */ 579, 578, 246, 350, 1034, 556, 434, 248, 264, 498,
- /* 2000 */ 1243, 250, 37, 1113, 193, 194, 864, 1034, 1034, 1036,
- /* 2010 */ 1037, 27, 503, 372, 254, 507, 195, 92, 19, 512,
- /* 2020 */ 364, 20, 895, 94, 367, 309, 175, 1034, 1036, 1037,
- /* 2030 */ 27, 908, 159, 515, 95, 522, 96, 1191, 160, 1073,
- /* 2040 */ 1160, 39, 225, 1159, 284, 286, 198, 263, 113, 977,
- /* 2050 */ 1177, 1179, 1181, 21, 983, 22, 1165, 7, 33, 1185,
- /* 2060 */ 23, 24, 1184, 25, 551, 26, 202, 100, 1088, 102,
- /* 2070 */ 1074, 1072, 1076, 1130, 1077, 1129, 269, 270, 28, 40,
- /* 2080 */ 942, 1039, 877, 103, 112, 573, 29, 396, 1199, 271,
- /* 2090 */ 168, 141, 272, 1623, 1198, 1622,
+ /* 0 */ 587, 119, 116, 234, 587, 1307, 1298, 587, 119, 116,
+ /* 10 */ 234, 587, 491, 587, 1298, 587, 589, 1639, 589, 587,
+ /* 20 */ 422, 541, 1560, 42, 42, 1317, 1295, 42, 42, 388,
+ /* 30 */ 42, 42, 562, 999, 72, 72, 72, 72, 72, 72,
+ /* 40 */ 17, 1000, 71, 71, 16, 16, 1310, 126, 127, 81,
+ /* 50 */ 1243, 1243, 1079, 1082, 1069, 1069, 124, 124, 125, 125,
+ /* 60 */ 125, 125, 422, 493, 1270, 1, 1, 593, 2, 1274,
+ /* 70 */ 1345, 569, 1324, 569, 326, 548, 144, 1350, 1350, 543,
+ /* 80 */ 1345, 568, 432, 1361, 119, 116, 234, 301, 542, 126,
+ /* 90 */ 127, 81, 1243, 1243, 1079, 1082, 1069, 1069, 124, 124,
+ /* 100 */ 125, 125, 125, 125, 394, 382, 123, 123, 123, 123,
+ /* 110 */ 122, 122, 121, 121, 121, 120, 117, 459, 294, 294,
+ /* 120 */ 384, 1600, 387, 294, 294, 1602, 334, 386, 1600, 556,
+ /* 130 */ 1219, 584, 1190, 422, 1190, 9, 584, 270, 1123, 102,
+ /* 140 */ 267, 231, 1123, 147, 441, 245, 1589, 389, 123, 123,
+ /* 150 */ 123, 123, 122, 122, 121, 121, 121, 120, 117, 459,
+ /* 160 */ 126, 127, 81, 1243, 1243, 1079, 1082, 1069, 1069, 124,
+ /* 170 */ 124, 125, 125, 125, 125, 1239, 505, 463, 122, 122,
+ /* 180 */ 121, 121, 121, 120, 117, 459, 128, 1219, 1220, 1219,
+ /* 190 */ 123, 123, 123, 123, 122, 122, 121, 121, 121, 120,
+ /* 200 */ 117, 459, 119, 116, 234, 260, 227, 422, 523, 520,
+ /* 210 */ 519, 125, 125, 125, 125, 118, 1524, 195, 518, 123,
+ /* 220 */ 123, 123, 123, 122, 122, 121, 121, 121, 120, 117,
+ /* 230 */ 459, 1588, 587, 1239, 126, 127, 81, 1243, 1243, 1079,
+ /* 240 */ 1082, 1069, 1069, 124, 124, 125, 125, 125, 125, 422,
+ /* 250 */ 585, 587, 954, 954, 84, 72, 72, 1219, 83, 123,
+ /* 260 */ 123, 123, 123, 122, 122, 121, 121, 121, 120, 117,
+ /* 270 */ 459, 581, 581, 581, 72, 72, 126, 127, 81, 1243,
+ /* 280 */ 1243, 1079, 1082, 1069, 1069, 124, 124, 125, 125, 125,
+ /* 290 */ 125, 459, 321, 123, 123, 123, 123, 122, 122, 121,
+ /* 300 */ 121, 121, 120, 117, 459, 121, 121, 121, 120, 117,
+ /* 310 */ 459, 569, 179, 1309, 1219, 1220, 1219, 1185, 12, 448,
+ /* 320 */ 422, 125, 125, 125, 125, 1219, 179, 395, 552, 391,
+ /* 330 */ 1185, 280, 279, 1185, 99, 123, 123, 123, 123, 122,
+ /* 340 */ 122, 121, 121, 121, 120, 117, 459, 126, 127, 81,
+ /* 350 */ 1243, 1243, 1079, 1082, 1069, 1069, 124, 124, 125, 125,
+ /* 360 */ 125, 125, 482, 352, 1219, 1166, 1674, 1219, 1674, 123,
+ /* 370 */ 123, 123, 123, 122, 122, 121, 121, 121, 120, 117,
+ /* 380 */ 459, 1185, 1219, 1220, 1219, 260, 1219, 551, 523, 520,
+ /* 390 */ 519, 208, 559, 1365, 1185, 587, 481, 1185, 518, 149,
+ /* 400 */ 1645, 1066, 1066, 1080, 1083, 584, 123, 123, 123, 123,
+ /* 410 */ 122, 122, 121, 121, 121, 120, 117, 459, 134, 134,
+ /* 420 */ 472, 1219, 1220, 1219, 1219, 1220, 1219, 535, 535, 422,
+ /* 430 */ 876, 114, 6, 367, 196, 562, 1219, 457, 457, 457,
+ /* 440 */ 1616, 560, 560, 1219, 1220, 1219, 6, 1164, 456, 455,
+ /* 450 */ 422, 550, 586, 356, 524, 219, 126, 127, 81, 1243,
+ /* 460 */ 1243, 1079, 1082, 1069, 1069, 124, 124, 125, 125, 125,
+ /* 470 */ 125, 422, 229, 534, 1219, 901, 1070, 126, 127, 81,
+ /* 480 */ 1243, 1243, 1079, 1082, 1069, 1069, 124, 124, 125, 125,
+ /* 490 */ 125, 125, 480, 1219, 1220, 1219, 1251, 1251, 126, 127,
+ /* 500 */ 81, 1243, 1243, 1079, 1082, 1069, 1069, 124, 124, 125,
+ /* 510 */ 125, 125, 125, 145, 385, 123, 123, 123, 123, 122,
+ /* 520 */ 122, 121, 121, 121, 120, 117, 459, 1219, 1453, 86,
+ /* 530 */ 587, 1219, 1220, 1219, 1328, 1101, 123, 123, 123, 123,
+ /* 540 */ 122, 122, 121, 121, 121, 120, 117, 459, 563, 563,
+ /* 550 */ 491, 470, 471, 72, 72, 565, 411, 123, 123, 123,
+ /* 560 */ 123, 122, 122, 121, 121, 121, 120, 117, 459, 470,
+ /* 570 */ 469, 325, 578, 1516, 456, 455, 547, 587, 422, 1348,
+ /* 580 */ 1348, 213, 894, 1248, 1219, 1220, 1219, 1219, 1250, 399,
+ /* 590 */ 322, 294, 294, 1595, 414, 101, 1249, 6, 436, 422,
+ /* 600 */ 136, 136, 232, 1203, 584, 126, 127, 81, 1243, 1243,
+ /* 610 */ 1079, 1082, 1069, 1069, 124, 124, 125, 125, 125, 125,
+ /* 620 */ 422, 489, 1251, 1251, 1057, 304, 126, 127, 81, 1243,
+ /* 630 */ 1243, 1079, 1082, 1069, 1069, 124, 124, 125, 125, 125,
+ /* 640 */ 125, 289, 470, 33, 1219, 1220, 1219, 126, 127, 81,
+ /* 650 */ 1243, 1243, 1079, 1082, 1069, 1069, 124, 124, 125, 125,
+ /* 660 */ 125, 125, 1529, 213, 123, 123, 123, 123, 122, 122,
+ /* 670 */ 121, 121, 121, 120, 117, 459, 420, 897, 1593, 1219,
+ /* 680 */ 1529, 1531, 6, 1219, 299, 123, 123, 123, 123, 122,
+ /* 690 */ 122, 121, 121, 121, 120, 117, 459, 531, 312, 908,
+ /* 700 */ 312, 1453, 119, 116, 234, 393, 123, 123, 123, 123,
+ /* 710 */ 122, 122, 121, 121, 121, 120, 117, 459, 1056, 294,
+ /* 720 */ 294, 863, 864, 865, 866, 960, 587, 422, 965, 1594,
+ /* 730 */ 959, 1040, 584, 6, 897, 1045, 1219, 1220, 1219, 1044,
+ /* 740 */ 1219, 1220, 1219, 120, 117, 459, 1676, 406, 422, 56,
+ /* 750 */ 56, 202, 1044, 1529, 126, 127, 81, 1243, 1243, 1079,
+ /* 760 */ 1082, 1069, 1069, 124, 124, 125, 125, 125, 125, 422,
+ /* 770 */ 587, 437, 1044, 1046, 145, 126, 127, 81, 1243, 1243,
+ /* 780 */ 1079, 1082, 1069, 1069, 124, 124, 125, 125, 125, 125,
+ /* 790 */ 1469, 5, 1570, 72, 72, 1219, 126, 127, 81, 1243,
+ /* 800 */ 1243, 1079, 1082, 1069, 1069, 124, 124, 125, 125, 125,
+ /* 810 */ 125, 1453, 365, 123, 123, 123, 123, 122, 122, 121,
+ /* 820 */ 121, 121, 120, 117, 459, 1219, 587, 1453, 380, 1613,
+ /* 830 */ 454, 1219, 325, 578, 123, 123, 123, 123, 122, 122,
+ /* 840 */ 121, 121, 121, 120, 117, 459, 1035, 587, 510, 72,
+ /* 850 */ 72, 587, 1219, 1220, 1219, 123, 123, 123, 123, 122,
+ /* 860 */ 122, 121, 121, 121, 120, 117, 459, 426, 325, 578,
+ /* 870 */ 13, 13, 587, 515, 57, 57, 360, 1056, 363, 1572,
+ /* 880 */ 987, 438, 1219, 1220, 1219, 434, 458, 422, 1219, 1220,
+ /* 890 */ 1219, 105, 214, 425, 1045, 15, 15, 506, 1044, 467,
+ /* 900 */ 350, 477, 337, 264, 1166, 1675, 1568, 1675, 422, 544,
+ /* 910 */ 986, 1044, 108, 3, 126, 127, 81, 1243, 1243, 1079,
+ /* 920 */ 1082, 1069, 1069, 124, 124, 125, 125, 125, 125, 422,
+ /* 930 */ 329, 1044, 1046, 1386, 320, 126, 127, 81, 1243, 1243,
+ /* 940 */ 1079, 1082, 1069, 1069, 124, 124, 125, 125, 125, 125,
+ /* 950 */ 502, 464, 330, 1219, 499, 497, 126, 115, 81, 1243,
+ /* 960 */ 1243, 1079, 1082, 1069, 1069, 124, 124, 125, 125, 125,
+ /* 970 */ 125, 491, 427, 123, 123, 123, 123, 122, 122, 121,
+ /* 980 */ 121, 121, 120, 117, 459, 101, 1164, 333, 370, 1126,
+ /* 990 */ 1126, 507, 308, 384, 123, 123, 123, 123, 122, 122,
+ /* 1000 */ 121, 121, 121, 120, 117, 459, 587, 1398, 98, 545,
+ /* 1010 */ 1219, 1220, 1219, 1356, 342, 123, 123, 123, 123, 122,
+ /* 1020 */ 122, 121, 121, 121, 120, 117, 459, 294, 294, 13,
+ /* 1030 */ 13, 1142, 558, 405, 1264, 587, 422, 213, 546, 1185,
+ /* 1040 */ 584, 155, 340, 213, 439, 1035, 307, 1143, 294, 294,
+ /* 1050 */ 408, 557, 1185, 145, 303, 1185, 409, 422, 44, 44,
+ /* 1060 */ 1196, 584, 1144, 565, 127, 81, 1243, 1243, 1079, 1082,
+ /* 1070 */ 1069, 1069, 124, 124, 125, 125, 125, 125, 338, 587,
+ /* 1080 */ 341, 150, 587, 1299, 428, 575, 81, 1243, 1243, 1079,
+ /* 1090 */ 1082, 1069, 1069, 124, 124, 125, 125, 125, 125, 350,
+ /* 1100 */ 1397, 491, 58, 58, 1587, 13, 13, 1453, 288, 288,
+ /* 1110 */ 431, 325, 578, 1196, 587, 1265, 112, 579, 587, 4,
+ /* 1120 */ 442, 584, 123, 123, 123, 123, 122, 122, 121, 121,
+ /* 1130 */ 121, 120, 117, 459, 582, 510, 1222, 45, 45, 431,
+ /* 1140 */ 587, 13, 13, 123, 123, 123, 123, 122, 122, 121,
+ /* 1150 */ 121, 121, 120, 117, 459, 238, 311, 1293, 592, 460,
+ /* 1160 */ 1274, 476, 339, 13, 13, 326, 587, 144, 1384, 112,
+ /* 1170 */ 579, 576, 4, 587, 1361, 587, 309, 452, 447, 336,
+ /* 1180 */ 1559, 145, 295, 295, 570, 580, 428, 582, 12, 13,
+ /* 1190 */ 13, 1468, 294, 294, 1222, 584, 72, 72, 59, 59,
+ /* 1200 */ 1056, 8, 587, 1259, 205, 584, 110, 110, 211, 294,
+ /* 1210 */ 294, 1142, 460, 536, 111, 384, 460, 588, 460, 294,
+ /* 1220 */ 294, 1044, 584, 587, 576, 52, 52, 1143, 587, 380,
+ /* 1230 */ 1613, 917, 584, 569, 1044, 291, 245, 985, 554, 325,
+ /* 1240 */ 578, 571, 1144, 553, 384, 1467, 60, 60, 294, 294,
+ /* 1250 */ 538, 61, 61, 1056, 1044, 1046, 1047, 28, 587, 110,
+ /* 1260 */ 110, 584, 537, 158, 527, 937, 498, 111, 463, 460,
+ /* 1270 */ 588, 460, 918, 587, 1044, 938, 112, 579, 1644, 4,
+ /* 1280 */ 926, 62, 62, 380, 1613, 294, 294, 1044, 1618, 1207,
+ /* 1290 */ 462, 587, 154, 285, 582, 152, 13, 13, 584, 403,
+ /* 1300 */ 403, 402, 282, 400, 572, 213, 873, 1044, 1046, 1047,
+ /* 1310 */ 28, 206, 382, 587, 13, 13, 130, 1360, 465, 460,
+ /* 1320 */ 239, 497, 332, 587, 999, 587, 1587, 985, 444, 564,
+ /* 1330 */ 331, 576, 1000, 233, 587, 889, 63, 63, 1121, 294,
+ /* 1340 */ 294, 587, 510, 431, 510, 554, 46, 46, 47, 47,
+ /* 1350 */ 555, 451, 584, 474, 384, 1587, 587, 48, 48, 985,
+ /* 1360 */ 1056, 544, 241, 419, 50, 50, 110, 110, 587, 1185,
+ /* 1370 */ 172, 429, 180, 143, 111, 587, 460, 588, 460, 51,
+ /* 1380 */ 51, 1044, 1185, 112, 579, 1185, 4, 1523, 497, 1357,
+ /* 1390 */ 240, 64, 64, 889, 1044, 587, 1207, 462, 65, 65,
+ /* 1400 */ 285, 582, 156, 418, 417, 944, 403, 403, 402, 282,
+ /* 1410 */ 400, 587, 212, 873, 1044, 1046, 1047, 28, 66, 66,
+ /* 1420 */ 349, 587, 945, 233, 587, 421, 460, 239, 1576, 332,
+ /* 1430 */ 510, 325, 578, 285, 14, 14, 343, 331, 576, 403,
+ /* 1440 */ 403, 402, 282, 400, 67, 67, 873, 132, 132, 985,
+ /* 1450 */ 112, 579, 554, 4, 468, 587, 1548, 553, 482, 352,
+ /* 1460 */ 239, 545, 332, 405, 1165, 1587, 587, 1056, 582, 241,
+ /* 1470 */ 331, 587, 510, 110, 110, 1353, 587, 172, 133, 133,
+ /* 1480 */ 143, 111, 1592, 460, 588, 460, 6, 310, 1044, 68,
+ /* 1490 */ 68, 587, 483, 460, 53, 53, 587, 240, 1327, 69,
+ /* 1500 */ 69, 1044, 241, 325, 578, 576, 263, 262, 261, 227,
+ /* 1510 */ 172, 1238, 587, 143, 70, 70, 347, 358, 475, 54,
+ /* 1520 */ 54, 1044, 1046, 1047, 28, 270, 112, 579, 419, 4,
+ /* 1530 */ 240, 540, 421, 587, 1056, 165, 165, 484, 325, 578,
+ /* 1540 */ 110, 110, 964, 587, 582, 1265, 298, 419, 111, 488,
+ /* 1550 */ 460, 588, 460, 587, 1591, 1044, 166, 166, 6, 419,
+ /* 1560 */ 473, 468, 587, 1239, 473, 421, 77, 77, 1044, 460,
+ /* 1570 */ 302, 325, 578, 587, 302, 587, 55, 55, 293, 231,
+ /* 1580 */ 328, 576, 324, 587, 98, 73, 73, 1547, 1044, 1046,
+ /* 1590 */ 1047, 28, 419, 487, 468, 587, 135, 135, 74, 74,
+ /* 1600 */ 87, 218, 80, 579, 242, 4, 163, 163, 264, 466,
+ /* 1610 */ 1056, 587, 1170, 587, 546, 587, 110, 110, 137, 137,
+ /* 1620 */ 582, 1239, 904, 587, 111, 31, 460, 588, 460, 221,
+ /* 1630 */ 222, 1044, 222, 162, 131, 131, 164, 164, 157, 157,
+ /* 1640 */ 109, 153, 107, 39, 1044, 460, 141, 141, 587, 495,
+ /* 1650 */ 587, 567, 587, 1619, 593, 2, 1274, 576, 485, 32,
+ /* 1660 */ 1161, 326, 407, 144, 1044, 1046, 1047, 28, 916, 915,
+ /* 1670 */ 1361, 140, 140, 138, 138, 139, 139, 427, 112, 579,
+ /* 1680 */ 904, 4, 305, 960, 446, 587, 1056, 587, 959, 371,
+ /* 1690 */ 587, 378, 110, 110, 1108, 348, 582, 101, 296, 587,
+ /* 1700 */ 111, 377, 460, 588, 460, 294, 294, 1044, 76, 76,
+ /* 1710 */ 78, 78, 587, 75, 75, 1037, 1048, 269, 584, 500,
+ /* 1720 */ 1044, 460, 43, 43, 490, 244, 269, 566, 492, 353,
+ /* 1730 */ 269, 101, 245, 576, 354, 49, 49, 516, 503, 266,
+ /* 1740 */ 1044, 1046, 1047, 28, 504, 368, 161, 101, 101, 496,
+ /* 1750 */ 923, 924, 1108, 1104, 990, 266, 269, 1002, 1003, 532,
+ /* 1760 */ 1394, 359, 1056, 526, 463, 957, 362, 114, 110, 110,
+ /* 1770 */ 1120, 1120, 1119, 1119, 1048, 887, 111, 151, 460, 588,
+ /* 1780 */ 460, 443, 958, 1044, 114, 364, 366, 278, 297, 379,
+ /* 1790 */ 529, 374, 528, 265, 1341, 1325, 1044, 1326, 204, 370,
+ /* 1800 */ 373, 383, 1407, 1452, 1380, 1607, 1392, 573, 574, 1457,
+ /* 1810 */ 511, 1306, 1297, 1296, 404, 1284, 1044, 1046, 1047, 28,
+ /* 1820 */ 1283, 1633, 1285, 1626, 286, 216, 237, 11, 1439, 1377,
+ /* 1830 */ 317, 318, 319, 1434, 300, 345, 346, 1427, 224, 577,
+ /* 1840 */ 306, 351, 494, 223, 209, 521, 1389, 1390, 398, 1444,
+ /* 1850 */ 1443, 412, 376, 1324, 1520, 228, 1519, 1388, 1387, 1629,
+ /* 1860 */ 1259, 182, 235, 273, 1567, 1565, 1256, 86, 430, 1525,
+ /* 1870 */ 220, 193, 177, 478, 186, 82, 1440, 479, 188, 189,
+ /* 1880 */ 210, 246, 190, 191, 514, 85, 248, 99, 1448, 410,
+ /* 1890 */ 501, 197, 252, 92, 486, 413, 254, 1514, 509, 287,
+ /* 1900 */ 256, 201, 512, 415, 361, 257, 36, 530, 445, 1286,
+ /* 1910 */ 1446, 258, 1335, 1344, 1343, 94, 1342, 908, 1334, 1445,
+ /* 1920 */ 37, 229, 449, 1314, 1643, 450, 1642, 271, 272, 375,
+ /* 1930 */ 453, 416, 129, 1313, 1412, 1312, 381, 1641, 1370, 565,
+ /* 1940 */ 1411, 315, 1536, 10, 357, 392, 106, 1501, 316, 100,
+ /* 1950 */ 323, 549, 35, 590, 1213, 284, 281, 283, 591, 1281,
+ /* 1960 */ 1275, 1552, 1553, 539, 167, 1612, 168, 169, 859, 1551,
+ /* 1970 */ 390, 215, 1369, 396, 397, 423, 181, 1598, 1550, 1597,
+ /* 1980 */ 148, 170, 424, 225, 226, 79, 313, 461, 217, 327,
+ /* 1990 */ 183, 184, 236, 1118, 146, 1116, 335, 185, 173, 1238,
+ /* 2000 */ 243, 940, 187, 344, 1132, 247, 192, 174, 175, 433,
+ /* 2010 */ 88, 435, 89, 194, 90, 91, 176, 249, 1135, 1131,
+ /* 2020 */ 159, 250, 18, 251, 253, 355, 440, 1253, 1124, 255,
+ /* 2030 */ 269, 198, 508, 199, 38, 875, 513, 377, 259, 517,
+ /* 2040 */ 200, 522, 93, 19, 178, 369, 20, 372, 906, 95,
+ /* 2050 */ 525, 160, 533, 314, 919, 96, 1201, 1085, 230, 1172,
+ /* 2060 */ 97, 21, 40, 1171, 290, 292, 994, 268, 203, 988,
+ /* 2070 */ 114, 1187, 22, 23, 24, 1191, 7, 1189, 25, 1195,
+ /* 2080 */ 1194, 1176, 26, 34, 561, 27, 103, 207, 101, 104,
+ /* 2090 */ 1099, 1086, 1084, 1088, 1141, 1089, 1140, 274, 275, 29,
+ /* 2100 */ 41, 953, 1049, 888, 113, 30, 583, 401, 1209, 276,
+ /* 2110 */ 171, 142, 277, 1634, 1208,
};
static const YYCODETYPE yy_lookahead[] = {
- /* 0 */ 195, 195, 195, 215, 195, 276, 277, 278, 187, 188,
- /* 10 */ 189, 190, 191, 192, 276, 277, 278, 208, 197, 19,
- /* 20 */ 199, 189, 190, 191, 192, 218, 219, 206, 217, 197,
- /* 30 */ 195, 199, 32, 206, 195, 297, 225, 218, 206, 230,
- /* 40 */ 40, 232, 207, 195, 206, 240, 46, 47, 48, 49,
+ /* 0 */ 196, 277, 278, 279, 196, 219, 196, 196, 277, 278,
+ /* 10 */ 279, 196, 196, 196, 196, 196, 206, 218, 208, 196,
+ /* 20 */ 20, 196, 298, 219, 220, 226, 208, 219, 220, 222,
+ /* 30 */ 219, 220, 196, 33, 219, 220, 219, 220, 219, 220,
+ /* 40 */ 23, 41, 219, 220, 219, 220, 219, 47, 48, 49,
/* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
- /* 60 */ 60, 195, 241, 242, 276, 277, 278, 218, 241, 242,
- /* 70 */ 195, 195, 221, 241, 242, 254, 270, 195, 195, 241,
- /* 80 */ 242, 254, 206, 208, 218, 219, 254, 195, 240, 268,
- /* 90 */ 218, 221, 254, 195, 218, 219, 258, 259, 271, 233,
- /* 100 */ 268, 218, 219, 298, 265, 105, 106, 107, 108, 109,
- /* 110 */ 110, 111, 112, 113, 114, 115, 116, 241, 242, 303,
- /* 120 */ 304, 300, 22, 316, 317, 19, 195, 276, 277, 278,
- /* 130 */ 254, 255, 300, 105, 106, 107, 108, 109, 110, 111,
- /* 140 */ 112, 113, 114, 115, 116, 19, 276, 277, 278, 218,
- /* 150 */ 219, 25, 46, 47, 48, 49, 50, 51, 52, 53,
- /* 160 */ 54, 55, 56, 57, 58, 59, 60, 285, 49, 50,
- /* 170 */ 51, 52, 46, 47, 48, 49, 50, 51, 52, 53,
- /* 180 */ 54, 55, 56, 57, 58, 59, 60, 111, 112, 113,
- /* 190 */ 114, 115, 116, 195, 195, 89, 19, 91, 72, 316,
- /* 200 */ 116, 318, 310, 311, 205, 62, 207, 315, 195, 109,
- /* 210 */ 110, 105, 106, 107, 108, 109, 110, 111, 112, 113,
- /* 220 */ 114, 115, 116, 109, 110, 111, 112, 113, 114, 115,
- /* 230 */ 116, 105, 106, 107, 108, 109, 110, 111, 112, 113,
- /* 240 */ 114, 115, 116, 124, 131, 132, 195, 316, 317, 109,
- /* 250 */ 110, 19, 109, 110, 195, 57, 58, 59, 60, 61,
- /* 260 */ 79, 118, 119, 120, 121, 195, 123, 76, 270, 218,
- /* 270 */ 219, 90, 232, 92, 131, 84, 95, 84, 46, 47,
- /* 280 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- /* 290 */ 58, 59, 60, 26, 27, 118, 119, 157, 158, 240,
- /* 300 */ 157, 158, 70, 105, 106, 107, 108, 109, 110, 111,
- /* 310 */ 112, 113, 114, 115, 116, 195, 123, 57, 58, 59,
- /* 320 */ 60, 130, 19, 310, 311, 148, 76, 24, 315, 62,
- /* 330 */ 149, 280, 195, 142, 143, 142, 143, 105, 106, 107,
- /* 340 */ 108, 109, 110, 111, 112, 113, 114, 115, 116, 46,
- /* 350 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 360 */ 57, 58, 59, 60, 19, 105, 106, 107, 108, 109,
- /* 370 */ 110, 111, 112, 113, 114, 115, 116, 25, 308, 309,
- /* 380 */ 130, 131, 132, 195, 264, 25, 119, 120, 121, 195,
- /* 390 */ 195, 46, 47, 48, 49, 50, 51, 52, 53, 54,
- /* 400 */ 55, 56, 57, 58, 59, 60, 218, 219, 105, 106,
- /* 410 */ 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
- /* 420 */ 84, 233, 195, 122, 120, 195, 125, 126, 127, 62,
- /* 430 */ 225, 79, 227, 168, 169, 19, 135, 62, 243, 23,
- /* 440 */ 235, 137, 75, 22, 92, 218, 219, 95, 218, 219,
- /* 450 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
- /* 460 */ 115, 116, 46, 47, 48, 49, 50, 51, 52, 53,
- /* 470 */ 54, 55, 56, 57, 58, 59, 60, 19, 142, 143,
- /* 480 */ 62, 23, 190, 62, 192, 255, 119, 120, 121, 197,
- /* 490 */ 195, 199, 195, 263, 119, 120, 121, 195, 206, 154,
- /* 500 */ 306, 306, 142, 143, 46, 47, 48, 49, 50, 51,
- /* 510 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 237,
- /* 520 */ 238, 105, 106, 107, 108, 109, 110, 111, 112, 113,
- /* 530 */ 114, 115, 116, 241, 242, 195, 234, 119, 120, 121,
- /* 540 */ 122, 120, 195, 125, 126, 127, 254, 271, 19, 62,
- /* 550 */ 203, 195, 23, 135, 62, 208, 22, 195, 218, 219,
- /* 560 */ 268, 264, 75, 105, 106, 107, 108, 109, 110, 111,
- /* 570 */ 112, 113, 114, 115, 116, 46, 47, 48, 49, 50,
- /* 580 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
- /* 590 */ 19, 195, 300, 228, 23, 255, 62, 215, 195, 243,
- /* 600 */ 212, 213, 214, 263, 309, 243, 119, 120, 121, 195,
- /* 610 */ 195, 119, 120, 121, 218, 219, 36, 46, 47, 48,
- /* 620 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
- /* 630 */ 59, 60, 218, 219, 105, 106, 107, 108, 109, 110,
- /* 640 */ 111, 112, 113, 114, 115, 116, 243, 155, 195, 69,
- /* 650 */ 124, 255, 195, 119, 120, 121, 11, 77, 62, 263,
- /* 660 */ 134, 19, 306, 237, 238, 23, 22, 195, 306, 62,
- /* 670 */ 22, 218, 219, 275, 22, 293, 105, 106, 107, 108,
- /* 680 */ 109, 110, 111, 112, 113, 114, 115, 116, 46, 47,
- /* 690 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- /* 700 */ 58, 59, 60, 19, 241, 242, 62, 23, 255, 306,
- /* 710 */ 62, 313, 314, 133, 62, 311, 120, 254, 111, 315,
- /* 720 */ 22, 264, 195, 212, 213, 214, 119, 120, 121, 228,
- /* 730 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
- /* 740 */ 56, 57, 58, 59, 60, 218, 219, 105, 106, 107,
- /* 750 */ 108, 109, 110, 111, 112, 113, 114, 115, 116, 215,
- /* 760 */ 62, 195, 195, 119, 120, 121, 294, 119, 120, 121,
- /* 770 */ 79, 119, 120, 121, 19, 242, 131, 132, 23, 130,
- /* 780 */ 131, 132, 255, 92, 218, 219, 95, 254, 206, 105,
- /* 790 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
- /* 800 */ 116, 46, 47, 48, 49, 50, 51, 52, 53, 54,
- /* 810 */ 55, 56, 57, 58, 59, 60, 19, 119, 120, 121,
- /* 820 */ 251, 255, 253, 241, 242, 241, 242, 195, 114, 115,
- /* 830 */ 116, 138, 288, 140, 141, 195, 254, 293, 254, 261,
- /* 840 */ 262, 206, 195, 46, 47, 48, 49, 50, 51, 52,
- /* 850 */ 53, 54, 55, 56, 57, 58, 59, 60, 218, 219,
- /* 860 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
- /* 870 */ 115, 116, 62, 16, 195, 195, 241, 242, 195, 228,
- /* 880 */ 22, 23, 195, 25, 7, 8, 9, 19, 19, 254,
- /* 890 */ 130, 131, 132, 24, 16, 255, 213, 214, 218, 219,
- /* 900 */ 118, 44, 105, 106, 107, 108, 109, 110, 111, 112,
- /* 910 */ 113, 114, 115, 116, 46, 47, 48, 49, 50, 51,
- /* 920 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 119,
- /* 930 */ 120, 121, 195, 111, 12, 255, 154, 80, 260, 82,
- /* 940 */ 195, 22, 23, 195, 25, 21, 195, 22, 23, 270,
- /* 950 */ 28, 206, 265, 210, 211, 218, 219, 147, 80, 162,
- /* 960 */ 82, 139, 104, 218, 219, 43, 144, 98, 44, 286,
- /* 970 */ 233, 19, 275, 105, 106, 107, 108, 109, 110, 111,
- /* 980 */ 112, 113, 114, 115, 116, 116, 241, 242, 66, 62,
- /* 990 */ 195, 122, 123, 124, 125, 126, 127, 128, 76, 254,
- /* 1000 */ 255, 49, 195, 134, 19, 246, 79, 83, 263, 24,
- /* 1010 */ 313, 314, 195, 218, 219, 256, 265, 90, 270, 92,
- /* 1020 */ 62, 164, 95, 104, 19, 218, 219, 62, 233, 104,
- /* 1030 */ 162, 46, 47, 48, 49, 50, 51, 52, 53, 54,
- /* 1040 */ 55, 56, 57, 58, 59, 60, 119, 120, 121, 195,
- /* 1050 */ 126, 46, 47, 48, 49, 50, 51, 52, 53, 54,
- /* 1060 */ 55, 56, 57, 58, 59, 60, 200, 311, 103, 195,
- /* 1070 */ 118, 315, 218, 219, 22, 23, 149, 119, 120, 121,
- /* 1080 */ 195, 25, 265, 195, 119, 120, 134, 233, 164, 124,
- /* 1090 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
- /* 1100 */ 115, 116, 137, 195, 206, 147, 195, 22, 195, 24,
- /* 1110 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
- /* 1120 */ 115, 116, 157, 158, 213, 214, 218, 219, 240, 195,
- /* 1130 */ 19, 218, 219, 195, 195, 23, 195, 25, 195, 241,
- /* 1140 */ 242, 233, 210, 211, 142, 143, 233, 62, 195, 283,
- /* 1150 */ 19, 195, 254, 287, 257, 19, 104, 46, 47, 48,
- /* 1160 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
- /* 1170 */ 59, 60, 195, 69, 218, 219, 195, 121, 47, 48,
- /* 1180 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
- /* 1190 */ 59, 60, 88, 240, 103, 218, 219, 286, 311, 218,
- /* 1200 */ 219, 97, 315, 147, 195, 120, 195, 195, 265, 258,
- /* 1210 */ 259, 120, 149, 195, 195, 124, 105, 106, 107, 108,
- /* 1220 */ 109, 110, 111, 112, 113, 114, 115, 116, 137, 206,
- /* 1230 */ 167, 206, 294, 121, 206, 294, 105, 106, 107, 108,
- /* 1240 */ 109, 110, 111, 112, 113, 114, 115, 116, 157, 158,
- /* 1250 */ 195, 240, 12, 234, 150, 119, 19, 195, 311, 147,
- /* 1260 */ 301, 302, 315, 290, 241, 242, 241, 242, 28, 241,
- /* 1270 */ 242, 15, 30, 218, 219, 195, 34, 254, 25, 254,
- /* 1280 */ 218, 219, 254, 43, 195, 48, 49, 50, 51, 52,
- /* 1290 */ 53, 54, 55, 56, 57, 58, 59, 60, 218, 219,
- /* 1300 */ 195, 311, 195, 25, 195, 315, 66, 218, 219, 195,
- /* 1310 */ 68, 19, 20, 195, 22, 195, 262, 195, 24, 63,
- /* 1320 */ 266, 246, 25, 218, 219, 218, 219, 218, 219, 37,
- /* 1330 */ 262, 256, 218, 219, 266, 195, 218, 219, 218, 219,
- /* 1340 */ 218, 219, 105, 106, 107, 108, 109, 110, 111, 112,
- /* 1350 */ 113, 114, 115, 116, 62, 195, 62, 195, 218, 219,
- /* 1360 */ 195, 246, 195, 246, 19, 20, 74, 22, 195, 32,
- /* 1370 */ 195, 256, 19, 256, 195, 195, 84, 40, 218, 219,
- /* 1380 */ 218, 219, 37, 218, 219, 218, 219, 153, 154, 246,
- /* 1390 */ 25, 218, 219, 218, 219, 103, 51, 218, 219, 256,
- /* 1400 */ 118, 109, 110, 23, 49, 25, 153, 62, 161, 117,
- /* 1410 */ 163, 119, 120, 121, 120, 25, 124, 195, 139, 74,
- /* 1420 */ 195, 62, 195, 144, 146, 22, 129, 24, 19, 137,
- /* 1430 */ 148, 195, 132, 88, 142, 143, 195, 23, 93, 25,
- /* 1440 */ 218, 219, 22, 218, 219, 218, 219, 22, 103, 157,
- /* 1450 */ 158, 159, 160, 195, 109, 110, 156, 123, 124, 218,
- /* 1460 */ 219, 24, 117, 195, 119, 120, 121, 132, 23, 124,
- /* 1470 */ 25, 195, 119, 118, 102, 195, 218, 219, 22, 120,
- /* 1480 */ 195, 56, 137, 0, 1, 2, 218, 219, 5, 19,
- /* 1490 */ 20, 156, 22, 10, 11, 12, 13, 14, 218, 219,
- /* 1500 */ 17, 195, 157, 158, 159, 160, 195, 37, 136, 100,
- /* 1510 */ 195, 146, 195, 195, 31, 23, 33, 25, 195, 195,
- /* 1520 */ 64, 23, 195, 25, 41, 195, 195, 23, 195, 25,
- /* 1530 */ 320, 195, 62, 218, 219, 62, 218, 219, 195, 149,
- /* 1540 */ 7, 8, 218, 219, 74, 218, 219, 195, 218, 219,
- /* 1550 */ 238, 218, 219, 195, 218, 219, 73, 23, 88, 25,
- /* 1560 */ 289, 218, 219, 93, 81, 145, 23, 84, 25, 195,
- /* 1570 */ 218, 219, 195, 103, 195, 193, 218, 219, 195, 109,
- /* 1580 */ 110, 195, 145, 23, 101, 25, 195, 117, 195, 119,
- /* 1590 */ 120, 121, 195, 120, 124, 218, 219, 218, 219, 19,
- /* 1600 */ 20, 23, 22, 25, 218, 219, 195, 137, 195, 86,
- /* 1610 */ 87, 218, 219, 195, 62, 218, 219, 37, 23, 136,
- /* 1620 */ 25, 23, 23, 25, 25, 142, 143, 157, 158, 159,
- /* 1630 */ 160, 218, 219, 23, 195, 25, 218, 219, 195, 195,
- /* 1640 */ 244, 195, 62, 157, 158, 157, 158, 195, 165, 195,
- /* 1650 */ 195, 257, 195, 195, 74, 195, 195, 218, 219, 195,
- /* 1660 */ 195, 195, 218, 219, 218, 219, 195, 195, 88, 195,
- /* 1670 */ 195, 195, 120, 93, 195, 1, 2, 195, 257, 5,
- /* 1680 */ 195, 257, 195, 103, 10, 11, 12, 13, 14, 109,
- /* 1690 */ 110, 17, 195, 257, 195, 245, 216, 117, 299, 119,
- /* 1700 */ 120, 121, 273, 269, 124, 31, 247, 33, 273, 269,
- /* 1710 */ 295, 248, 295, 222, 273, 41, 248, 137, 198, 63,
- /* 1720 */ 273, 231, 227, 221, 247, 299, 221, 221, 261, 251,
- /* 1730 */ 261, 282, 299, 145, 202, 39, 247, 157, 158, 159,
- /* 1740 */ 160, 245, 261, 202, 5, 261, 202, 73, 155, 10,
- /* 1750 */ 11, 12, 13, 14, 251, 81, 17, 154, 84, 19,
- /* 1760 */ 20, 46, 22, 22, 236, 18, 239, 202, 239, 239,
- /* 1770 */ 31, 18, 33, 272, 239, 101, 239, 37, 19, 20,
- /* 1780 */ 41, 22, 274, 201, 153, 285, 248, 274, 274, 296,
- /* 1790 */ 296, 272, 236, 248, 248, 236, 37, 248, 202, 161,
- /* 1800 */ 65, 201, 62, 201, 292, 201, 291, 202, 22, 223,
- /* 1810 */ 136, 202, 73, 201, 74, 202, 142, 143, 201, 118,
- /* 1820 */ 81, 62, 67, 84, 223, 22, 220, 220, 220, 129,
- /* 1830 */ 168, 314, 24, 74, 220, 116, 202, 226, 307, 165,
- /* 1840 */ 101, 223, 226, 103, 229, 222, 220, 220, 229, 109,
- /* 1850 */ 110, 111, 220, 284, 284, 94, 223, 117, 319, 119,
- /* 1860 */ 120, 121, 103, 85, 124, 152, 319, 149, 109, 110,
- /* 1870 */ 19, 20, 251, 22, 252, 136, 117, 137, 119, 120,
- /* 1880 */ 121, 142, 143, 124, 22, 202, 161, 267, 37, 19,
- /* 1890 */ 20, 267, 22, 252, 151, 250, 137, 157, 158, 159,
- /* 1900 */ 160, 150, 249, 144, 165, 248, 281, 37, 279, 25,
- /* 1910 */ 204, 13, 196, 62, 6, 194, 157, 158, 159, 160,
- /* 1920 */ 196, 194, 194, 209, 215, 74, 215, 215, 224, 209,
- /* 1930 */ 4, 224, 62, 305, 3, 305, 22, 302, 215, 209,
- /* 1940 */ 166, 16, 216, 15, 74, 216, 215, 23, 143, 155,
- /* 1950 */ 23, 133, 146, 24, 103, 25, 20, 148, 16, 1,
- /* 1960 */ 109, 110, 146, 133, 133, 64, 155, 56, 117, 56,
- /* 1970 */ 119, 120, 121, 103, 56, 124, 38, 56, 133, 109,
- /* 1980 */ 110, 35, 119, 145, 1, 5, 22, 117, 137, 119,
- /* 1990 */ 120, 121, 118, 164, 124, 144, 24, 45, 25, 42,
- /* 2000 */ 78, 145, 24, 71, 71, 118, 20, 137, 157, 158,
- /* 2010 */ 159, 160, 19, 134, 128, 70, 22, 22, 22, 70,
- /* 2020 */ 23, 22, 62, 22, 24, 70, 38, 157, 158, 159,
- /* 2030 */ 160, 29, 23, 99, 153, 22, 25, 23, 23, 23,
- /* 2040 */ 23, 22, 145, 100, 23, 23, 22, 35, 25, 147,
- /* 2050 */ 91, 89, 78, 35, 119, 35, 23, 47, 22, 78,
- /* 2060 */ 35, 35, 96, 35, 24, 35, 25, 25, 23, 146,
- /* 2070 */ 23, 23, 23, 23, 11, 23, 25, 22, 22, 22,
- /* 2080 */ 139, 23, 23, 146, 22, 25, 22, 15, 1, 145,
- /* 2090 */ 25, 23, 145, 145, 1, 145, 321, 321, 321, 321,
- /* 2100 */ 321, 321, 321, 321, 321, 321, 321, 321, 321, 321,
- /* 2110 */ 321, 321, 321, 321, 321, 321, 321, 321, 321, 321,
- /* 2120 */ 321, 321, 321, 321, 321, 321, 321, 321, 321, 321,
- /* 2130 */ 321, 321, 321, 321, 321, 321, 321, 321, 321, 321,
- /* 2140 */ 321, 321, 321, 321, 321, 321, 321, 321, 321, 321,
- /* 2150 */ 321, 321, 321, 321, 321, 321, 321, 321, 321, 321,
- /* 2160 */ 321, 321, 321, 321, 321, 321, 321, 321, 321, 321,
- /* 2170 */ 321, 321, 321, 321, 321, 321, 321, 321, 321, 321,
- /* 2180 */ 321, 321, 321, 321, 321, 321, 321, 321, 321, 321,
- /* 2190 */ 321, 321, 321, 321, 321, 321, 321, 321, 321, 321,
- /* 2200 */ 321, 321, 321, 321, 321, 321, 321, 321, 321, 321,
- /* 2210 */ 321, 321, 321, 321, 321, 321, 321, 321, 321, 321,
- /* 2220 */ 321, 321, 321, 321, 321, 321, 321, 321, 321, 321,
- /* 2230 */ 321, 321, 321, 321, 321, 321, 321, 321, 321, 321,
- /* 2240 */ 321, 321, 321, 321, 321, 321, 321, 321, 321, 321,
- /* 2250 */ 321, 321, 321, 321, 321, 321, 321, 321, 321, 321,
- /* 2260 */ 321, 321, 321, 321, 321, 321, 321, 321, 321, 321,
- /* 2270 */ 321, 321, 321, 321, 321, 321, 321, 321, 321, 321,
- /* 2280 */ 321, 321, 321,
+ /* 60 */ 60, 61, 20, 196, 188, 189, 190, 191, 192, 193,
+ /* 70 */ 226, 256, 228, 256, 198, 256, 200, 238, 239, 264,
+ /* 80 */ 236, 264, 65, 207, 277, 278, 279, 271, 207, 47,
+ /* 90 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ /* 100 */ 58, 59, 60, 61, 281, 196, 106, 107, 108, 109,
+ /* 110 */ 110, 111, 112, 113, 114, 115, 116, 117, 242, 243,
+ /* 120 */ 196, 317, 318, 242, 243, 317, 196, 319, 317, 318,
+ /* 130 */ 63, 255, 90, 20, 92, 23, 255, 25, 31, 26,
+ /* 140 */ 259, 260, 35, 76, 235, 269, 310, 222, 106, 107,
+ /* 150 */ 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+ /* 160 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ /* 170 */ 57, 58, 59, 60, 61, 63, 69, 301, 110, 111,
+ /* 180 */ 112, 113, 114, 115, 116, 117, 73, 120, 121, 122,
+ /* 190 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
+ /* 200 */ 116, 117, 277, 278, 279, 123, 26, 20, 126, 127,
+ /* 210 */ 128, 58, 59, 60, 61, 62, 286, 23, 136, 106,
+ /* 220 */ 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
+ /* 230 */ 117, 307, 196, 121, 47, 48, 49, 50, 51, 52,
+ /* 240 */ 53, 54, 55, 56, 57, 58, 59, 60, 61, 20,
+ /* 250 */ 139, 196, 141, 142, 25, 219, 220, 63, 71, 106,
+ /* 260 */ 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
+ /* 270 */ 117, 213, 214, 215, 219, 220, 47, 48, 49, 50,
+ /* 280 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ /* 290 */ 61, 117, 256, 106, 107, 108, 109, 110, 111, 112,
+ /* 300 */ 113, 114, 115, 116, 117, 112, 113, 114, 115, 116,
+ /* 310 */ 117, 256, 196, 219, 120, 121, 122, 80, 216, 264,
+ /* 320 */ 20, 58, 59, 60, 61, 63, 196, 252, 91, 254,
+ /* 330 */ 93, 27, 28, 96, 154, 106, 107, 108, 109, 110,
+ /* 340 */ 111, 112, 113, 114, 115, 116, 117, 47, 48, 49,
+ /* 350 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ /* 360 */ 60, 61, 132, 133, 63, 23, 24, 63, 26, 106,
+ /* 370 */ 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
+ /* 380 */ 117, 80, 120, 121, 122, 123, 63, 150, 126, 127,
+ /* 390 */ 128, 289, 91, 243, 93, 196, 294, 96, 136, 76,
+ /* 400 */ 233, 50, 51, 52, 53, 255, 106, 107, 108, 109,
+ /* 410 */ 110, 111, 112, 113, 114, 115, 116, 117, 219, 220,
+ /* 420 */ 272, 120, 121, 122, 120, 121, 122, 311, 312, 20,
+ /* 430 */ 22, 26, 316, 24, 23, 196, 63, 213, 214, 215,
+ /* 440 */ 196, 311, 312, 120, 121, 122, 316, 105, 110, 111,
+ /* 450 */ 20, 150, 196, 45, 24, 155, 47, 48, 49, 50,
+ /* 460 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ /* 470 */ 61, 20, 169, 170, 63, 24, 125, 47, 48, 49,
+ /* 480 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ /* 490 */ 60, 61, 84, 120, 121, 122, 158, 159, 47, 48,
+ /* 500 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+ /* 510 */ 59, 60, 61, 85, 196, 106, 107, 108, 109, 110,
+ /* 520 */ 111, 112, 113, 114, 115, 116, 117, 63, 196, 156,
+ /* 530 */ 196, 120, 121, 122, 229, 127, 106, 107, 108, 109,
+ /* 540 */ 110, 111, 112, 113, 114, 115, 116, 117, 309, 310,
+ /* 550 */ 196, 196, 124, 219, 220, 150, 207, 106, 107, 108,
+ /* 560 */ 109, 110, 111, 112, 113, 114, 115, 116, 117, 214,
+ /* 570 */ 215, 143, 144, 165, 110, 111, 196, 196, 20, 238,
+ /* 580 */ 239, 196, 24, 119, 120, 121, 122, 63, 124, 204,
+ /* 590 */ 256, 242, 243, 312, 209, 26, 132, 316, 266, 20,
+ /* 600 */ 219, 220, 196, 24, 255, 47, 48, 49, 50, 51,
+ /* 610 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ /* 620 */ 20, 272, 158, 159, 24, 271, 47, 48, 49, 50,
+ /* 630 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ /* 640 */ 61, 216, 287, 23, 120, 121, 122, 47, 48, 49,
+ /* 650 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ /* 660 */ 60, 61, 196, 196, 106, 107, 108, 109, 110, 111,
+ /* 670 */ 112, 113, 114, 115, 116, 117, 209, 63, 312, 63,
+ /* 680 */ 214, 215, 316, 63, 207, 106, 107, 108, 109, 110,
+ /* 690 */ 111, 112, 113, 114, 115, 116, 117, 112, 231, 130,
+ /* 700 */ 233, 196, 277, 278, 279, 196, 106, 107, 108, 109,
+ /* 710 */ 110, 111, 112, 113, 114, 115, 116, 117, 104, 242,
+ /* 720 */ 243, 7, 8, 9, 10, 140, 196, 20, 112, 312,
+ /* 730 */ 145, 24, 255, 316, 120, 121, 120, 121, 122, 125,
+ /* 740 */ 120, 121, 122, 115, 116, 117, 304, 305, 20, 219,
+ /* 750 */ 220, 26, 138, 287, 47, 48, 49, 50, 51, 52,
+ /* 760 */ 53, 54, 55, 56, 57, 58, 59, 60, 61, 20,
+ /* 770 */ 196, 266, 158, 159, 85, 47, 48, 49, 50, 51,
+ /* 780 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ /* 790 */ 276, 23, 196, 219, 220, 63, 47, 48, 49, 50,
+ /* 800 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ /* 810 */ 61, 196, 17, 106, 107, 108, 109, 110, 111, 112,
+ /* 820 */ 113, 114, 115, 116, 117, 63, 196, 196, 314, 315,
+ /* 830 */ 256, 63, 143, 144, 106, 107, 108, 109, 110, 111,
+ /* 840 */ 112, 113, 114, 115, 116, 117, 77, 196, 196, 219,
+ /* 850 */ 220, 196, 120, 121, 122, 106, 107, 108, 109, 110,
+ /* 860 */ 111, 112, 113, 114, 115, 116, 117, 201, 143, 144,
+ /* 870 */ 219, 220, 196, 20, 219, 220, 81, 104, 83, 196,
+ /* 880 */ 148, 266, 120, 121, 122, 234, 256, 20, 120, 121,
+ /* 890 */ 122, 163, 25, 241, 121, 219, 220, 266, 125, 196,
+ /* 900 */ 131, 132, 133, 50, 23, 24, 196, 26, 20, 20,
+ /* 910 */ 148, 138, 163, 23, 47, 48, 49, 50, 51, 52,
+ /* 920 */ 53, 54, 55, 56, 57, 58, 59, 60, 61, 20,
+ /* 930 */ 196, 158, 159, 262, 263, 47, 48, 49, 50, 51,
+ /* 940 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ /* 950 */ 284, 299, 196, 63, 288, 196, 47, 48, 49, 50,
+ /* 960 */ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ /* 970 */ 61, 196, 119, 106, 107, 108, 109, 110, 111, 112,
+ /* 980 */ 113, 114, 115, 116, 117, 26, 105, 196, 135, 131,
+ /* 990 */ 132, 133, 207, 196, 106, 107, 108, 109, 110, 111,
+ /* 1000 */ 112, 113, 114, 115, 116, 117, 196, 196, 119, 120,
+ /* 1010 */ 120, 121, 122, 207, 17, 106, 107, 108, 109, 110,
+ /* 1020 */ 111, 112, 113, 114, 115, 116, 117, 242, 243, 219,
+ /* 1030 */ 220, 13, 70, 23, 24, 196, 20, 196, 149, 80,
+ /* 1040 */ 255, 244, 45, 196, 234, 77, 271, 29, 242, 243,
+ /* 1050 */ 209, 89, 93, 85, 295, 96, 209, 20, 219, 220,
+ /* 1060 */ 98, 255, 44, 150, 48, 49, 50, 51, 52, 53,
+ /* 1070 */ 54, 55, 56, 57, 58, 59, 60, 61, 81, 196,
+ /* 1080 */ 83, 168, 196, 211, 212, 67, 49, 50, 51, 52,
+ /* 1090 */ 53, 54, 55, 56, 57, 58, 59, 60, 61, 131,
+ /* 1100 */ 196, 196, 219, 220, 307, 219, 220, 196, 242, 243,
+ /* 1110 */ 196, 143, 144, 151, 196, 105, 20, 21, 196, 23,
+ /* 1120 */ 234, 255, 106, 107, 108, 109, 110, 111, 112, 113,
+ /* 1130 */ 114, 115, 116, 117, 38, 196, 63, 219, 220, 196,
+ /* 1140 */ 196, 219, 220, 106, 107, 108, 109, 110, 111, 112,
+ /* 1150 */ 113, 114, 115, 116, 117, 16, 234, 207, 191, 63,
+ /* 1160 */ 193, 196, 165, 219, 220, 198, 196, 200, 261, 20,
+ /* 1170 */ 21, 75, 23, 196, 207, 196, 271, 266, 234, 265,
+ /* 1180 */ 241, 85, 242, 243, 207, 211, 212, 38, 216, 219,
+ /* 1190 */ 220, 276, 242, 243, 121, 255, 219, 220, 219, 220,
+ /* 1200 */ 104, 52, 196, 64, 234, 255, 110, 111, 265, 242,
+ /* 1210 */ 243, 13, 63, 207, 118, 196, 120, 121, 122, 242,
+ /* 1220 */ 243, 125, 255, 196, 75, 219, 220, 29, 196, 314,
+ /* 1230 */ 315, 37, 255, 256, 138, 24, 269, 26, 89, 143,
+ /* 1240 */ 144, 264, 44, 94, 196, 276, 219, 220, 242, 243,
+ /* 1250 */ 207, 219, 220, 104, 158, 159, 160, 161, 196, 110,
+ /* 1260 */ 111, 255, 256, 244, 70, 67, 294, 118, 301, 120,
+ /* 1270 */ 121, 122, 78, 196, 125, 77, 20, 21, 24, 23,
+ /* 1280 */ 26, 219, 220, 314, 315, 242, 243, 138, 0, 1,
+ /* 1290 */ 2, 196, 244, 5, 38, 23, 219, 220, 255, 11,
+ /* 1300 */ 12, 13, 14, 15, 207, 196, 18, 158, 159, 160,
+ /* 1310 */ 161, 234, 196, 196, 219, 220, 23, 196, 209, 63,
+ /* 1320 */ 32, 196, 34, 196, 33, 196, 307, 26, 134, 234,
+ /* 1330 */ 42, 75, 41, 122, 196, 63, 219, 220, 12, 242,
+ /* 1340 */ 243, 196, 196, 196, 196, 89, 219, 220, 219, 220,
+ /* 1350 */ 94, 235, 255, 247, 196, 307, 196, 219, 220, 148,
+ /* 1360 */ 104, 20, 74, 257, 219, 220, 110, 111, 196, 80,
+ /* 1370 */ 82, 302, 303, 85, 118, 196, 120, 121, 122, 219,
+ /* 1380 */ 220, 125, 93, 20, 21, 96, 23, 241, 196, 241,
+ /* 1390 */ 102, 219, 220, 121, 138, 196, 1, 2, 219, 220,
+ /* 1400 */ 5, 38, 244, 110, 111, 121, 11, 12, 13, 14,
+ /* 1410 */ 15, 196, 265, 18, 158, 159, 160, 161, 219, 220,
+ /* 1420 */ 295, 196, 138, 122, 196, 137, 63, 32, 196, 34,
+ /* 1430 */ 196, 143, 144, 5, 219, 220, 196, 42, 75, 11,
+ /* 1440 */ 12, 13, 14, 15, 219, 220, 18, 219, 220, 148,
+ /* 1450 */ 20, 21, 89, 23, 166, 196, 196, 94, 132, 133,
+ /* 1460 */ 32, 120, 34, 23, 24, 307, 196, 104, 38, 74,
+ /* 1470 */ 42, 196, 196, 110, 111, 241, 196, 82, 219, 220,
+ /* 1480 */ 85, 118, 312, 120, 121, 122, 316, 295, 125, 219,
+ /* 1490 */ 220, 196, 133, 63, 219, 220, 196, 102, 229, 219,
+ /* 1500 */ 220, 138, 74, 143, 144, 75, 131, 132, 133, 26,
+ /* 1510 */ 82, 26, 196, 85, 219, 220, 157, 241, 247, 219,
+ /* 1520 */ 220, 158, 159, 160, 161, 25, 20, 21, 257, 23,
+ /* 1530 */ 102, 20, 137, 196, 104, 219, 220, 247, 143, 144,
+ /* 1540 */ 110, 111, 112, 196, 38, 105, 103, 257, 118, 247,
+ /* 1550 */ 120, 121, 122, 196, 312, 125, 219, 220, 316, 257,
+ /* 1560 */ 263, 166, 196, 63, 267, 137, 219, 220, 138, 63,
+ /* 1570 */ 263, 143, 144, 196, 267, 196, 219, 220, 259, 260,
+ /* 1580 */ 137, 75, 247, 196, 119, 219, 220, 196, 158, 159,
+ /* 1590 */ 160, 161, 257, 119, 166, 196, 219, 220, 219, 220,
+ /* 1600 */ 154, 155, 20, 21, 25, 23, 219, 220, 50, 166,
+ /* 1610 */ 104, 196, 101, 196, 149, 196, 110, 111, 219, 220,
+ /* 1620 */ 38, 121, 63, 196, 118, 23, 120, 121, 122, 155,
+ /* 1630 */ 147, 125, 147, 24, 219, 220, 219, 220, 219, 220,
+ /* 1640 */ 162, 23, 164, 25, 138, 63, 219, 220, 196, 20,
+ /* 1650 */ 196, 145, 196, 190, 191, 192, 193, 75, 133, 57,
+ /* 1660 */ 24, 198, 26, 200, 158, 159, 160, 161, 124, 125,
+ /* 1670 */ 207, 219, 220, 219, 220, 219, 220, 119, 20, 21,
+ /* 1680 */ 121, 23, 157, 140, 20, 196, 104, 196, 145, 25,
+ /* 1690 */ 196, 125, 110, 111, 63, 24, 38, 26, 23, 196,
+ /* 1700 */ 118, 135, 120, 121, 122, 242, 243, 125, 219, 220,
+ /* 1710 */ 219, 220, 196, 219, 220, 24, 63, 26, 255, 196,
+ /* 1720 */ 138, 63, 219, 220, 24, 146, 26, 145, 24, 24,
+ /* 1730 */ 26, 26, 269, 75, 196, 219, 220, 24, 196, 26,
+ /* 1740 */ 158, 159, 160, 161, 196, 24, 24, 26, 26, 120,
+ /* 1750 */ 7, 8, 121, 24, 24, 26, 26, 87, 88, 150,
+ /* 1760 */ 196, 196, 104, 99, 301, 24, 196, 26, 110, 111,
+ /* 1770 */ 158, 159, 158, 159, 121, 24, 118, 26, 120, 121,
+ /* 1780 */ 122, 117, 24, 125, 26, 196, 196, 123, 124, 125,
+ /* 1790 */ 126, 127, 128, 129, 196, 196, 138, 229, 258, 135,
+ /* 1800 */ 196, 196, 196, 196, 196, 321, 196, 196, 239, 196,
+ /* 1810 */ 291, 196, 196, 196, 194, 196, 158, 159, 160, 161,
+ /* 1820 */ 196, 146, 196, 196, 290, 245, 300, 246, 274, 258,
+ /* 1830 */ 258, 258, 258, 270, 248, 296, 249, 270, 217, 283,
+ /* 1840 */ 249, 248, 296, 246, 252, 223, 262, 262, 248, 274,
+ /* 1850 */ 274, 274, 222, 228, 222, 232, 222, 262, 262, 199,
+ /* 1860 */ 64, 300, 300, 146, 203, 203, 40, 156, 203, 286,
+ /* 1870 */ 155, 23, 47, 19, 237, 297, 275, 203, 240, 240,
+ /* 1880 */ 252, 240, 240, 240, 19, 297, 202, 154, 237, 249,
+ /* 1890 */ 203, 237, 202, 162, 249, 249, 202, 249, 66, 203,
+ /* 1900 */ 202, 23, 224, 224, 203, 202, 273, 119, 68, 203,
+ /* 1910 */ 275, 202, 230, 221, 221, 23, 221, 130, 230, 275,
+ /* 1920 */ 273, 169, 25, 221, 227, 117, 227, 203, 95, 221,
+ /* 1930 */ 86, 224, 153, 223, 268, 221, 224, 221, 253, 150,
+ /* 1940 */ 268, 285, 293, 23, 292, 203, 162, 280, 285, 152,
+ /* 1950 */ 282, 151, 26, 205, 14, 6, 197, 197, 195, 195,
+ /* 1960 */ 195, 216, 216, 308, 210, 315, 210, 210, 4, 216,
+ /* 1970 */ 252, 251, 253, 250, 249, 306, 303, 320, 216, 320,
+ /* 1980 */ 225, 210, 306, 217, 217, 216, 225, 3, 23, 167,
+ /* 1990 */ 16, 64, 16, 24, 17, 24, 144, 156, 134, 26,
+ /* 2000 */ 25, 21, 147, 17, 1, 149, 147, 134, 134, 65,
+ /* 2010 */ 57, 39, 57, 156, 57, 57, 134, 36, 120, 1,
+ /* 2020 */ 5, 146, 23, 119, 46, 165, 25, 79, 72, 146,
+ /* 2030 */ 26, 72, 43, 119, 25, 21, 20, 135, 129, 71,
+ /* 2040 */ 23, 71, 23, 23, 39, 24, 23, 25, 63, 23,
+ /* 2050 */ 100, 24, 23, 71, 30, 154, 24, 24, 146, 24,
+ /* 2060 */ 26, 36, 23, 101, 24, 24, 120, 36, 23, 148,
+ /* 2070 */ 26, 92, 36, 36, 36, 79, 48, 90, 36, 79,
+ /* 2080 */ 97, 24, 36, 23, 25, 36, 147, 26, 26, 147,
+ /* 2090 */ 24, 24, 24, 24, 24, 12, 24, 26, 23, 23,
+ /* 2100 */ 23, 140, 24, 24, 23, 23, 26, 16, 1, 146,
+ /* 2110 */ 26, 24, 146, 146, 1, 322, 322, 322, 322, 322,
+ /* 2120 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2130 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2140 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2150 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2160 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2170 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2180 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2190 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2200 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2210 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2220 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2230 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2240 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2250 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2260 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2270 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2280 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2290 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 2300 */ 322, 322, 322,
};
-#define YY_SHIFT_COUNT (584)
+#define YY_SHIFT_COUNT (593)
#define YY_SHIFT_MIN (0)
-#define YY_SHIFT_MAX (2093)
+#define YY_SHIFT_MAX (2113)
static const unsigned short int yy_shift_ofst[] = {
- /* 0 */ 1674, 1483, 1739, 1292, 1292, 336, 1345, 1470, 1580, 1870,
- /* 10 */ 1870, 1870, 191, 0, 0, 232, 1005, 1870, 1870, 1870,
- /* 20 */ 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870,
- /* 30 */ 143, 143, 927, 927, 418, 193, 336, 336, 336, 336,
- /* 40 */ 336, 106, 126, 303, 345, 416, 458, 529, 571, 642,
- /* 50 */ 684, 755, 797, 868, 985, 1005, 1005, 1005, 1005, 1005,
- /* 60 */ 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
- /* 70 */ 1005, 1005, 1005, 1111, 1005, 1131, 1237, 1237, 1740, 1759,
- /* 80 */ 1851, 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870,
- /* 90 */ 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870,
- /* 100 */ 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870,
- /* 110 */ 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870,
- /* 120 */ 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870,
- /* 130 */ 198, 260, 260, 260, 260, 260, 260, 260, 28, 114,
- /* 140 */ 76, 267, 367, 924, 487, 375, 375, 952, 375, 375,
- /* 150 */ 140, 140, 375, 360, 360, 360, 714, 360, 113, 265,
- /* 160 */ 265, 84, 84, 2096, 2096, 869, 869, 869, 267, 492,
- /* 170 */ 534, 534, 534, 534, 922, 922, 181, 858, 919, 375,
- /* 180 */ 375, 375, 375, 375, 375, 375, 375, 375, 375, 375,
- /* 190 */ 375, 375, 375, 375, 375, 375, 375, 375, 375, 177,
- /* 200 */ 352, 352, 375, 645, 691, 691, 1136, 1136, 596, 596,
- /* 210 */ 1063, 1002, 2096, 2096, 2096, 2096, 2096, 2096, 2096, 965,
- /* 220 */ 1091, 1091, 644, 301, 648, 607, 652, 810, 958, 698,
- /* 230 */ 375, 375, 375, 375, 375, 375, 375, 375, 375, 375,
- /* 240 */ 250, 375, 375, 375, 375, 375, 375, 375, 375, 375,
- /* 250 */ 375, 375, 375, 375, 375, 375, 580, 580, 580, 375,
- /* 260 */ 375, 375, 1112, 375, 375, 375, 1085, 1104, 375, 375,
- /* 270 */ 1240, 375, 375, 375, 375, 375, 375, 375, 375, 375,
- /* 280 */ 649, 1242, 693, 1294, 1294, 1294, 1294, 1056, 693, 693,
- /* 290 */ 822, 100, 877, 1256, 782, 1234, 1278, 1234, 1353, 1253,
- /* 300 */ 782, 782, 1253, 782, 1278, 1353, 1297, 1380, 1355, 1337,
- /* 310 */ 1337, 1337, 1282, 1282, 1282, 1282, 1390, 1390, 1247, 1365,
- /* 320 */ 1279, 1403, 1656, 1656, 1588, 1588, 1696, 1696, 1588, 1593,
- /* 330 */ 1603, 1741, 1715, 1747, 1747, 1747, 1747, 1747, 1588, 1753,
- /* 340 */ 1631, 1603, 1603, 1631, 1741, 1715, 1631, 1715, 1631, 1588,
- /* 350 */ 1753, 1753, 1638, 1735, 1588, 1753, 1786, 1588, 1753, 1588,
- /* 360 */ 1753, 1786, 1701, 1701, 1701, 1755, 1803, 1803, 1786, 1701,
- /* 370 */ 1700, 1701, 1755, 1701, 1701, 1662, 1808, 1719, 1719, 1786,
- /* 380 */ 1588, 1761, 1761, 1778, 1778, 1713, 1718, 1862, 1588, 1725,
- /* 390 */ 1713, 1743, 1751, 1631, 1884, 1898, 1898, 1908, 1908, 1908,
- /* 400 */ 2096, 2096, 2096, 2096, 2096, 2096, 2096, 2096, 2096, 2096,
- /* 410 */ 2096, 2096, 2096, 2096, 2096, 857, 119, 925, 1052, 878,
- /* 420 */ 760, 421, 1414, 1372, 1425, 1437, 1300, 1335, 1445, 1456,
- /* 430 */ 1492, 1498, 1504, 1534, 304, 1543, 1560, 1359, 1334, 1533,
- /* 440 */ 526, 1409, 1473, 1578, 1595, 1523, 1598, 1486, 1488, 1599,
- /* 450 */ 1610, 1552, 1420, 1926, 1931, 1914, 1774, 1928, 1925, 1924,
- /* 460 */ 1927, 1805, 1794, 1818, 1930, 1930, 1929, 1806, 1936, 1809,
- /* 470 */ 1942, 1958, 1816, 1830, 1930, 1831, 1901, 1938, 1930, 1811,
- /* 480 */ 1911, 1913, 1918, 1921, 1845, 1863, 1946, 1838, 1983, 1980,
- /* 490 */ 1964, 1874, 1829, 1972, 1952, 1932, 1973, 1933, 1922, 1957,
- /* 500 */ 1856, 1887, 1978, 1986, 1993, 1879, 1886, 1994, 1945, 1995,
- /* 510 */ 1996, 1997, 1999, 1949, 1960, 2000, 1934, 2002, 2001, 1955,
- /* 520 */ 1988, 2009, 1881, 2013, 2014, 2015, 2016, 2011, 2017, 2019,
- /* 530 */ 1943, 1897, 2021, 2022, 1935, 2012, 2024, 1902, 2023, 2018,
- /* 540 */ 2020, 2025, 2026, 1959, 1974, 1962, 2010, 1981, 1966, 2028,
- /* 550 */ 2033, 2036, 2040, 2041, 2042, 2030, 1923, 1937, 2045, 2023,
- /* 560 */ 2047, 2048, 2049, 2050, 2051, 2052, 2055, 2063, 2056, 2057,
- /* 570 */ 2058, 2059, 2062, 2064, 2060, 1941, 1944, 1947, 1948, 1950,
- /* 580 */ 2065, 2068, 2072, 2087, 2093,
+ /* 0 */ 1395, 1288, 1428, 1096, 1096, 689, 1149, 1256, 1363, 1658,
+ /* 10 */ 1658, 1658, 968, 0, 0, 187, 888, 1658, 1658, 1658,
+ /* 20 */ 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658,
+ /* 30 */ 1658, 464, 464, 301, 301, 262, 428, 689, 689, 689,
+ /* 40 */ 689, 689, 42, 113, 229, 300, 409, 430, 451, 558,
+ /* 50 */ 579, 600, 707, 728, 749, 867, 888, 888, 888, 888,
+ /* 60 */ 888, 888, 888, 888, 888, 888, 888, 888, 888, 888,
+ /* 70 */ 888, 888, 888, 888, 909, 888, 1016, 1037, 1037, 1430,
+ /* 80 */ 1506, 1582, 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658,
+ /* 90 */ 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658,
+ /* 100 */ 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658,
+ /* 110 */ 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658,
+ /* 120 */ 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658,
+ /* 130 */ 1658, 153, 263, 263, 263, 263, 263, 263, 263, 84,
+ /* 140 */ 68, 193, 304, 67, 408, 323, 524, 524, 853, 524,
+ /* 150 */ 524, 338, 338, 524, 725, 725, 725, 628, 725, 230,
+ /* 160 */ 303, 303, 303, 174, 174, 2115, 2115, 1664, 1664, 1664,
+ /* 170 */ 1664, 304, 373, 194, 194, 194, 194, 1198, 1198, 237,
+ /* 180 */ 342, 881, 524, 524, 524, 524, 524, 524, 524, 524,
+ /* 190 */ 524, 524, 524, 524, 524, 524, 524, 524, 524, 524,
+ /* 200 */ 524, 524, 524, 524, 889, 959, 959, 524, 1326, 1289,
+ /* 210 */ 1289, 1341, 1341, 1073, 1073, 913, 1360, 2115, 2115, 2115,
+ /* 220 */ 2115, 2115, 2115, 2115, 614, 773, 773, 411, 82, 620,
+ /* 230 */ 616, 768, 732, 762, 890, 524, 524, 524, 524, 524,
+ /* 240 */ 524, 524, 524, 524, 524, 769, 524, 524, 524, 524,
+ /* 250 */ 524, 524, 524, 524, 524, 524, 524, 524, 524, 524,
+ /* 260 */ 524, 1194, 1194, 1194, 524, 524, 524, 1211, 524, 524,
+ /* 270 */ 524, 112, 962, 524, 524, 1018, 524, 524, 524, 524,
+ /* 280 */ 524, 524, 524, 524, 524, 714, 858, 107, 111, 1500,
+ /* 290 */ 1500, 1500, 1500, 1301, 111, 111, 585, 1293, 1139, 1474,
+ /* 300 */ 1446, 1483, 1446, 1629, 180, 1474, 1474, 180, 1474, 1483,
+ /* 310 */ 1629, 569, 1254, 1558, 1291, 1291, 1291, 1465, 1465, 1465,
+ /* 320 */ 1465, 405, 405, 1478, 1485, 1543, 1618, 1796, 1796, 1717,
+ /* 330 */ 1717, 1826, 1826, 1717, 1711, 1715, 1848, 1825, 1854, 1854,
+ /* 340 */ 1854, 1854, 1854, 1717, 1865, 1733, 1715, 1715, 1733, 1848,
+ /* 350 */ 1825, 1733, 1825, 1733, 1717, 1865, 1865, 1731, 1832, 1717,
+ /* 360 */ 1865, 1878, 1717, 1865, 1717, 1865, 1878, 1788, 1788, 1788,
+ /* 370 */ 1840, 1892, 1892, 1878, 1788, 1787, 1788, 1840, 1788, 1788,
+ /* 380 */ 1752, 1897, 1808, 1808, 1878, 1717, 1833, 1833, 1844, 1844,
+ /* 390 */ 1779, 1789, 1920, 1717, 1784, 1779, 1797, 1800, 1733, 1926,
+ /* 400 */ 1940, 1940, 1949, 1949, 1949, 2115, 2115, 2115, 2115, 2115,
+ /* 410 */ 2115, 2115, 2115, 2115, 2115, 2115, 2115, 2115, 2115, 2115,
+ /* 420 */ 2115, 997, 351, 1010, 1440, 1443, 795, 1375, 1272, 1636,
+ /* 430 */ 1602, 1579, 1359, 1525, 1671, 17, 1691, 1700, 1704, 1705,
+ /* 440 */ 1284, 1713, 1721, 1559, 1544, 1743, 1566, 1722, 1609, 1511,
+ /* 450 */ 1631, 1729, 1730, 1670, 1741, 1612, 1614, 1751, 1758, 1653,
+ /* 460 */ 1675, 1964, 1984, 1965, 1822, 1974, 1927, 1976, 1977, 1969,
+ /* 470 */ 1971, 1852, 1841, 1864, 1973, 1973, 1975, 1855, 1980, 1856,
+ /* 480 */ 1986, 2003, 1859, 1873, 1973, 1874, 1944, 1972, 1973, 1857,
+ /* 490 */ 1953, 1955, 1957, 1958, 1882, 1898, 1981, 1875, 2018, 2015,
+ /* 500 */ 1999, 1904, 1860, 2001, 1978, 1956, 2004, 1959, 1948, 1989,
+ /* 510 */ 1883, 1914, 2009, 2014, 2016, 1902, 1909, 2017, 1968, 2019,
+ /* 520 */ 2020, 2021, 2023, 1970, 1985, 2022, 1950, 2024, 2026, 1982,
+ /* 530 */ 2005, 2027, 2025, 1901, 2029, 2032, 2033, 2034, 2035, 2039,
+ /* 540 */ 1962, 1912, 2040, 2041, 1946, 2031, 2045, 1921, 2044, 2036,
+ /* 550 */ 2037, 2038, 2042, 1979, 1996, 1987, 2028, 2000, 1983, 2046,
+ /* 560 */ 2057, 2060, 2059, 2061, 2062, 2049, 1939, 1942, 2066, 2044,
+ /* 570 */ 2067, 2068, 2069, 2070, 2071, 2072, 2075, 2083, 2076, 2077,
+ /* 580 */ 2078, 2079, 2081, 2082, 2080, 1961, 1963, 1966, 1967, 2084,
+ /* 590 */ 2087, 2091, 2107, 2113,
};
-#define YY_REDUCE_COUNT (414)
-#define YY_REDUCE_MIN (-271)
-#define YY_REDUCE_MAX (1731)
+#define YY_REDUCE_COUNT (420)
+#define YY_REDUCE_MIN (-276)
+#define YY_REDUCE_MAX (1771)
static const short yy_reduce_ofst[] = {
- /* 0 */ -179, -168, 292, 745, -124, -162, -193, -117, -69, 230,
- /* 10 */ 340, 396, -173, -149, -130, -262, -212, -134, 188, 737,
- /* 20 */ 795, 453, 854, 908, 527, 566, 913, 51, 640, 680,
- /* 30 */ 683, 911, -108, 13, -191, 582, 635, 898, 1023, 1025,
- /* 40 */ 1028, -271, -271, -271, -271, -271, -271, -271, -271, -271,
- /* 50 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271,
- /* 60 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271,
- /* 70 */ -271, -271, -271, -271, -271, -271, -271, -271, 227, 414,
- /* 80 */ 807, 956, 977, 981, 1055, 1062, 1080, 1089, 1105, 1107,
- /* 90 */ 1109, 1114, 1118, 1120, 1122, 1140, 1160, 1162, 1165, 1167,
- /* 100 */ 1173, 1175, 1179, 1222, 1225, 1227, 1241, 1258, 1268, 1280,
- /* 110 */ 1315, 1318, 1324, 1327, 1330, 1333, 1336, 1343, 1352, 1358,
- /* 120 */ 1377, 1379, 1386, 1393, 1397, 1413, 1418, 1439, 1444, 1446,
- /* 130 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271,
- /* 140 */ -271, -1, 195, 866, 356, -195, 362, 205, 403, 70,
- /* 150 */ 388, 511, 347, 463, 584, 463, -271, 584, 544, 398,
- /* 160 */ 697, -271, -271, -271, -271, -189, -189, -189, -165, -118,
- /* 170 */ -194, -2, 679, 748, 282, 426, 404, -184, -184, -125,
- /* 180 */ 120, 297, 457, -152, 59, 888, 1011, 472, -161, 938,
- /* 190 */ 687, 751, 941, 817, 953, 302, 1019, 194, 943, 578,
- /* 200 */ 756, 887, 295, 382, 947, 990, 1054, 1068, 743, 932,
- /* 210 */ 569, 533, 959, 759, 1075, 1115, 1117, 951, 1143, -181,
- /* 220 */ -151, -128, -102, 40, 137, 415, 567, 632, 647, 874,
- /* 230 */ 885, 934, 1009, 1012, 1018, 1180, 1236, 1276, 1285, 1306,
- /* 240 */ 276, 1311, 1317, 1323, 1331, 1374, 1383, 1391, 1411, 1443,
- /* 250 */ 1452, 1454, 1455, 1457, 1458, 1460, 365, 501, 651, 1461,
- /* 260 */ 1464, 1465, 678, 939, 1466, 1471, 897, 1210, 1472, 1474,
- /* 270 */ 1312, 1475, 415, 1476, 1479, 1482, 1485, 1487, 1497, 1499,
- /* 280 */ 973, 1271, 1396, 1394, 1421, 1424, 1436, 678, 1396, 1396,
- /* 290 */ 1450, 1480, 1382, 1399, 1429, 1434, 1459, 1440, 1415, 1463,
- /* 300 */ 1435, 1441, 1468, 1447, 1477, 1417, 1491, 1490, 1495, 1502,
- /* 310 */ 1505, 1506, 1467, 1469, 1481, 1484, 1478, 1503, 1449, 1489,
- /* 320 */ 1496, 1520, 1426, 1433, 1532, 1541, 1493, 1494, 1544, 1500,
- /* 330 */ 1508, 1501, 1528, 1527, 1529, 1530, 1535, 1537, 1565, 1582,
- /* 340 */ 1538, 1513, 1514, 1545, 1519, 1556, 1546, 1559, 1549, 1596,
- /* 350 */ 1600, 1602, 1512, 1515, 1605, 1604, 1586, 1609, 1612, 1613,
- /* 360 */ 1617, 1601, 1606, 1607, 1608, 1615, 1611, 1616, 1618, 1614,
- /* 370 */ 1623, 1626, 1619, 1627, 1632, 1517, 1531, 1569, 1570, 1633,
- /* 380 */ 1634, 1539, 1547, 1620, 1624, 1622, 1621, 1629, 1683, 1625,
- /* 390 */ 1641, 1645, 1653, 1657, 1706, 1716, 1724, 1721, 1727, 1728,
- /* 400 */ 1628, 1630, 1635, 1714, 1709, 1711, 1712, 1723, 1720, 1704,
- /* 410 */ 1707, 1726, 1729, 1731, 1730,
+ /* 0 */ -124, 1463, 967, 977, 1006, -119, -196, -192, -189, -185,
+ /* 10 */ -183, 55, 349, -193, -75, -276, 425, 651, 810, 886,
+ /* 20 */ 922, 944, -181, 970, 1077, 36, 334, 1095, -177, 574,
+ /* 30 */ 630, 355, 466, 116, 130, 467, 477, 785, 806, 950,
+ /* 40 */ 1043, 1097, -269, -269, -269, -269, -269, -269, -269, -269,
+ /* 50 */ -269, -269, -269, -269, -269, -269, -269, -269, -269, -269,
+ /* 60 */ -269, -269, -269, -269, -269, -269, -269, -269, -269, -269,
+ /* 70 */ -269, -269, -269, -269, -269, -269, -269, -269, -269, -175,
+ /* 80 */ 199, 381, 530, 655, 676, 839, 883, 918, 979, 1027,
+ /* 90 */ 1032, 1062, 1117, 1127, 1129, 1138, 1145, 1160, 1172, 1179,
+ /* 100 */ 1199, 1215, 1225, 1228, 1259, 1270, 1275, 1280, 1295, 1300,
+ /* 110 */ 1316, 1337, 1347, 1357, 1366, 1377, 1379, 1387, 1399, 1415,
+ /* 120 */ 1417, 1419, 1427, 1452, 1454, 1456, 1489, 1491, 1494, 1503,
+ /* 130 */ 1516, -269, -269, -269, -269, -269, -269, -269, -269, -269,
+ /* 140 */ -269, -269, -190, 797, 666, 1019, 652, 1048, -156, 1158,
+ /* 150 */ 239, 58, 224, 385, 866, 940, 866, -269, 940, 102,
+ /* 160 */ 514, 915, 969, -269, -269, -269, -269, -201, -201, -201,
+ /* 170 */ -201, -182, -70, -184, 354, 775, 905, -161, 341, 281,
+ /* 180 */ 442, 442, 841, 847, 1109, 914, 943, 1147, 939, 1146,
+ /* 190 */ 1148, 1234, 759, 332, 1125, 505, 615, 1192, 631, 1276,
+ /* 200 */ -91, 1116, -76, 911, 671, 366, 417, -164, 972, 1170,
+ /* 210 */ 1242, 1297, 1307, 872, 974, 75, 150, 1069, 1106, 1271,
+ /* 220 */ 1290, 1302, 1319, 1335, -214, -173, 94, -133, 167, 244,
+ /* 230 */ 256, 318, 380, 406, 509, 596, 683, 703, 710, 734,
+ /* 240 */ 756, 791, 811, 904, 965, 148, 1121, 1232, 1240, 1260,
+ /* 250 */ 1391, 1523, 1538, 1542, 1548, 1564, 1565, 1570, 1589, 1590,
+ /* 260 */ 1598, 305, 1269, 1568, 1599, 1604, 1605, 907, 1606, 1607,
+ /* 270 */ 1608, 1540, 1484, 1610, 1611, 1569, 1613, 256, 1615, 1616,
+ /* 280 */ 1617, 1619, 1624, 1626, 1627, 1620, 1519, 1534, 1580, 1571,
+ /* 290 */ 1572, 1573, 1574, 907, 1580, 1580, 1581, 1621, 1526, 1554,
+ /* 300 */ 1563, 1586, 1567, 1539, 1587, 1575, 1576, 1591, 1577, 1593,
+ /* 310 */ 1546, 1622, 1623, 1625, 1630, 1632, 1634, 1584, 1585, 1595,
+ /* 320 */ 1596, 1592, 1628, 1556, 1600, 1597, 1660, 1561, 1562, 1661,
+ /* 330 */ 1662, 1578, 1588, 1665, 1583, 1601, 1633, 1637, 1638, 1639,
+ /* 340 */ 1641, 1642, 1643, 1674, 1684, 1640, 1635, 1644, 1645, 1647,
+ /* 350 */ 1651, 1646, 1654, 1648, 1687, 1690, 1694, 1649, 1652, 1696,
+ /* 360 */ 1698, 1678, 1701, 1703, 1706, 1709, 1679, 1692, 1693, 1695,
+ /* 370 */ 1682, 1697, 1699, 1707, 1702, 1710, 1708, 1688, 1714, 1716,
+ /* 380 */ 1650, 1655, 1656, 1663, 1712, 1724, 1657, 1659, 1666, 1672,
+ /* 390 */ 1685, 1718, 1667, 1742, 1668, 1719, 1720, 1723, 1725, 1748,
+ /* 400 */ 1759, 1760, 1763, 1764, 1765, 1669, 1676, 1673, 1754, 1756,
+ /* 410 */ 1745, 1746, 1753, 1762, 1757, 1755, 1761, 1766, 1767, 1769,
+ /* 420 */ 1771,
};
static const YYACTIONTYPE yy_default[] = {
- /* 0 */ 1668, 1668, 1668, 1496, 1257, 1372, 1257, 1257, 1257, 1496,
- /* 10 */ 1496, 1496, 1257, 1402, 1402, 1549, 1291, 1257, 1257, 1257,
- /* 20 */ 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1495, 1257, 1257,
- /* 30 */ 1257, 1257, 1584, 1584, 1257, 1257, 1257, 1257, 1257, 1257,
- /* 40 */ 1257, 1257, 1411, 1257, 1418, 1257, 1257, 1257, 1257, 1257,
- /* 50 */ 1497, 1498, 1257, 1257, 1257, 1548, 1550, 1513, 1425, 1424,
- /* 60 */ 1423, 1422, 1531, 1390, 1416, 1409, 1413, 1491, 1492, 1490,
- /* 70 */ 1494, 1498, 1497, 1257, 1412, 1459, 1475, 1458, 1257, 1257,
- /* 80 */ 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257,
- /* 90 */ 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257,
- /* 100 */ 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257,
- /* 110 */ 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257,
- /* 120 */ 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257,
- /* 130 */ 1467, 1474, 1473, 1472, 1481, 1471, 1468, 1461, 1460, 1462,
- /* 140 */ 1463, 1281, 1257, 1278, 1257, 1257, 1257, 1333, 1257, 1257,
- /* 150 */ 1257, 1257, 1257, 1568, 1567, 1257, 1464, 1257, 1291, 1453,
- /* 160 */ 1452, 1478, 1465, 1477, 1476, 1556, 1620, 1619, 1257, 1514,
- /* 170 */ 1257, 1257, 1257, 1257, 1257, 1257, 1584, 1257, 1257, 1257,
- /* 180 */ 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257,
- /* 190 */ 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1392,
- /* 200 */ 1584, 1584, 1257, 1291, 1584, 1584, 1393, 1393, 1287, 1287,
- /* 210 */ 1396, 1257, 1563, 1363, 1363, 1363, 1363, 1372, 1363, 1257,
- /* 220 */ 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257,
- /* 230 */ 1257, 1257, 1257, 1257, 1553, 1551, 1257, 1257, 1257, 1257,
- /* 240 */ 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257,
- /* 250 */ 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257,
- /* 260 */ 1257, 1257, 1257, 1257, 1257, 1257, 1368, 1257, 1257, 1257,
- /* 270 */ 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1613,
- /* 280 */ 1257, 1526, 1350, 1368, 1368, 1368, 1368, 1370, 1351, 1349,
- /* 290 */ 1362, 1292, 1264, 1660, 1428, 1417, 1369, 1417, 1657, 1415,
- /* 300 */ 1428, 1428, 1415, 1428, 1369, 1657, 1308, 1636, 1303, 1402,
- /* 310 */ 1402, 1402, 1392, 1392, 1392, 1392, 1396, 1396, 1493, 1369,
- /* 320 */ 1362, 1257, 1660, 1660, 1378, 1378, 1659, 1659, 1378, 1514,
- /* 330 */ 1644, 1437, 1336, 1342, 1342, 1342, 1342, 1342, 1378, 1275,
- /* 340 */ 1415, 1644, 1644, 1415, 1437, 1336, 1415, 1336, 1415, 1378,
- /* 350 */ 1275, 1275, 1530, 1654, 1378, 1275, 1504, 1378, 1275, 1378,
- /* 360 */ 1275, 1504, 1334, 1334, 1334, 1323, 1257, 1257, 1504, 1334,
- /* 370 */ 1308, 1334, 1323, 1334, 1334, 1602, 1257, 1508, 1508, 1504,
- /* 380 */ 1378, 1594, 1594, 1405, 1405, 1410, 1396, 1499, 1378, 1257,
- /* 390 */ 1410, 1408, 1406, 1415, 1326, 1616, 1616, 1612, 1612, 1612,
- /* 400 */ 1665, 1665, 1563, 1629, 1291, 1291, 1291, 1291, 1629, 1310,
- /* 410 */ 1310, 1292, 1292, 1291, 1629, 1257, 1257, 1257, 1257, 1257,
- /* 420 */ 1257, 1624, 1257, 1558, 1515, 1382, 1257, 1257, 1257, 1257,
- /* 430 */ 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257,
- /* 440 */ 1257, 1569, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257,
- /* 450 */ 1257, 1257, 1442, 1257, 1260, 1560, 1257, 1257, 1257, 1257,
- /* 460 */ 1257, 1257, 1257, 1257, 1419, 1420, 1383, 1257, 1257, 1257,
- /* 470 */ 1257, 1257, 1257, 1257, 1434, 1257, 1257, 1257, 1429, 1257,
- /* 480 */ 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1656, 1257, 1257,
- /* 490 */ 1257, 1257, 1257, 1257, 1257, 1257, 1529, 1528, 1257, 1257,
- /* 500 */ 1380, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257,
- /* 510 */ 1257, 1257, 1257, 1257, 1306, 1257, 1257, 1257, 1257, 1257,
- /* 520 */ 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257,
- /* 530 */ 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1407, 1257,
- /* 540 */ 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257,
- /* 550 */ 1257, 1257, 1257, 1599, 1397, 1257, 1257, 1257, 1257, 1647,
- /* 560 */ 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257,
- /* 570 */ 1257, 1257, 1257, 1257, 1640, 1353, 1444, 1257, 1443, 1447,
- /* 580 */ 1279, 1257, 1269, 1257, 1257,
+ /* 0 */ 1680, 1680, 1680, 1509, 1269, 1385, 1269, 1269, 1269, 1509,
+ /* 10 */ 1509, 1509, 1269, 1415, 1415, 1562, 1304, 1269, 1269, 1269,
+ /* 20 */ 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1508, 1269,
+ /* 30 */ 1269, 1269, 1269, 1596, 1596, 1269, 1269, 1269, 1269, 1269,
+ /* 40 */ 1269, 1269, 1269, 1424, 1269, 1431, 1269, 1269, 1269, 1269,
+ /* 50 */ 1269, 1510, 1511, 1269, 1269, 1269, 1561, 1563, 1526, 1438,
+ /* 60 */ 1437, 1436, 1435, 1544, 1403, 1429, 1422, 1426, 1505, 1506,
+ /* 70 */ 1504, 1658, 1511, 1510, 1269, 1425, 1473, 1489, 1472, 1269,
+ /* 80 */ 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 90 */ 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 100 */ 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 110 */ 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 120 */ 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 130 */ 1269, 1481, 1488, 1487, 1486, 1495, 1485, 1482, 1475, 1474,
+ /* 140 */ 1476, 1477, 1294, 1269, 1291, 1269, 1269, 1269, 1346, 1269,
+ /* 150 */ 1269, 1269, 1269, 1269, 1582, 1581, 1269, 1478, 1269, 1304,
+ /* 160 */ 1466, 1465, 1464, 1492, 1479, 1491, 1490, 1569, 1573, 1632,
+ /* 170 */ 1631, 1269, 1527, 1269, 1269, 1269, 1269, 1269, 1269, 1596,
+ /* 180 */ 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 190 */ 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 200 */ 1269, 1269, 1269, 1269, 1405, 1596, 1596, 1269, 1304, 1596,
+ /* 210 */ 1596, 1406, 1406, 1300, 1300, 1409, 1269, 1577, 1376, 1376,
+ /* 220 */ 1376, 1376, 1385, 1376, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 230 */ 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1566,
+ /* 240 */ 1564, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 250 */ 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 260 */ 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 270 */ 1269, 1381, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 280 */ 1269, 1269, 1269, 1269, 1625, 1276, 1269, 1539, 1363, 1381,
+ /* 290 */ 1381, 1381, 1381, 1383, 1364, 1362, 1375, 1305, 1672, 1441,
+ /* 300 */ 1430, 1382, 1430, 1669, 1428, 1441, 1441, 1428, 1441, 1382,
+ /* 310 */ 1669, 1321, 1647, 1316, 1415, 1415, 1415, 1405, 1405, 1405,
+ /* 320 */ 1405, 1409, 1409, 1507, 1382, 1375, 1269, 1672, 1672, 1391,
+ /* 330 */ 1391, 1671, 1671, 1391, 1527, 1655, 1450, 1349, 1355, 1355,
+ /* 340 */ 1355, 1355, 1355, 1391, 1288, 1428, 1655, 1655, 1428, 1450,
+ /* 350 */ 1349, 1428, 1349, 1428, 1391, 1288, 1288, 1543, 1666, 1391,
+ /* 360 */ 1288, 1517, 1391, 1288, 1391, 1288, 1517, 1347, 1347, 1347,
+ /* 370 */ 1336, 1269, 1269, 1517, 1347, 1321, 1347, 1336, 1347, 1347,
+ /* 380 */ 1614, 1269, 1521, 1521, 1517, 1391, 1606, 1606, 1418, 1418,
+ /* 390 */ 1423, 1409, 1512, 1391, 1269, 1423, 1421, 1419, 1428, 1339,
+ /* 400 */ 1628, 1628, 1624, 1624, 1624, 1677, 1677, 1577, 1640, 1640,
+ /* 410 */ 1304, 1304, 1304, 1304, 1640, 1323, 1323, 1305, 1305, 1304,
+ /* 420 */ 1640, 1269, 1269, 1269, 1269, 1571, 1269, 1269, 1635, 1269,
+ /* 430 */ 1528, 1395, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 440 */ 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1583,
+ /* 450 */ 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 460 */ 1455, 1269, 1272, 1574, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 470 */ 1269, 1269, 1269, 1269, 1432, 1433, 1396, 1269, 1269, 1269,
+ /* 480 */ 1269, 1269, 1269, 1269, 1447, 1269, 1269, 1269, 1442, 1269,
+ /* 490 */ 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1668, 1269, 1269,
+ /* 500 */ 1269, 1269, 1269, 1269, 1269, 1269, 1542, 1541, 1269, 1269,
+ /* 510 */ 1393, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 520 */ 1269, 1269, 1269, 1269, 1319, 1269, 1269, 1269, 1269, 1269,
+ /* 530 */ 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 540 */ 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1420, 1269,
+ /* 550 */ 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 560 */ 1269, 1269, 1269, 1611, 1410, 1269, 1269, 1269, 1269, 1659,
+ /* 570 */ 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269,
+ /* 580 */ 1269, 1269, 1269, 1269, 1651, 1366, 1456, 1269, 1459, 1292,
+ /* 590 */ 1269, 1282, 1269, 1269,
};
/********** End of lemon-generated parsing tables *****************************/
@@ -169385,55 +173047,56 @@ static const YYACTIONTYPE yy_default[] = {
static const YYCODETYPE yyFallback[] = {
0, /* $ => nothing */
0, /* SEMI => nothing */
- 62, /* EXPLAIN => ID */
- 62, /* QUERY => ID */
- 62, /* PLAN => ID */
- 62, /* BEGIN => ID */
+ 63, /* EXPLAIN => ID */
+ 63, /* QUERY => ID */
+ 63, /* PLAN => ID */
+ 63, /* BEGIN => ID */
0, /* TRANSACTION => nothing */
- 62, /* DEFERRED => ID */
- 62, /* IMMEDIATE => ID */
- 62, /* EXCLUSIVE => ID */
+ 63, /* DEFERRED => ID */
+ 63, /* IMMEDIATE => ID */
+ 63, /* EXCLUSIVE => ID */
+ 63, /* READONLY => ID */
0, /* COMMIT => nothing */
- 62, /* END => ID */
- 62, /* ROLLBACK => ID */
- 62, /* SAVEPOINT => ID */
- 62, /* RELEASE => ID */
+ 63, /* END => ID */
+ 63, /* ROLLBACK => ID */
+ 63, /* SAVEPOINT => ID */
+ 63, /* RELEASE => ID */
0, /* TO => nothing */
0, /* TABLE => nothing */
0, /* CREATE => nothing */
- 62, /* IF => ID */
+ 63, /* IF => ID */
0, /* NOT => nothing */
0, /* EXISTS => nothing */
- 62, /* TEMP => ID */
+ 63, /* TEMP => ID */
0, /* LP => nothing */
0, /* RP => nothing */
0, /* AS => nothing */
0, /* COMMA => nothing */
- 62, /* WITHOUT => ID */
- 62, /* RANDOM => ID */
- 62, /* ABORT => ID */
- 62, /* ACTION => ID */
- 62, /* AFTER => ID */
- 62, /* ANALYZE => ID */
- 62, /* ASC => ID */
- 62, /* ATTACH => ID */
- 62, /* BEFORE => ID */
- 62, /* BY => ID */
- 62, /* CASCADE => ID */
- 62, /* CAST => ID */
- 62, /* CONFLICT => ID */
- 62, /* DATABASE => ID */
- 62, /* DESC => ID */
- 62, /* DETACH => ID */
- 62, /* EACH => ID */
- 62, /* FAIL => ID */
- 62, /* FUNCTION => ID */
- 62, /* LANGUAGE => ID */
+ 63, /* WITHOUT => ID */
+ 63, /* RANDOM => ID */
+ 63, /* ABORT => ID */
+ 63, /* ACTION => ID */
+ 63, /* AFTER => ID */
+ 63, /* ANALYZE => ID */
+ 63, /* ASC => ID */
+ 63, /* ATTACH => ID */
+ 63, /* BEFORE => ID */
+ 63, /* BY => ID */
+ 63, /* CASCADE => ID */
+ 63, /* CAST => ID */
+ 63, /* CONFLICT => ID */
+ 63, /* DATABASE => ID */
+ 63, /* DESC => ID */
+ 63, /* DETACH => ID */
+ 63, /* EACH => ID */
+ 63, /* FAIL => ID */
+ 63, /* FUNCTION => ID */
+ 63, /* LANGUAGE => ID */
0, /* OR => nothing */
0, /* AND => nothing */
0, /* IS => nothing */
- 62, /* MATCH => ID */
- 62, /* LIKE_KW => ID */
+ 63, /* MATCH => ID */
+ 63, /* LIKE_KW => ID */
0, /* BETWEEN => nothing */
0, /* IN => nothing */
0, /* ISNULL => nothing */
@@ -169446,47 +173109,47 @@ static const YYCODETYPE yyFallback[] = {
0, /* GE => nothing */
0, /* ESCAPE => nothing */
0, /* ID => nothing */
- 62, /* COLUMNKW => ID */
- 62, /* DO => ID */
- 62, /* FOR => ID */
- 62, /* IGNORE => ID */
- 62, /* INITIALLY => ID */
- 62, /* INSTEAD => ID */
- 62, /* NO => ID */
- 62, /* KEY => ID */
- 62, /* OF => ID */
- 62, /* OFFSET => ID */
- 62, /* PRAGMA => ID */
- 62, /* RAISE => ID */
- 62, /* RECURSIVE => ID */
- 62, /* REPLACE => ID */
- 62, /* RESTRICT => ID */
- 62, /* ROW => ID */
- 62, /* ROWS => ID */
- 62, /* TRIGGER => ID */
- 62, /* VACUUM => ID */
- 62, /* VIEW => ID */
- 62, /* VIRTUAL => ID */
- 62, /* WITH => ID */
- 62, /* NULLS => ID */
- 62, /* FIRST => ID */
- 62, /* LAST => ID */
- 62, /* CURRENT => ID */
- 62, /* FOLLOWING => ID */
- 62, /* PARTITION => ID */
- 62, /* PRECEDING => ID */
- 62, /* RANGE => ID */
- 62, /* UNBOUNDED => ID */
- 62, /* EXCLUDE => ID */
- 62, /* GROUPS => ID */
- 62, /* OTHERS => ID */
- 62, /* TIES => ID */
- 62, /* GENERATED => ID */
- 62, /* ALWAYS => ID */
- 62, /* MATERIALIZED => ID */
- 62, /* REINDEX => ID */
- 62, /* RENAME => ID */
- 62, /* CTIME_KW => ID */
+ 63, /* COLUMNKW => ID */
+ 63, /* DO => ID */
+ 63, /* FOR => ID */
+ 63, /* IGNORE => ID */
+ 63, /* INITIALLY => ID */
+ 63, /* INSTEAD => ID */
+ 63, /* NO => ID */
+ 63, /* KEY => ID */
+ 63, /* OF => ID */
+ 63, /* OFFSET => ID */
+ 63, /* PRAGMA => ID */
+ 63, /* RAISE => ID */
+ 63, /* RECURSIVE => ID */
+ 63, /* REPLACE => ID */
+ 63, /* RESTRICT => ID */
+ 63, /* ROW => ID */
+ 63, /* ROWS => ID */
+ 63, /* TRIGGER => ID */
+ 63, /* VACUUM => ID */
+ 63, /* VIEW => ID */
+ 63, /* VIRTUAL => ID */
+ 63, /* WITH => ID */
+ 63, /* NULLS => ID */
+ 63, /* FIRST => ID */
+ 63, /* LAST => ID */
+ 63, /* CURRENT => ID */
+ 63, /* FOLLOWING => ID */
+ 63, /* PARTITION => ID */
+ 63, /* PRECEDING => ID */
+ 63, /* RANGE => ID */
+ 63, /* UNBOUNDED => ID */
+ 63, /* EXCLUDE => ID */
+ 63, /* GROUPS => ID */
+ 63, /* OTHERS => ID */
+ 63, /* TIES => ID */
+ 63, /* GENERATED => ID */
+ 63, /* ALWAYS => ID */
+ 63, /* MATERIALIZED => ID */
+ 63, /* REINDEX => ID */
+ 63, /* RENAME => ID */
+ 63, /* CTIME_KW => ID */
0, /* ANY => nothing */
0, /* BITAND => nothing */
0, /* BITOR => nothing */
@@ -169668,317 +173331,318 @@ static const char *const yyTokenName[] = {
/* 7 */ "DEFERRED",
/* 8 */ "IMMEDIATE",
/* 9 */ "EXCLUSIVE",
- /* 10 */ "COMMIT",
- /* 11 */ "END",
- /* 12 */ "ROLLBACK",
- /* 13 */ "SAVEPOINT",
- /* 14 */ "RELEASE",
- /* 15 */ "TO",
- /* 16 */ "TABLE",
- /* 17 */ "CREATE",
- /* 18 */ "IF",
- /* 19 */ "NOT",
- /* 20 */ "EXISTS",
- /* 21 */ "TEMP",
- /* 22 */ "LP",
- /* 23 */ "RP",
- /* 24 */ "AS",
- /* 25 */ "COMMA",
- /* 26 */ "WITHOUT",
- /* 27 */ "RANDOM",
- /* 28 */ "ABORT",
- /* 29 */ "ACTION",
- /* 30 */ "AFTER",
- /* 31 */ "ANALYZE",
- /* 32 */ "ASC",
- /* 33 */ "ATTACH",
- /* 34 */ "BEFORE",
- /* 35 */ "BY",
- /* 36 */ "CASCADE",
- /* 37 */ "CAST",
- /* 38 */ "CONFLICT",
- /* 39 */ "DATABASE",
- /* 40 */ "DESC",
- /* 41 */ "DETACH",
- /* 42 */ "EACH",
- /* 43 */ "FAIL",
- /* 44 */ "FUNCTION",
- /* 45 */ "LANGUAGE",
- /* 46 */ "OR",
- /* 47 */ "AND",
- /* 48 */ "IS",
- /* 49 */ "MATCH",
- /* 50 */ "LIKE_KW",
- /* 51 */ "BETWEEN",
- /* 52 */ "IN",
- /* 53 */ "ISNULL",
- /* 54 */ "NOTNULL",
- /* 55 */ "NE",
- /* 56 */ "EQ",
- /* 57 */ "GT",
- /* 58 */ "LE",
- /* 59 */ "LT",
- /* 60 */ "GE",
- /* 61 */ "ESCAPE",
- /* 62 */ "ID",
- /* 63 */ "COLUMNKW",
- /* 64 */ "DO",
- /* 65 */ "FOR",
- /* 66 */ "IGNORE",
- /* 67 */ "INITIALLY",
- /* 68 */ "INSTEAD",
- /* 69 */ "NO",
- /* 70 */ "KEY",
- /* 71 */ "OF",
- /* 72 */ "OFFSET",
- /* 73 */ "PRAGMA",
- /* 74 */ "RAISE",
- /* 75 */ "RECURSIVE",
- /* 76 */ "REPLACE",
- /* 77 */ "RESTRICT",
- /* 78 */ "ROW",
- /* 79 */ "ROWS",
- /* 80 */ "TRIGGER",
- /* 81 */ "VACUUM",
- /* 82 */ "VIEW",
- /* 83 */ "VIRTUAL",
- /* 84 */ "WITH",
- /* 85 */ "NULLS",
- /* 86 */ "FIRST",
- /* 87 */ "LAST",
- /* 88 */ "CURRENT",
- /* 89 */ "FOLLOWING",
- /* 90 */ "PARTITION",
- /* 91 */ "PRECEDING",
- /* 92 */ "RANGE",
- /* 93 */ "UNBOUNDED",
- /* 94 */ "EXCLUDE",
- /* 95 */ "GROUPS",
- /* 96 */ "OTHERS",
- /* 97 */ "TIES",
- /* 98 */ "GENERATED",
- /* 99 */ "ALWAYS",
- /* 100 */ "MATERIALIZED",
- /* 101 */ "REINDEX",
- /* 102 */ "RENAME",
- /* 103 */ "CTIME_KW",
- /* 104 */ "ANY",
- /* 105 */ "BITAND",
- /* 106 */ "BITOR",
- /* 107 */ "LSHIFT",
- /* 108 */ "RSHIFT",
- /* 109 */ "PLUS",
- /* 110 */ "MINUS",
- /* 111 */ "STAR",
- /* 112 */ "SLASH",
- /* 113 */ "REM",
- /* 114 */ "CONCAT",
- /* 115 */ "PTR",
- /* 116 */ "COLLATE",
- /* 117 */ "BITNOT",
- /* 118 */ "ON",
- /* 119 */ "INDEXED",
- /* 120 */ "STRING",
- /* 121 */ "JOIN_KW",
- /* 122 */ "CONSTRAINT",
- /* 123 */ "DEFAULT",
- /* 124 */ "NULL",
- /* 125 */ "PRIMARY",
- /* 126 */ "UNIQUE",
- /* 127 */ "CHECK",
- /* 128 */ "REFERENCES",
- /* 129 */ "AUTOINCR",
- /* 130 */ "INSERT",
- /* 131 */ "DELETE",
- /* 132 */ "UPDATE",
- /* 133 */ "SET",
- /* 134 */ "DEFERRABLE",
- /* 135 */ "FOREIGN",
- /* 136 */ "DROP",
- /* 137 */ "BLOB",
- /* 138 */ "UNION",
- /* 139 */ "ALL",
- /* 140 */ "EXCEPT",
- /* 141 */ "INTERSECT",
- /* 142 */ "SELECT",
- /* 143 */ "VALUES",
- /* 144 */ "DISTINCT",
- /* 145 */ "DOT",
- /* 146 */ "FROM",
- /* 147 */ "JOIN",
- /* 148 */ "USING",
- /* 149 */ "ORDER",
- /* 150 */ "GROUP",
- /* 151 */ "HAVING",
- /* 152 */ "LIMIT",
- /* 153 */ "WHERE",
- /* 154 */ "RETURNING",
- /* 155 */ "INTO",
- /* 156 */ "NOTHING",
- /* 157 */ "FLOAT",
- /* 158 */ "INTEGER",
- /* 159 */ "VARIABLE",
- /* 160 */ "CASE",
- /* 161 */ "WHEN",
- /* 162 */ "THEN",
- /* 163 */ "ELSE",
- /* 164 */ "INDEX",
- /* 165 */ "ALTER",
- /* 166 */ "ADD",
- /* 167 */ "WINDOW",
- /* 168 */ "OVER",
- /* 169 */ "FILTER",
- /* 170 */ "COLUMN",
- /* 171 */ "AGG_FUNCTION",
- /* 172 */ "AGG_COLUMN",
- /* 173 */ "TRUEFALSE",
- /* 174 */ "ISNOT",
- /* 175 */ "UMINUS",
- /* 176 */ "UPLUS",
- /* 177 */ "TRUTH",
- /* 178 */ "REGISTER",
- /* 179 */ "VECTOR",
- /* 180 */ "SELECT_COLUMN",
- /* 181 */ "IF_NULL_ROW",
- /* 182 */ "ASTERISK",
- /* 183 */ "SPAN",
- /* 184 */ "ERROR",
- /* 185 */ "SPACE",
- /* 186 */ "ILLEGAL",
- /* 187 */ "input",
- /* 188 */ "cmdlist",
- /* 189 */ "ecmd",
- /* 190 */ "cmdx",
- /* 191 */ "explain",
- /* 192 */ "cmd",
- /* 193 */ "transtype",
- /* 194 */ "trans_opt",
- /* 195 */ "nm",
- /* 196 */ "savepoint_opt",
- /* 197 */ "create_table",
- /* 198 */ "create_table_args",
- /* 199 */ "createkw",
- /* 200 */ "temp",
- /* 201 */ "ifnotexists",
- /* 202 */ "dbnm",
- /* 203 */ "columnlist",
- /* 204 */ "conslist_opt",
- /* 205 */ "table_option_set",
- /* 206 */ "select",
- /* 207 */ "table_option",
- /* 208 */ "columnname",
- /* 209 */ "carglist",
- /* 210 */ "typetoken",
- /* 211 */ "typename",
- /* 212 */ "signed",
- /* 213 */ "plus_num",
- /* 214 */ "minus_num",
- /* 215 */ "scanpt",
- /* 216 */ "scantok",
- /* 217 */ "ccons",
- /* 218 */ "term",
- /* 219 */ "expr",
- /* 220 */ "onconf",
- /* 221 */ "sortorder",
- /* 222 */ "autoinc",
- /* 223 */ "eidlist_opt",
- /* 224 */ "refargs",
- /* 225 */ "defer_subclause",
- /* 226 */ "generated",
- /* 227 */ "refarg",
- /* 228 */ "refact",
- /* 229 */ "init_deferred_pred_opt",
- /* 230 */ "conslist",
- /* 231 */ "tconscomma",
- /* 232 */ "tcons",
- /* 233 */ "sortlist",
- /* 234 */ "eidlist",
- /* 235 */ "defer_subclause_opt",
- /* 236 */ "orconf",
- /* 237 */ "resolvetype",
- /* 238 */ "raisetype",
- /* 239 */ "ifexists",
- /* 240 */ "fullname",
- /* 241 */ "selectnowith",
- /* 242 */ "oneselect",
- /* 243 */ "wqlist",
- /* 244 */ "multiselect_op",
- /* 245 */ "distinct",
- /* 246 */ "selcollist",
- /* 247 */ "from",
- /* 248 */ "where_opt",
- /* 249 */ "groupby_opt",
- /* 250 */ "having_opt",
- /* 251 */ "orderby_opt",
- /* 252 */ "limit_opt",
- /* 253 */ "window_clause",
- /* 254 */ "values",
- /* 255 */ "nexprlist",
- /* 256 */ "sclp",
- /* 257 */ "as",
- /* 258 */ "seltablist",
- /* 259 */ "stl_prefix",
- /* 260 */ "joinop",
- /* 261 */ "on_using",
- /* 262 */ "indexed_by",
- /* 263 */ "exprlist",
- /* 264 */ "xfullname",
- /* 265 */ "idlist",
- /* 266 */ "indexed_opt",
- /* 267 */ "nulls",
- /* 268 */ "with",
- /* 269 */ "where_opt_ret",
- /* 270 */ "setlist",
- /* 271 */ "insert_cmd",
- /* 272 */ "idlist_opt",
- /* 273 */ "upsert",
- /* 274 */ "returning",
- /* 275 */ "filter_over",
- /* 276 */ "likeop",
- /* 277 */ "between_op",
- /* 278 */ "in_op",
- /* 279 */ "paren_exprlist",
- /* 280 */ "case_operand",
- /* 281 */ "case_exprlist",
- /* 282 */ "case_else",
- /* 283 */ "uniqueflag",
- /* 284 */ "collate",
- /* 285 */ "vinto",
- /* 286 */ "nmnum",
- /* 287 */ "trigger_decl",
- /* 288 */ "trigger_cmd_list",
- /* 289 */ "trigger_time",
- /* 290 */ "trigger_event",
- /* 291 */ "foreach_clause",
- /* 292 */ "when_clause",
- /* 293 */ "trigger_cmd",
- /* 294 */ "trnm",
- /* 295 */ "tridxby",
- /* 296 */ "database_kw_opt",
- /* 297 */ "key_opt",
- /* 298 */ "add_column_fullname",
- /* 299 */ "kwcolumn_opt",
- /* 300 */ "create_vtab",
- /* 301 */ "vtabarglist",
- /* 302 */ "vtabarg",
- /* 303 */ "vtabargtoken",
- /* 304 */ "lp",
- /* 305 */ "anylist",
- /* 306 */ "wqitem",
- /* 307 */ "wqas",
- /* 308 */ "windowdefn_list",
- /* 309 */ "windowdefn",
- /* 310 */ "window",
- /* 311 */ "frame_opt",
- /* 312 */ "part_opt",
- /* 313 */ "filter_clause",
- /* 314 */ "over_clause",
- /* 315 */ "range_or_rows",
- /* 316 */ "frame_bound",
- /* 317 */ "frame_bound_s",
- /* 318 */ "frame_bound_e",
- /* 319 */ "frame_exclude_opt",
- /* 320 */ "frame_exclude",
+ /* 10 */ "READONLY",
+ /* 11 */ "COMMIT",
+ /* 12 */ "END",
+ /* 13 */ "ROLLBACK",
+ /* 14 */ "SAVEPOINT",
+ /* 15 */ "RELEASE",
+ /* 16 */ "TO",
+ /* 17 */ "TABLE",
+ /* 18 */ "CREATE",
+ /* 19 */ "IF",
+ /* 20 */ "NOT",
+ /* 21 */ "EXISTS",
+ /* 22 */ "TEMP",
+ /* 23 */ "LP",
+ /* 24 */ "RP",
+ /* 25 */ "AS",
+ /* 26 */ "COMMA",
+ /* 27 */ "WITHOUT",
+ /* 28 */ "RANDOM",
+ /* 29 */ "ABORT",
+ /* 30 */ "ACTION",
+ /* 31 */ "AFTER",
+ /* 32 */ "ANALYZE",
+ /* 33 */ "ASC",
+ /* 34 */ "ATTACH",
+ /* 35 */ "BEFORE",
+ /* 36 */ "BY",
+ /* 37 */ "CASCADE",
+ /* 38 */ "CAST",
+ /* 39 */ "CONFLICT",
+ /* 40 */ "DATABASE",
+ /* 41 */ "DESC",
+ /* 42 */ "DETACH",
+ /* 43 */ "EACH",
+ /* 44 */ "FAIL",
+ /* 45 */ "FUNCTION",
+ /* 46 */ "LANGUAGE",
+ /* 47 */ "OR",
+ /* 48 */ "AND",
+ /* 49 */ "IS",
+ /* 50 */ "MATCH",
+ /* 51 */ "LIKE_KW",
+ /* 52 */ "BETWEEN",
+ /* 53 */ "IN",
+ /* 54 */ "ISNULL",
+ /* 55 */ "NOTNULL",
+ /* 56 */ "NE",
+ /* 57 */ "EQ",
+ /* 58 */ "GT",
+ /* 59 */ "LE",
+ /* 60 */ "LT",
+ /* 61 */ "GE",
+ /* 62 */ "ESCAPE",
+ /* 63 */ "ID",
+ /* 64 */ "COLUMNKW",
+ /* 65 */ "DO",
+ /* 66 */ "FOR",
+ /* 67 */ "IGNORE",
+ /* 68 */ "INITIALLY",
+ /* 69 */ "INSTEAD",
+ /* 70 */ "NO",
+ /* 71 */ "KEY",
+ /* 72 */ "OF",
+ /* 73 */ "OFFSET",
+ /* 74 */ "PRAGMA",
+ /* 75 */ "RAISE",
+ /* 76 */ "RECURSIVE",
+ /* 77 */ "REPLACE",
+ /* 78 */ "RESTRICT",
+ /* 79 */ "ROW",
+ /* 80 */ "ROWS",
+ /* 81 */ "TRIGGER",
+ /* 82 */ "VACUUM",
+ /* 83 */ "VIEW",
+ /* 84 */ "VIRTUAL",
+ /* 85 */ "WITH",
+ /* 86 */ "NULLS",
+ /* 87 */ "FIRST",
+ /* 88 */ "LAST",
+ /* 89 */ "CURRENT",
+ /* 90 */ "FOLLOWING",
+ /* 91 */ "PARTITION",
+ /* 92 */ "PRECEDING",
+ /* 93 */ "RANGE",
+ /* 94 */ "UNBOUNDED",
+ /* 95 */ "EXCLUDE",
+ /* 96 */ "GROUPS",
+ /* 97 */ "OTHERS",
+ /* 98 */ "TIES",
+ /* 99 */ "GENERATED",
+ /* 100 */ "ALWAYS",
+ /* 101 */ "MATERIALIZED",
+ /* 102 */ "REINDEX",
+ /* 103 */ "RENAME",
+ /* 104 */ "CTIME_KW",
+ /* 105 */ "ANY",
+ /* 106 */ "BITAND",
+ /* 107 */ "BITOR",
+ /* 108 */ "LSHIFT",
+ /* 109 */ "RSHIFT",
+ /* 110 */ "PLUS",
+ /* 111 */ "MINUS",
+ /* 112 */ "STAR",
+ /* 113 */ "SLASH",
+ /* 114 */ "REM",
+ /* 115 */ "CONCAT",
+ /* 116 */ "PTR",
+ /* 117 */ "COLLATE",
+ /* 118 */ "BITNOT",
+ /* 119 */ "ON",
+ /* 120 */ "INDEXED",
+ /* 121 */ "STRING",
+ /* 122 */ "JOIN_KW",
+ /* 123 */ "CONSTRAINT",
+ /* 124 */ "DEFAULT",
+ /* 125 */ "NULL",
+ /* 126 */ "PRIMARY",
+ /* 127 */ "UNIQUE",
+ /* 128 */ "CHECK",
+ /* 129 */ "REFERENCES",
+ /* 130 */ "AUTOINCR",
+ /* 131 */ "INSERT",
+ /* 132 */ "DELETE",
+ /* 133 */ "UPDATE",
+ /* 134 */ "SET",
+ /* 135 */ "DEFERRABLE",
+ /* 136 */ "FOREIGN",
+ /* 137 */ "DROP",
+ /* 138 */ "BLOB",
+ /* 139 */ "UNION",
+ /* 140 */ "ALL",
+ /* 141 */ "EXCEPT",
+ /* 142 */ "INTERSECT",
+ /* 143 */ "SELECT",
+ /* 144 */ "VALUES",
+ /* 145 */ "DISTINCT",
+ /* 146 */ "DOT",
+ /* 147 */ "FROM",
+ /* 148 */ "JOIN",
+ /* 149 */ "USING",
+ /* 150 */ "ORDER",
+ /* 151 */ "GROUP",
+ /* 152 */ "HAVING",
+ /* 153 */ "LIMIT",
+ /* 154 */ "WHERE",
+ /* 155 */ "RETURNING",
+ /* 156 */ "INTO",
+ /* 157 */ "NOTHING",
+ /* 158 */ "FLOAT",
+ /* 159 */ "INTEGER",
+ /* 160 */ "VARIABLE",
+ /* 161 */ "CASE",
+ /* 162 */ "WHEN",
+ /* 163 */ "THEN",
+ /* 164 */ "ELSE",
+ /* 165 */ "INDEX",
+ /* 166 */ "ALTER",
+ /* 167 */ "ADD",
+ /* 168 */ "WINDOW",
+ /* 169 */ "OVER",
+ /* 170 */ "FILTER",
+ /* 171 */ "COLUMN",
+ /* 172 */ "AGG_FUNCTION",
+ /* 173 */ "AGG_COLUMN",
+ /* 174 */ "TRUEFALSE",
+ /* 175 */ "ISNOT",
+ /* 176 */ "UMINUS",
+ /* 177 */ "UPLUS",
+ /* 178 */ "TRUTH",
+ /* 179 */ "REGISTER",
+ /* 180 */ "VECTOR",
+ /* 181 */ "SELECT_COLUMN",
+ /* 182 */ "IF_NULL_ROW",
+ /* 183 */ "ASTERISK",
+ /* 184 */ "SPAN",
+ /* 185 */ "ERROR",
+ /* 186 */ "SPACE",
+ /* 187 */ "ILLEGAL",
+ /* 188 */ "input",
+ /* 189 */ "cmdlist",
+ /* 190 */ "ecmd",
+ /* 191 */ "cmdx",
+ /* 192 */ "explain",
+ /* 193 */ "cmd",
+ /* 194 */ "transtype",
+ /* 195 */ "trans_opt",
+ /* 196 */ "nm",
+ /* 197 */ "savepoint_opt",
+ /* 198 */ "create_table",
+ /* 199 */ "create_table_args",
+ /* 200 */ "createkw",
+ /* 201 */ "temp",
+ /* 202 */ "ifnotexists",
+ /* 203 */ "dbnm",
+ /* 204 */ "columnlist",
+ /* 205 */ "conslist_opt",
+ /* 206 */ "table_option_set",
+ /* 207 */ "select",
+ /* 208 */ "table_option",
+ /* 209 */ "columnname",
+ /* 210 */ "carglist",
+ /* 211 */ "typetoken",
+ /* 212 */ "typename",
+ /* 213 */ "signed",
+ /* 214 */ "plus_num",
+ /* 215 */ "minus_num",
+ /* 216 */ "scanpt",
+ /* 217 */ "scantok",
+ /* 218 */ "ccons",
+ /* 219 */ "term",
+ /* 220 */ "expr",
+ /* 221 */ "onconf",
+ /* 222 */ "sortorder",
+ /* 223 */ "autoinc",
+ /* 224 */ "eidlist_opt",
+ /* 225 */ "refargs",
+ /* 226 */ "defer_subclause",
+ /* 227 */ "generated",
+ /* 228 */ "refarg",
+ /* 229 */ "refact",
+ /* 230 */ "init_deferred_pred_opt",
+ /* 231 */ "conslist",
+ /* 232 */ "tconscomma",
+ /* 233 */ "tcons",
+ /* 234 */ "sortlist",
+ /* 235 */ "eidlist",
+ /* 236 */ "defer_subclause_opt",
+ /* 237 */ "orconf",
+ /* 238 */ "resolvetype",
+ /* 239 */ "raisetype",
+ /* 240 */ "ifexists",
+ /* 241 */ "fullname",
+ /* 242 */ "selectnowith",
+ /* 243 */ "oneselect",
+ /* 244 */ "wqlist",
+ /* 245 */ "multiselect_op",
+ /* 246 */ "distinct",
+ /* 247 */ "selcollist",
+ /* 248 */ "from",
+ /* 249 */ "where_opt",
+ /* 250 */ "groupby_opt",
+ /* 251 */ "having_opt",
+ /* 252 */ "orderby_opt",
+ /* 253 */ "limit_opt",
+ /* 254 */ "window_clause",
+ /* 255 */ "values",
+ /* 256 */ "nexprlist",
+ /* 257 */ "sclp",
+ /* 258 */ "as",
+ /* 259 */ "seltablist",
+ /* 260 */ "stl_prefix",
+ /* 261 */ "joinop",
+ /* 262 */ "on_using",
+ /* 263 */ "indexed_by",
+ /* 264 */ "exprlist",
+ /* 265 */ "xfullname",
+ /* 266 */ "idlist",
+ /* 267 */ "indexed_opt",
+ /* 268 */ "nulls",
+ /* 269 */ "with",
+ /* 270 */ "where_opt_ret",
+ /* 271 */ "setlist",
+ /* 272 */ "insert_cmd",
+ /* 273 */ "idlist_opt",
+ /* 274 */ "upsert",
+ /* 275 */ "returning",
+ /* 276 */ "filter_over",
+ /* 277 */ "likeop",
+ /* 278 */ "between_op",
+ /* 279 */ "in_op",
+ /* 280 */ "paren_exprlist",
+ /* 281 */ "case_operand",
+ /* 282 */ "case_exprlist",
+ /* 283 */ "case_else",
+ /* 284 */ "uniqueflag",
+ /* 285 */ "collate",
+ /* 286 */ "vinto",
+ /* 287 */ "nmnum",
+ /* 288 */ "trigger_decl",
+ /* 289 */ "trigger_cmd_list",
+ /* 290 */ "trigger_time",
+ /* 291 */ "trigger_event",
+ /* 292 */ "foreach_clause",
+ /* 293 */ "when_clause",
+ /* 294 */ "trigger_cmd",
+ /* 295 */ "trnm",
+ /* 296 */ "tridxby",
+ /* 297 */ "database_kw_opt",
+ /* 298 */ "key_opt",
+ /* 299 */ "add_column_fullname",
+ /* 300 */ "kwcolumn_opt",
+ /* 301 */ "create_vtab",
+ /* 302 */ "vtabarglist",
+ /* 303 */ "vtabarg",
+ /* 304 */ "vtabargtoken",
+ /* 305 */ "lp",
+ /* 306 */ "anylist",
+ /* 307 */ "wqitem",
+ /* 308 */ "wqas",
+ /* 309 */ "windowdefn_list",
+ /* 310 */ "windowdefn",
+ /* 311 */ "window",
+ /* 312 */ "frame_opt",
+ /* 313 */ "part_opt",
+ /* 314 */ "filter_clause",
+ /* 315 */ "over_clause",
+ /* 316 */ "range_or_rows",
+ /* 317 */ "frame_bound",
+ /* 318 */ "frame_bound_s",
+ /* 319 */ "frame_bound_e",
+ /* 320 */ "frame_exclude_opt",
+ /* 321 */ "frame_exclude",
};
#endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */
@@ -169994,182 +173658,182 @@ static const char *const yyRuleName[] = {
/* 5 */ "transtype ::= DEFERRED",
/* 6 */ "transtype ::= IMMEDIATE",
/* 7 */ "transtype ::= EXCLUSIVE",
- /* 8 */ "cmd ::= COMMIT|END trans_opt",
- /* 9 */ "cmd ::= ROLLBACK trans_opt",
- /* 10 */ "cmd ::= SAVEPOINT nm",
- /* 11 */ "cmd ::= RELEASE savepoint_opt nm",
- /* 12 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm",
- /* 13 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm",
- /* 14 */ "createkw ::= CREATE",
- /* 15 */ "ifnotexists ::=",
- /* 16 */ "ifnotexists ::= IF NOT EXISTS",
- /* 17 */ "temp ::= TEMP",
- /* 18 */ "temp ::=",
- /* 19 */ "create_table_args ::= LP columnlist conslist_opt RP table_option_set",
- /* 20 */ "create_table_args ::= AS select",
- /* 21 */ "table_option_set ::=",
- /* 22 */ "table_option_set ::= table_option_set COMMA table_option",
- /* 23 */ "table_option ::= WITHOUT nm",
- /* 24 */ "table_option ::= RANDOM nm",
- /* 25 */ "table_option ::= nm",
- /* 26 */ "columnname ::= nm typetoken",
- /* 27 */ "typetoken ::=",
- /* 28 */ "typetoken ::= typename LP signed RP",
- /* 29 */ "typetoken ::= typename LP signed COMMA signed RP",
- /* 30 */ "typename ::= typename ID|STRING",
- /* 31 */ "scanpt ::=",
- /* 32 */ "scantok ::=",
- /* 33 */ "ccons ::= CONSTRAINT nm",
- /* 34 */ "ccons ::= DEFAULT scantok term",
- /* 35 */ "ccons ::= DEFAULT LP expr RP",
- /* 36 */ "ccons ::= DEFAULT PLUS scantok term",
- /* 37 */ "ccons ::= DEFAULT MINUS scantok term",
- /* 38 */ "ccons ::= DEFAULT scantok ID|INDEXED",
- /* 39 */ "ccons ::= NOT NULL onconf",
- /* 40 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
- /* 41 */ "ccons ::= UNIQUE onconf",
- /* 42 */ "ccons ::= CHECK LP expr RP",
- /* 43 */ "ccons ::= REFERENCES nm eidlist_opt refargs",
- /* 44 */ "ccons ::= defer_subclause",
- /* 45 */ "ccons ::= COLLATE ID|STRING",
- /* 46 */ "generated ::= LP expr RP",
- /* 47 */ "generated ::= LP expr RP ID",
- /* 48 */ "autoinc ::=",
- /* 49 */ "autoinc ::= AUTOINCR",
- /* 50 */ "refargs ::=",
- /* 51 */ "refargs ::= refargs refarg",
- /* 52 */ "refarg ::= MATCH nm",
- /* 53 */ "refarg ::= ON INSERT refact",
- /* 54 */ "refarg ::= ON DELETE refact",
- /* 55 */ "refarg ::= ON UPDATE refact",
- /* 56 */ "refact ::= SET NULL",
- /* 57 */ "refact ::= SET DEFAULT",
- /* 58 */ "refact ::= CASCADE",
- /* 59 */ "refact ::= RESTRICT",
- /* 60 */ "refact ::= NO ACTION",
- /* 61 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
- /* 62 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
- /* 63 */ "init_deferred_pred_opt ::=",
- /* 64 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
- /* 65 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
- /* 66 */ "conslist_opt ::=",
- /* 67 */ "tconscomma ::= COMMA",
- /* 68 */ "tcons ::= CONSTRAINT nm",
- /* 69 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf",
- /* 70 */ "tcons ::= UNIQUE LP sortlist RP onconf",
- /* 71 */ "tcons ::= CHECK LP expr RP onconf",
- /* 72 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt",
- /* 73 */ "defer_subclause_opt ::=",
- /* 74 */ "onconf ::=",
- /* 75 */ "onconf ::= ON CONFLICT resolvetype",
- /* 76 */ "orconf ::=",
- /* 77 */ "orconf ::= OR resolvetype",
- /* 78 */ "resolvetype ::= IGNORE",
- /* 79 */ "resolvetype ::= REPLACE",
- /* 80 */ "cmd ::= DROP TABLE ifexists fullname",
- /* 81 */ "ifexists ::= IF EXISTS",
- /* 82 */ "ifexists ::=",
- /* 83 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select",
- /* 84 */ "cmd ::= DROP VIEW ifexists fullname",
- /* 85 */ "cmd ::= createkw FUNCTION ifnotexists nm LANGUAGE nm AS STRING",
- /* 86 */ "cmd ::= createkw FUNCTION ifnotexists nm LANGUAGE nm AS BLOB",
- /* 87 */ "cmd ::= DROP FUNCTION ifexists nm",
- /* 88 */ "cmd ::= select",
- /* 89 */ "select ::= WITH wqlist selectnowith",
- /* 90 */ "select ::= WITH RECURSIVE wqlist selectnowith",
- /* 91 */ "select ::= selectnowith",
- /* 92 */ "selectnowith ::= selectnowith multiselect_op oneselect",
- /* 93 */ "multiselect_op ::= UNION",
- /* 94 */ "multiselect_op ::= UNION ALL",
- /* 95 */ "multiselect_op ::= EXCEPT|INTERSECT",
- /* 96 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
- /* 97 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt",
- /* 98 */ "values ::= VALUES LP nexprlist RP",
- /* 99 */ "values ::= values COMMA LP nexprlist RP",
- /* 100 */ "distinct ::= DISTINCT",
- /* 101 */ "distinct ::= ALL",
- /* 102 */ "distinct ::=",
- /* 103 */ "sclp ::=",
- /* 104 */ "selcollist ::= sclp scanpt expr scanpt as",
- /* 105 */ "selcollist ::= sclp scanpt STAR",
- /* 106 */ "selcollist ::= sclp scanpt nm DOT STAR",
- /* 107 */ "as ::= AS nm",
- /* 108 */ "as ::=",
- /* 109 */ "from ::=",
- /* 110 */ "from ::= FROM seltablist",
- /* 111 */ "stl_prefix ::= seltablist joinop",
- /* 112 */ "stl_prefix ::=",
- /* 113 */ "seltablist ::= stl_prefix nm dbnm as on_using",
- /* 114 */ "seltablist ::= stl_prefix nm dbnm as indexed_by on_using",
- /* 115 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using",
- /* 116 */ "seltablist ::= stl_prefix LP select RP as on_using",
- /* 117 */ "seltablist ::= stl_prefix LP seltablist RP as on_using",
- /* 118 */ "dbnm ::=",
- /* 119 */ "dbnm ::= DOT nm",
- /* 120 */ "fullname ::= nm",
- /* 121 */ "fullname ::= nm DOT nm",
- /* 122 */ "xfullname ::= nm",
- /* 123 */ "xfullname ::= nm DOT nm",
- /* 124 */ "xfullname ::= nm DOT nm AS nm",
- /* 125 */ "xfullname ::= nm AS nm",
- /* 126 */ "joinop ::= COMMA|JOIN",
- /* 127 */ "joinop ::= JOIN_KW JOIN",
- /* 128 */ "joinop ::= JOIN_KW nm JOIN",
- /* 129 */ "joinop ::= JOIN_KW nm nm JOIN",
- /* 130 */ "on_using ::= ON expr",
- /* 131 */ "on_using ::= USING LP idlist RP",
- /* 132 */ "on_using ::=",
- /* 133 */ "indexed_opt ::=",
- /* 134 */ "indexed_by ::= INDEXED BY nm",
- /* 135 */ "indexed_by ::= NOT INDEXED",
- /* 136 */ "orderby_opt ::=",
- /* 137 */ "orderby_opt ::= ORDER BY sortlist",
- /* 138 */ "sortlist ::= sortlist COMMA expr sortorder nulls",
- /* 139 */ "sortlist ::= expr sortorder nulls",
- /* 140 */ "sortorder ::= ASC",
- /* 141 */ "sortorder ::= DESC",
- /* 142 */ "sortorder ::=",
- /* 143 */ "nulls ::= NULLS FIRST",
- /* 144 */ "nulls ::= NULLS LAST",
- /* 145 */ "nulls ::=",
- /* 146 */ "groupby_opt ::=",
- /* 147 */ "groupby_opt ::= GROUP BY nexprlist",
- /* 148 */ "having_opt ::=",
- /* 149 */ "having_opt ::= HAVING expr",
- /* 150 */ "limit_opt ::=",
- /* 151 */ "limit_opt ::= LIMIT expr",
- /* 152 */ "limit_opt ::= LIMIT expr OFFSET expr",
- /* 153 */ "limit_opt ::= LIMIT expr COMMA expr",
- /* 154 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret",
- /* 155 */ "where_opt ::=",
- /* 156 */ "where_opt ::= WHERE expr",
- /* 157 */ "where_opt_ret ::=",
- /* 158 */ "where_opt_ret ::= WHERE expr",
- /* 159 */ "where_opt_ret ::= RETURNING selcollist",
- /* 160 */ "where_opt_ret ::= WHERE expr RETURNING selcollist",
- /* 161 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret",
- /* 162 */ "setlist ::= setlist COMMA nm EQ expr",
- /* 163 */ "setlist ::= setlist COMMA LP idlist RP EQ expr",
- /* 164 */ "setlist ::= nm EQ expr",
- /* 165 */ "setlist ::= LP idlist RP EQ expr",
- /* 166 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert",
- /* 167 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning",
- /* 168 */ "upsert ::=",
- /* 169 */ "upsert ::= RETURNING selcollist",
- /* 170 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert",
- /* 171 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert",
- /* 172 */ "upsert ::= ON CONFLICT DO NOTHING returning",
- /* 173 */ "upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning",
- /* 174 */ "returning ::= RETURNING selcollist",
- /* 175 */ "insert_cmd ::= INSERT orconf",
- /* 176 */ "insert_cmd ::= REPLACE",
- /* 177 */ "idlist_opt ::=",
- /* 178 */ "idlist_opt ::= LP idlist RP",
- /* 179 */ "idlist ::= idlist COMMA nm",
- /* 180 */ "idlist ::= nm",
- /* 181 */ "expr ::= LP expr RP",
- /* 182 */ "expr ::= ID|INDEXED",
- /* 183 */ "expr ::= JOIN_KW",
+ /* 8 */ "transtype ::= READONLY",
+ /* 9 */ "cmd ::= COMMIT|END trans_opt",
+ /* 10 */ "cmd ::= ROLLBACK trans_opt",
+ /* 11 */ "cmd ::= SAVEPOINT nm",
+ /* 12 */ "cmd ::= RELEASE savepoint_opt nm",
+ /* 13 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm",
+ /* 14 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm",
+ /* 15 */ "createkw ::= CREATE",
+ /* 16 */ "ifnotexists ::=",
+ /* 17 */ "ifnotexists ::= IF NOT EXISTS",
+ /* 18 */ "temp ::= TEMP",
+ /* 19 */ "temp ::=",
+ /* 20 */ "create_table_args ::= LP columnlist conslist_opt RP table_option_set",
+ /* 21 */ "create_table_args ::= AS select",
+ /* 22 */ "table_option_set ::=",
+ /* 23 */ "table_option_set ::= table_option_set COMMA table_option",
+ /* 24 */ "table_option ::= WITHOUT nm",
+ /* 25 */ "table_option ::= RANDOM nm",
+ /* 26 */ "table_option ::= nm",
+ /* 27 */ "columnname ::= nm typetoken",
+ /* 28 */ "typetoken ::=",
+ /* 29 */ "typetoken ::= typename LP signed RP",
+ /* 30 */ "typetoken ::= typename LP signed COMMA signed RP",
+ /* 31 */ "typename ::= typename ID|STRING",
+ /* 32 */ "scanpt ::=",
+ /* 33 */ "scantok ::=",
+ /* 34 */ "ccons ::= CONSTRAINT nm",
+ /* 35 */ "ccons ::= DEFAULT scantok term",
+ /* 36 */ "ccons ::= DEFAULT LP expr RP",
+ /* 37 */ "ccons ::= DEFAULT PLUS scantok term",
+ /* 38 */ "ccons ::= DEFAULT MINUS scantok term",
+ /* 39 */ "ccons ::= DEFAULT scantok ID|INDEXED",
+ /* 40 */ "ccons ::= NOT NULL onconf",
+ /* 41 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
+ /* 42 */ "ccons ::= UNIQUE onconf",
+ /* 43 */ "ccons ::= CHECK LP expr RP",
+ /* 44 */ "ccons ::= REFERENCES nm eidlist_opt refargs",
+ /* 45 */ "ccons ::= defer_subclause",
+ /* 46 */ "ccons ::= COLLATE ID|STRING",
+ /* 47 */ "generated ::= LP expr RP",
+ /* 48 */ "generated ::= LP expr RP ID",
+ /* 49 */ "autoinc ::=",
+ /* 50 */ "autoinc ::= AUTOINCR",
+ /* 51 */ "refargs ::=",
+ /* 52 */ "refargs ::= refargs refarg",
+ /* 53 */ "refarg ::= MATCH nm",
+ /* 54 */ "refarg ::= ON INSERT refact",
+ /* 55 */ "refarg ::= ON DELETE refact",
+ /* 56 */ "refarg ::= ON UPDATE refact",
+ /* 57 */ "refact ::= SET NULL",
+ /* 58 */ "refact ::= SET DEFAULT",
+ /* 59 */ "refact ::= CASCADE",
+ /* 60 */ "refact ::= RESTRICT",
+ /* 61 */ "refact ::= NO ACTION",
+ /* 62 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
+ /* 63 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
+ /* 64 */ "init_deferred_pred_opt ::=",
+ /* 65 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
+ /* 66 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
+ /* 67 */ "conslist_opt ::=",
+ /* 68 */ "tconscomma ::= COMMA",
+ /* 69 */ "tcons ::= CONSTRAINT nm",
+ /* 70 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf",
+ /* 71 */ "tcons ::= UNIQUE LP sortlist RP onconf",
+ /* 72 */ "tcons ::= CHECK LP expr RP onconf",
+ /* 73 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt",
+ /* 74 */ "defer_subclause_opt ::=",
+ /* 75 */ "onconf ::=",
+ /* 76 */ "onconf ::= ON CONFLICT resolvetype",
+ /* 77 */ "orconf ::=",
+ /* 78 */ "orconf ::= OR resolvetype",
+ /* 79 */ "resolvetype ::= IGNORE",
+ /* 80 */ "resolvetype ::= REPLACE",
+ /* 81 */ "cmd ::= DROP TABLE ifexists fullname",
+ /* 82 */ "ifexists ::= IF EXISTS",
+ /* 83 */ "ifexists ::=",
+ /* 84 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select",
+ /* 85 */ "cmd ::= DROP VIEW ifexists fullname",
+ /* 86 */ "cmd ::= createkw FUNCTION ifnotexists nm LANGUAGE nm AS STRING",
+ /* 87 */ "cmd ::= createkw FUNCTION ifnotexists nm LANGUAGE nm AS BLOB",
+ /* 88 */ "cmd ::= DROP FUNCTION ifexists nm",
+ /* 89 */ "cmd ::= select",
+ /* 90 */ "select ::= WITH wqlist selectnowith",
+ /* 91 */ "select ::= WITH RECURSIVE wqlist selectnowith",
+ /* 92 */ "select ::= selectnowith",
+ /* 93 */ "selectnowith ::= selectnowith multiselect_op oneselect",
+ /* 94 */ "multiselect_op ::= UNION",
+ /* 95 */ "multiselect_op ::= UNION ALL",
+ /* 96 */ "multiselect_op ::= EXCEPT|INTERSECT",
+ /* 97 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
+ /* 98 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt",
+ /* 99 */ "values ::= VALUES LP nexprlist RP",
+ /* 100 */ "values ::= values COMMA LP nexprlist RP",
+ /* 101 */ "distinct ::= DISTINCT",
+ /* 102 */ "distinct ::= ALL",
+ /* 103 */ "distinct ::=",
+ /* 104 */ "sclp ::=",
+ /* 105 */ "selcollist ::= sclp scanpt expr scanpt as",
+ /* 106 */ "selcollist ::= sclp scanpt STAR",
+ /* 107 */ "selcollist ::= sclp scanpt nm DOT STAR",
+ /* 108 */ "as ::= AS nm",
+ /* 109 */ "as ::=",
+ /* 110 */ "from ::=",
+ /* 111 */ "from ::= FROM seltablist",
+ /* 112 */ "stl_prefix ::= seltablist joinop",
+ /* 113 */ "stl_prefix ::=",
+ /* 114 */ "seltablist ::= stl_prefix nm dbnm as on_using",
+ /* 115 */ "seltablist ::= stl_prefix nm dbnm as indexed_by on_using",
+ /* 116 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using",
+ /* 117 */ "seltablist ::= stl_prefix LP select RP as on_using",
+ /* 118 */ "seltablist ::= stl_prefix LP seltablist RP as on_using",
+ /* 119 */ "dbnm ::=",
+ /* 120 */ "dbnm ::= DOT nm",
+ /* 121 */ "fullname ::= nm",
+ /* 122 */ "fullname ::= nm DOT nm",
+ /* 123 */ "xfullname ::= nm",
+ /* 124 */ "xfullname ::= nm DOT nm",
+ /* 125 */ "xfullname ::= nm DOT nm AS nm",
+ /* 126 */ "xfullname ::= nm AS nm",
+ /* 127 */ "joinop ::= COMMA|JOIN",
+ /* 128 */ "joinop ::= JOIN_KW JOIN",
+ /* 129 */ "joinop ::= JOIN_KW nm JOIN",
+ /* 130 */ "joinop ::= JOIN_KW nm nm JOIN",
+ /* 131 */ "on_using ::= ON expr",
+ /* 132 */ "on_using ::= USING LP idlist RP",
+ /* 133 */ "on_using ::=",
+ /* 134 */ "indexed_opt ::=",
+ /* 135 */ "indexed_by ::= INDEXED BY nm",
+ /* 136 */ "indexed_by ::= NOT INDEXED",
+ /* 137 */ "orderby_opt ::=",
+ /* 138 */ "orderby_opt ::= ORDER BY sortlist",
+ /* 139 */ "sortlist ::= sortlist COMMA expr sortorder nulls",
+ /* 140 */ "sortlist ::= expr sortorder nulls",
+ /* 141 */ "sortorder ::= ASC",
+ /* 142 */ "sortorder ::= DESC",
+ /* 143 */ "sortorder ::=",
+ /* 144 */ "nulls ::= NULLS FIRST",
+ /* 145 */ "nulls ::= NULLS LAST",
+ /* 146 */ "nulls ::=",
+ /* 147 */ "groupby_opt ::=",
+ /* 148 */ "groupby_opt ::= GROUP BY nexprlist",
+ /* 149 */ "having_opt ::=",
+ /* 150 */ "having_opt ::= HAVING expr",
+ /* 151 */ "limit_opt ::=",
+ /* 152 */ "limit_opt ::= LIMIT expr",
+ /* 153 */ "limit_opt ::= LIMIT expr OFFSET expr",
+ /* 154 */ "limit_opt ::= LIMIT expr COMMA expr",
+ /* 155 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret",
+ /* 156 */ "where_opt ::=",
+ /* 157 */ "where_opt ::= WHERE expr",
+ /* 158 */ "where_opt_ret ::=",
+ /* 159 */ "where_opt_ret ::= WHERE expr",
+ /* 160 */ "where_opt_ret ::= RETURNING selcollist",
+ /* 161 */ "where_opt_ret ::= WHERE expr RETURNING selcollist",
+ /* 162 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret",
+ /* 163 */ "setlist ::= setlist COMMA nm EQ expr",
+ /* 164 */ "setlist ::= setlist COMMA LP idlist RP EQ expr",
+ /* 165 */ "setlist ::= nm EQ expr",
+ /* 166 */ "setlist ::= LP idlist RP EQ expr",
+ /* 167 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert",
+ /* 168 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning",
+ /* 169 */ "upsert ::=",
+ /* 170 */ "upsert ::= RETURNING selcollist",
+ /* 171 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert",
+ /* 172 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert",
+ /* 173 */ "upsert ::= ON CONFLICT DO NOTHING returning",
+ /* 174 */ "upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning",
+ /* 175 */ "returning ::= RETURNING selcollist",
+ /* 176 */ "insert_cmd ::= INSERT orconf",
+ /* 177 */ "insert_cmd ::= REPLACE",
+ /* 178 */ "idlist_opt ::=",
+ /* 179 */ "idlist_opt ::= LP idlist RP",
+ /* 180 */ "idlist ::= idlist COMMA nm",
+ /* 181 */ "idlist ::= nm",
+ /* 182 */ "expr ::= LP expr RP",
+ /* 183 */ "expr ::= ID|INDEXED|JOIN_KW",
/* 184 */ "expr ::= nm DOT nm",
/* 185 */ "expr ::= nm DOT nm DOT nm",
/* 186 */ "term ::= NULL|FLOAT|BLOB",
@@ -170178,137 +173842,137 @@ static const char *const yyRuleName[] = {
/* 189 */ "expr ::= VARIABLE",
/* 190 */ "expr ::= expr COLLATE ID|STRING",
/* 191 */ "expr ::= CAST LP expr AS typetoken RP",
- /* 192 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
- /* 193 */ "expr ::= ID|INDEXED LP STAR RP",
- /* 194 */ "expr ::= ID|INDEXED LP distinct exprlist RP filter_over",
- /* 195 */ "expr ::= ID|INDEXED LP STAR RP filter_over",
- /* 196 */ "term ::= CTIME_KW",
- /* 197 */ "expr ::= LP nexprlist COMMA expr RP",
- /* 198 */ "expr ::= expr AND expr",
- /* 199 */ "expr ::= expr OR expr",
- /* 200 */ "expr ::= expr LT|GT|GE|LE expr",
- /* 201 */ "expr ::= expr EQ|NE expr",
- /* 202 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
- /* 203 */ "expr ::= expr PLUS|MINUS expr",
- /* 204 */ "expr ::= expr STAR|SLASH|REM expr",
- /* 205 */ "expr ::= expr CONCAT expr",
- /* 206 */ "likeop ::= NOT LIKE_KW|MATCH",
- /* 207 */ "expr ::= expr likeop expr",
- /* 208 */ "expr ::= expr likeop expr ESCAPE expr",
- /* 209 */ "expr ::= expr ISNULL|NOTNULL",
- /* 210 */ "expr ::= expr NOT NULL",
- /* 211 */ "expr ::= expr IS expr",
- /* 212 */ "expr ::= expr IS NOT expr",
- /* 213 */ "expr ::= expr IS NOT DISTINCT FROM expr",
- /* 214 */ "expr ::= expr IS DISTINCT FROM expr",
- /* 215 */ "expr ::= NOT expr",
- /* 216 */ "expr ::= BITNOT expr",
- /* 217 */ "expr ::= PLUS|MINUS expr",
- /* 218 */ "expr ::= expr PTR expr",
- /* 219 */ "between_op ::= BETWEEN",
- /* 220 */ "between_op ::= NOT BETWEEN",
- /* 221 */ "expr ::= expr between_op expr AND expr",
- /* 222 */ "in_op ::= IN",
- /* 223 */ "in_op ::= NOT IN",
- /* 224 */ "expr ::= expr in_op LP exprlist RP",
- /* 225 */ "expr ::= LP select RP",
- /* 226 */ "expr ::= expr in_op LP select RP",
- /* 227 */ "expr ::= expr in_op nm dbnm paren_exprlist",
- /* 228 */ "expr ::= EXISTS LP select RP",
- /* 229 */ "expr ::= CASE case_operand case_exprlist case_else END",
- /* 230 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
- /* 231 */ "case_exprlist ::= WHEN expr THEN expr",
- /* 232 */ "case_else ::= ELSE expr",
- /* 233 */ "case_else ::=",
- /* 234 */ "case_operand ::= expr",
- /* 235 */ "case_operand ::=",
- /* 236 */ "exprlist ::=",
- /* 237 */ "nexprlist ::= nexprlist COMMA expr",
- /* 238 */ "nexprlist ::= expr",
- /* 239 */ "paren_exprlist ::=",
- /* 240 */ "paren_exprlist ::= LP exprlist RP",
- /* 241 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
- /* 242 */ "uniqueflag ::= UNIQUE",
- /* 243 */ "uniqueflag ::=",
- /* 244 */ "eidlist_opt ::=",
- /* 245 */ "eidlist_opt ::= LP eidlist RP",
- /* 246 */ "eidlist ::= eidlist COMMA nm collate sortorder",
- /* 247 */ "eidlist ::= nm collate sortorder",
- /* 248 */ "collate ::=",
- /* 249 */ "collate ::= COLLATE ID|STRING",
- /* 250 */ "cmd ::= DROP INDEX ifexists fullname",
- /* 251 */ "cmd ::= VACUUM vinto",
- /* 252 */ "cmd ::= VACUUM nm vinto",
- /* 253 */ "vinto ::= INTO expr",
- /* 254 */ "vinto ::=",
- /* 255 */ "cmd ::= PRAGMA nm dbnm",
- /* 256 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
- /* 257 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
- /* 258 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
- /* 259 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
- /* 260 */ "plus_num ::= PLUS INTEGER|FLOAT",
- /* 261 */ "minus_num ::= MINUS INTEGER|FLOAT",
- /* 262 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
- /* 263 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
- /* 264 */ "trigger_time ::= BEFORE|AFTER",
- /* 265 */ "trigger_time ::= INSTEAD OF",
- /* 266 */ "trigger_time ::=",
- /* 267 */ "trigger_event ::= DELETE|INSERT",
- /* 268 */ "trigger_event ::= UPDATE",
- /* 269 */ "trigger_event ::= UPDATE OF idlist",
- /* 270 */ "when_clause ::=",
- /* 271 */ "when_clause ::= WHEN expr",
- /* 272 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
- /* 273 */ "trigger_cmd_list ::= trigger_cmd SEMI",
- /* 274 */ "trnm ::= nm DOT nm",
- /* 275 */ "tridxby ::= INDEXED BY nm",
- /* 276 */ "tridxby ::= NOT INDEXED",
- /* 277 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt",
- /* 278 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt",
- /* 279 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt",
- /* 280 */ "trigger_cmd ::= scanpt select scanpt",
- /* 281 */ "expr ::= RAISE LP IGNORE RP",
- /* 282 */ "expr ::= RAISE LP raisetype COMMA nm RP",
- /* 283 */ "raisetype ::= ROLLBACK",
- /* 284 */ "raisetype ::= ABORT",
- /* 285 */ "raisetype ::= FAIL",
- /* 286 */ "cmd ::= DROP TRIGGER ifexists fullname",
- /* 287 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
- /* 288 */ "cmd ::= DETACH database_kw_opt expr",
- /* 289 */ "key_opt ::=",
- /* 290 */ "key_opt ::= KEY expr",
- /* 291 */ "cmd ::= REINDEX",
- /* 292 */ "cmd ::= REINDEX nm dbnm",
- /* 293 */ "cmd ::= ANALYZE",
- /* 294 */ "cmd ::= ANALYZE nm dbnm",
- /* 295 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
- /* 296 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
- /* 297 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm",
- /* 298 */ "add_column_fullname ::= fullname",
- /* 299 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm",
- /* 300 */ "cmd ::= create_vtab",
- /* 301 */ "cmd ::= create_vtab LP vtabarglist RP",
- /* 302 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
- /* 303 */ "vtabarg ::=",
- /* 304 */ "vtabargtoken ::= ANY",
- /* 305 */ "vtabargtoken ::= lp anylist RP",
- /* 306 */ "lp ::= LP",
- /* 307 */ "with ::= WITH wqlist",
- /* 308 */ "with ::= WITH RECURSIVE wqlist",
- /* 309 */ "wqas ::= AS",
- /* 310 */ "wqas ::= AS MATERIALIZED",
- /* 311 */ "wqas ::= AS NOT MATERIALIZED",
- /* 312 */ "wqitem ::= nm eidlist_opt wqas LP select RP",
- /* 313 */ "wqlist ::= wqitem",
- /* 314 */ "wqlist ::= wqlist COMMA wqitem",
- /* 315 */ "windowdefn_list ::= windowdefn",
- /* 316 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn",
- /* 317 */ "windowdefn ::= nm AS LP window RP",
- /* 318 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt",
- /* 319 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt",
- /* 320 */ "window ::= ORDER BY sortlist frame_opt",
- /* 321 */ "window ::= nm ORDER BY sortlist frame_opt",
- /* 322 */ "window ::= frame_opt",
+ /* 192 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP",
+ /* 193 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP",
+ /* 194 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP",
+ /* 195 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over",
+ /* 196 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over",
+ /* 197 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over",
+ /* 198 */ "term ::= CTIME_KW",
+ /* 199 */ "expr ::= LP nexprlist COMMA expr RP",
+ /* 200 */ "expr ::= expr AND expr",
+ /* 201 */ "expr ::= expr OR expr",
+ /* 202 */ "expr ::= expr LT|GT|GE|LE expr",
+ /* 203 */ "expr ::= expr EQ|NE expr",
+ /* 204 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
+ /* 205 */ "expr ::= expr PLUS|MINUS expr",
+ /* 206 */ "expr ::= expr STAR|SLASH|REM expr",
+ /* 207 */ "expr ::= expr CONCAT expr",
+ /* 208 */ "likeop ::= NOT LIKE_KW|MATCH",
+ /* 209 */ "expr ::= expr likeop expr",
+ /* 210 */ "expr ::= expr likeop expr ESCAPE expr",
+ /* 211 */ "expr ::= expr ISNULL|NOTNULL",
+ /* 212 */ "expr ::= expr NOT NULL",
+ /* 213 */ "expr ::= expr IS expr",
+ /* 214 */ "expr ::= expr IS NOT expr",
+ /* 215 */ "expr ::= expr IS NOT DISTINCT FROM expr",
+ /* 216 */ "expr ::= expr IS DISTINCT FROM expr",
+ /* 217 */ "expr ::= NOT expr",
+ /* 218 */ "expr ::= BITNOT expr",
+ /* 219 */ "expr ::= PLUS|MINUS expr",
+ /* 220 */ "expr ::= expr PTR expr",
+ /* 221 */ "between_op ::= BETWEEN",
+ /* 222 */ "between_op ::= NOT BETWEEN",
+ /* 223 */ "expr ::= expr between_op expr AND expr",
+ /* 224 */ "in_op ::= IN",
+ /* 225 */ "in_op ::= NOT IN",
+ /* 226 */ "expr ::= expr in_op LP exprlist RP",
+ /* 227 */ "expr ::= LP select RP",
+ /* 228 */ "expr ::= expr in_op LP select RP",
+ /* 229 */ "expr ::= expr in_op nm dbnm paren_exprlist",
+ /* 230 */ "expr ::= EXISTS LP select RP",
+ /* 231 */ "expr ::= CASE case_operand case_exprlist case_else END",
+ /* 232 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
+ /* 233 */ "case_exprlist ::= WHEN expr THEN expr",
+ /* 234 */ "case_else ::= ELSE expr",
+ /* 235 */ "case_else ::=",
+ /* 236 */ "case_operand ::=",
+ /* 237 */ "exprlist ::=",
+ /* 238 */ "nexprlist ::= nexprlist COMMA expr",
+ /* 239 */ "nexprlist ::= expr",
+ /* 240 */ "paren_exprlist ::=",
+ /* 241 */ "paren_exprlist ::= LP exprlist RP",
+ /* 242 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
+ /* 243 */ "uniqueflag ::= UNIQUE",
+ /* 244 */ "uniqueflag ::=",
+ /* 245 */ "eidlist_opt ::=",
+ /* 246 */ "eidlist_opt ::= LP eidlist RP",
+ /* 247 */ "eidlist ::= eidlist COMMA nm collate sortorder",
+ /* 248 */ "eidlist ::= nm collate sortorder",
+ /* 249 */ "collate ::=",
+ /* 250 */ "collate ::= COLLATE ID|STRING",
+ /* 251 */ "cmd ::= DROP INDEX ifexists fullname",
+ /* 252 */ "cmd ::= VACUUM vinto",
+ /* 253 */ "cmd ::= VACUUM nm vinto",
+ /* 254 */ "vinto ::= INTO expr",
+ /* 255 */ "vinto ::=",
+ /* 256 */ "cmd ::= PRAGMA nm dbnm",
+ /* 257 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
+ /* 258 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
+ /* 259 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
+ /* 260 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
+ /* 261 */ "plus_num ::= PLUS INTEGER|FLOAT",
+ /* 262 */ "minus_num ::= MINUS INTEGER|FLOAT",
+ /* 263 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
+ /* 264 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
+ /* 265 */ "trigger_time ::= BEFORE|AFTER",
+ /* 266 */ "trigger_time ::= INSTEAD OF",
+ /* 267 */ "trigger_time ::=",
+ /* 268 */ "trigger_event ::= DELETE|INSERT",
+ /* 269 */ "trigger_event ::= UPDATE",
+ /* 270 */ "trigger_event ::= UPDATE OF idlist",
+ /* 271 */ "when_clause ::=",
+ /* 272 */ "when_clause ::= WHEN expr",
+ /* 273 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
+ /* 274 */ "trigger_cmd_list ::= trigger_cmd SEMI",
+ /* 275 */ "trnm ::= nm DOT nm",
+ /* 276 */ "tridxby ::= INDEXED BY nm",
+ /* 277 */ "tridxby ::= NOT INDEXED",
+ /* 278 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt",
+ /* 279 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt",
+ /* 280 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt",
+ /* 281 */ "trigger_cmd ::= scanpt select scanpt",
+ /* 282 */ "expr ::= RAISE LP IGNORE RP",
+ /* 283 */ "expr ::= RAISE LP raisetype COMMA nm RP",
+ /* 284 */ "raisetype ::= ROLLBACK",
+ /* 285 */ "raisetype ::= ABORT",
+ /* 286 */ "raisetype ::= FAIL",
+ /* 287 */ "cmd ::= DROP TRIGGER ifexists fullname",
+ /* 288 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
+ /* 289 */ "cmd ::= DETACH database_kw_opt expr",
+ /* 290 */ "key_opt ::=",
+ /* 291 */ "key_opt ::= KEY expr",
+ /* 292 */ "cmd ::= REINDEX",
+ /* 293 */ "cmd ::= REINDEX nm dbnm",
+ /* 294 */ "cmd ::= ANALYZE",
+ /* 295 */ "cmd ::= ANALYZE nm dbnm",
+ /* 296 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
+ /* 297 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
+ /* 298 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm",
+ /* 299 */ "add_column_fullname ::= fullname",
+ /* 300 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm",
+ /* 301 */ "cmd ::= ALTER TABLE fullname ALTER COLUMNKW columnname TO columnname carglist",
+ /* 302 */ "cmd ::= create_vtab",
+ /* 303 */ "cmd ::= create_vtab LP vtabarglist RP",
+ /* 304 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
+ /* 305 */ "vtabarg ::=",
+ /* 306 */ "vtabargtoken ::= ANY",
+ /* 307 */ "vtabargtoken ::= lp anylist RP",
+ /* 308 */ "lp ::= LP",
+ /* 309 */ "with ::= WITH wqlist",
+ /* 310 */ "with ::= WITH RECURSIVE wqlist",
+ /* 311 */ "wqas ::= AS",
+ /* 312 */ "wqas ::= AS MATERIALIZED",
+ /* 313 */ "wqas ::= AS NOT MATERIALIZED",
+ /* 314 */ "wqitem ::= nm eidlist_opt wqas LP select RP",
+ /* 315 */ "wqlist ::= wqitem",
+ /* 316 */ "wqlist ::= wqlist COMMA wqitem",
+ /* 317 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn",
+ /* 318 */ "windowdefn ::= nm AS LP window RP",
+ /* 319 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt",
+ /* 320 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt",
+ /* 321 */ "window ::= ORDER BY sortlist frame_opt",
+ /* 322 */ "window ::= nm ORDER BY sortlist frame_opt",
/* 323 */ "window ::= nm frame_opt",
/* 324 */ "frame_opt ::=",
/* 325 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt",
@@ -170347,32 +174011,32 @@ static const char *const yyRuleName[] = {
/* 358 */ "table_option_set ::= table_option",
/* 359 */ "columnlist ::= columnlist COMMA columnname carglist",
/* 360 */ "columnlist ::= columnname carglist",
- /* 361 */ "nm ::= ID|INDEXED",
+ /* 361 */ "nm ::= ID|INDEXED|JOIN_KW",
/* 362 */ "nm ::= STRING",
- /* 363 */ "nm ::= JOIN_KW",
- /* 364 */ "typetoken ::= typename",
- /* 365 */ "typename ::= ID|STRING",
- /* 366 */ "signed ::= plus_num",
- /* 367 */ "signed ::= minus_num",
- /* 368 */ "carglist ::= carglist ccons",
- /* 369 */ "carglist ::=",
- /* 370 */ "ccons ::= NULL onconf",
- /* 371 */ "ccons ::= GENERATED ALWAYS AS generated",
- /* 372 */ "ccons ::= AS generated",
- /* 373 */ "conslist_opt ::= COMMA conslist",
- /* 374 */ "conslist ::= conslist tconscomma tcons",
- /* 375 */ "conslist ::= tcons",
- /* 376 */ "tconscomma ::=",
- /* 377 */ "defer_subclause_opt ::= defer_subclause",
- /* 378 */ "resolvetype ::= raisetype",
- /* 379 */ "selectnowith ::= oneselect",
- /* 380 */ "oneselect ::= values",
- /* 381 */ "sclp ::= selcollist COMMA",
- /* 382 */ "as ::= ID|STRING",
- /* 383 */ "indexed_opt ::= indexed_by",
- /* 384 */ "returning ::=",
- /* 385 */ "expr ::= term",
- /* 386 */ "likeop ::= LIKE_KW|MATCH",
+ /* 363 */ "typetoken ::= typename",
+ /* 364 */ "typename ::= ID|STRING",
+ /* 365 */ "signed ::= plus_num",
+ /* 366 */ "signed ::= minus_num",
+ /* 367 */ "carglist ::= carglist ccons",
+ /* 368 */ "carglist ::=",
+ /* 369 */ "ccons ::= NULL onconf",
+ /* 370 */ "ccons ::= GENERATED ALWAYS AS generated",
+ /* 371 */ "ccons ::= AS generated",
+ /* 372 */ "conslist_opt ::= COMMA conslist",
+ /* 373 */ "conslist ::= conslist tconscomma tcons",
+ /* 374 */ "conslist ::= tcons",
+ /* 375 */ "tconscomma ::=",
+ /* 376 */ "defer_subclause_opt ::= defer_subclause",
+ /* 377 */ "resolvetype ::= raisetype",
+ /* 378 */ "selectnowith ::= oneselect",
+ /* 379 */ "oneselect ::= values",
+ /* 380 */ "sclp ::= selcollist COMMA",
+ /* 381 */ "as ::= ID|STRING",
+ /* 382 */ "indexed_opt ::= indexed_by",
+ /* 383 */ "returning ::=",
+ /* 384 */ "expr ::= term",
+ /* 385 */ "likeop ::= LIKE_KW|MATCH",
+ /* 386 */ "case_operand ::= expr",
/* 387 */ "exprlist ::= nexprlist",
/* 388 */ "nmnum ::= plus_num",
/* 389 */ "nmnum ::= nm",
@@ -170395,6 +174059,8 @@ static const char *const yyRuleName[] = {
/* 406 */ "anylist ::= anylist LP anylist RP",
/* 407 */ "anylist ::= anylist ANY",
/* 408 */ "with ::=",
+ /* 409 */ "windowdefn_list ::= windowdefn",
+ /* 410 */ "window ::= frame_opt",
};
#endif /* NDEBUG */
@@ -170520,97 +174186,97 @@ static void yy_destructor(
** inside the C code.
*/
/********* Begin destructor definitions ***************************************/
- case 206: /* select */
- case 241: /* selectnowith */
- case 242: /* oneselect */
- case 254: /* values */
+ case 207: /* select */
+ case 242: /* selectnowith */
+ case 243: /* oneselect */
+ case 255: /* values */
{
-sqlite3SelectDelete(pParse->db, (yypminor->yy136));
-}
- break;
- case 218: /* term */
- case 219: /* expr */
- case 248: /* where_opt */
- case 250: /* having_opt */
- case 269: /* where_opt_ret */
- case 280: /* case_operand */
- case 282: /* case_else */
- case 285: /* vinto */
- case 292: /* when_clause */
- case 297: /* key_opt */
- case 313: /* filter_clause */
+sqlite3SelectDelete(pParse->db, (yypminor->yy555));
+}
+ break;
+ case 219: /* term */
+ case 220: /* expr */
+ case 249: /* where_opt */
+ case 251: /* having_opt */
+ case 270: /* where_opt_ret */
+ case 281: /* case_operand */
+ case 283: /* case_else */
+ case 286: /* vinto */
+ case 293: /* when_clause */
+ case 298: /* key_opt */
+ case 314: /* filter_clause */
{
-sqlite3ExprDelete(pParse->db, (yypminor->yy224));
-}
- break;
- case 223: /* eidlist_opt */
- case 233: /* sortlist */
- case 234: /* eidlist */
- case 246: /* selcollist */
- case 249: /* groupby_opt */
- case 251: /* orderby_opt */
- case 255: /* nexprlist */
- case 256: /* sclp */
- case 263: /* exprlist */
- case 270: /* setlist */
- case 279: /* paren_exprlist */
- case 281: /* case_exprlist */
- case 312: /* part_opt */
+sqlite3ExprDelete(pParse->db, (yypminor->yy454));
+}
+ break;
+ case 224: /* eidlist_opt */
+ case 234: /* sortlist */
+ case 235: /* eidlist */
+ case 247: /* selcollist */
+ case 250: /* groupby_opt */
+ case 252: /* orderby_opt */
+ case 256: /* nexprlist */
+ case 257: /* sclp */
+ case 264: /* exprlist */
+ case 271: /* setlist */
+ case 280: /* paren_exprlist */
+ case 282: /* case_exprlist */
+ case 313: /* part_opt */
{
-sqlite3ExprListDelete(pParse->db, (yypminor->yy586));
+sqlite3ExprListDelete(pParse->db, (yypminor->yy14));
}
break;
- case 240: /* fullname */
- case 247: /* from */
- case 258: /* seltablist */
- case 259: /* stl_prefix */
- case 264: /* xfullname */
+ case 241: /* fullname */
+ case 248: /* from */
+ case 259: /* seltablist */
+ case 260: /* stl_prefix */
+ case 265: /* xfullname */
{
-sqlite3SrcListDelete(pParse->db, (yypminor->yy493));
+sqlite3SrcListDelete(pParse->db, (yypminor->yy203));
}
break;
- case 243: /* wqlist */
+ case 244: /* wqlist */
{
-sqlite3WithDelete(pParse->db, (yypminor->yy19));
+sqlite3WithDelete(pParse->db, (yypminor->yy59));
}
break;
- case 253: /* window_clause */
- case 308: /* windowdefn_list */
+ case 254: /* window_clause */
+ case 309: /* windowdefn_list */
{
-sqlite3WindowListDelete(pParse->db, (yypminor->yy591));
+sqlite3WindowListDelete(pParse->db, (yypminor->yy211));
}
break;
- case 265: /* idlist */
- case 272: /* idlist_opt */
+ case 266: /* idlist */
+ case 273: /* idlist_opt */
{
-sqlite3IdListDelete(pParse->db, (yypminor->yy600));
+sqlite3IdListDelete(pParse->db, (yypminor->yy132));
}
break;
- case 275: /* filter_over */
- case 309: /* windowdefn */
- case 310: /* window */
- case 311: /* frame_opt */
- case 314: /* over_clause */
+ case 276: /* filter_over */
+ case 310: /* windowdefn */
+ case 311: /* window */
+ case 312: /* frame_opt */
+ case 315: /* over_clause */
{
-sqlite3WindowDelete(pParse->db, (yypminor->yy591));
+sqlite3WindowDelete(pParse->db, (yypminor->yy211));
}
break;
- case 288: /* trigger_cmd_list */
- case 293: /* trigger_cmd */
+ case 289: /* trigger_cmd_list */
+ case 294: /* trigger_cmd */
{
-sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy137));
+sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy427));
}
break;
- case 290: /* trigger_event */
+ case 291: /* trigger_event */
{
-sqlite3IdListDelete(pParse->db, (yypminor->yy510).b);
+sqlite3IdListDelete(pParse->db, (yypminor->yy286).b);
}
break;
- case 316: /* frame_bound */
- case 317: /* frame_bound_s */
- case 318: /* frame_bound_e */
+ case 317: /* frame_bound */
+ case 318: /* frame_bound_s */
+ case 319: /* frame_bound_e */
{
-sqlite3ExprDelete(pParse->db, (yypminor->yy537).pExpr);
+sqlite3ExprDelete(pParse->db, (yypminor->yy509).pExpr);
}
break;
/********* End destructor definitions *****************************************/
@@ -170901,415 +174567,417 @@ static void yy_shift(
/* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side
** of that rule */
static const YYCODETYPE yyRuleInfoLhs[] = {
- 191, /* (0) explain ::= EXPLAIN */
- 191, /* (1) explain ::= EXPLAIN QUERY PLAN */
- 190, /* (2) cmdx ::= cmd */
- 192, /* (3) cmd ::= BEGIN transtype trans_opt */
- 193, /* (4) transtype ::= */
- 193, /* (5) transtype ::= DEFERRED */
- 193, /* (6) transtype ::= IMMEDIATE */
- 193, /* (7) transtype ::= EXCLUSIVE */
- 192, /* (8) cmd ::= COMMIT|END trans_opt */
- 192, /* (9) cmd ::= ROLLBACK trans_opt */
- 192, /* (10) cmd ::= SAVEPOINT nm */
- 192, /* (11) cmd ::= RELEASE savepoint_opt nm */
- 192, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
- 197, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
- 199, /* (14) createkw ::= CREATE */
- 201, /* (15) ifnotexists ::= */
- 201, /* (16) ifnotexists ::= IF NOT EXISTS */
- 200, /* (17) temp ::= TEMP */
- 200, /* (18) temp ::= */
- 198, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */
- 198, /* (20) create_table_args ::= AS select */
- 205, /* (21) table_option_set ::= */
- 205, /* (22) table_option_set ::= table_option_set COMMA table_option */
- 207, /* (23) table_option ::= WITHOUT nm */
- 207, /* (24) table_option ::= RANDOM nm */
- 207, /* (25) table_option ::= nm */
- 208, /* (26) columnname ::= nm typetoken */
- 210, /* (27) typetoken ::= */
- 210, /* (28) typetoken ::= typename LP signed RP */
- 210, /* (29) typetoken ::= typename LP signed COMMA signed RP */
- 211, /* (30) typename ::= typename ID|STRING */
- 215, /* (31) scanpt ::= */
- 216, /* (32) scantok ::= */
- 217, /* (33) ccons ::= CONSTRAINT nm */
- 217, /* (34) ccons ::= DEFAULT scantok term */
- 217, /* (35) ccons ::= DEFAULT LP expr RP */
- 217, /* (36) ccons ::= DEFAULT PLUS scantok term */
- 217, /* (37) ccons ::= DEFAULT MINUS scantok term */
- 217, /* (38) ccons ::= DEFAULT scantok ID|INDEXED */
- 217, /* (39) ccons ::= NOT NULL onconf */
- 217, /* (40) ccons ::= PRIMARY KEY sortorder onconf autoinc */
- 217, /* (41) ccons ::= UNIQUE onconf */
- 217, /* (42) ccons ::= CHECK LP expr RP */
- 217, /* (43) ccons ::= REFERENCES nm eidlist_opt refargs */
- 217, /* (44) ccons ::= defer_subclause */
- 217, /* (45) ccons ::= COLLATE ID|STRING */
- 226, /* (46) generated ::= LP expr RP */
- 226, /* (47) generated ::= LP expr RP ID */
- 222, /* (48) autoinc ::= */
- 222, /* (49) autoinc ::= AUTOINCR */
- 224, /* (50) refargs ::= */
- 224, /* (51) refargs ::= refargs refarg */
- 227, /* (52) refarg ::= MATCH nm */
- 227, /* (53) refarg ::= ON INSERT refact */
- 227, /* (54) refarg ::= ON DELETE refact */
- 227, /* (55) refarg ::= ON UPDATE refact */
- 228, /* (56) refact ::= SET NULL */
- 228, /* (57) refact ::= SET DEFAULT */
- 228, /* (58) refact ::= CASCADE */
- 228, /* (59) refact ::= RESTRICT */
- 228, /* (60) refact ::= NO ACTION */
- 225, /* (61) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
- 225, /* (62) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
- 229, /* (63) init_deferred_pred_opt ::= */
- 229, /* (64) init_deferred_pred_opt ::= INITIALLY DEFERRED */
- 229, /* (65) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
- 204, /* (66) conslist_opt ::= */
- 231, /* (67) tconscomma ::= COMMA */
- 232, /* (68) tcons ::= CONSTRAINT nm */
- 232, /* (69) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
- 232, /* (70) tcons ::= UNIQUE LP sortlist RP onconf */
- 232, /* (71) tcons ::= CHECK LP expr RP onconf */
- 232, /* (72) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
- 235, /* (73) defer_subclause_opt ::= */
- 220, /* (74) onconf ::= */
- 220, /* (75) onconf ::= ON CONFLICT resolvetype */
- 236, /* (76) orconf ::= */
- 236, /* (77) orconf ::= OR resolvetype */
- 237, /* (78) resolvetype ::= IGNORE */
- 237, /* (79) resolvetype ::= REPLACE */
- 192, /* (80) cmd ::= DROP TABLE ifexists fullname */
- 239, /* (81) ifexists ::= IF EXISTS */
- 239, /* (82) ifexists ::= */
- 192, /* (83) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
- 192, /* (84) cmd ::= DROP VIEW ifexists fullname */
- 192, /* (85) cmd ::= createkw FUNCTION ifnotexists nm LANGUAGE nm AS STRING */
- 192, /* (86) cmd ::= createkw FUNCTION ifnotexists nm LANGUAGE nm AS BLOB */
- 192, /* (87) cmd ::= DROP FUNCTION ifexists nm */
- 192, /* (88) cmd ::= select */
- 206, /* (89) select ::= WITH wqlist selectnowith */
- 206, /* (90) select ::= WITH RECURSIVE wqlist selectnowith */
- 206, /* (91) select ::= selectnowith */
- 241, /* (92) selectnowith ::= selectnowith multiselect_op oneselect */
- 244, /* (93) multiselect_op ::= UNION */
- 244, /* (94) multiselect_op ::= UNION ALL */
- 244, /* (95) multiselect_op ::= EXCEPT|INTERSECT */
- 242, /* (96) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
- 242, /* (97) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
- 254, /* (98) values ::= VALUES LP nexprlist RP */
- 254, /* (99) values ::= values COMMA LP nexprlist RP */
- 245, /* (100) distinct ::= DISTINCT */
- 245, /* (101) distinct ::= ALL */
- 245, /* (102) distinct ::= */
- 256, /* (103) sclp ::= */
- 246, /* (104) selcollist ::= sclp scanpt expr scanpt as */
- 246, /* (105) selcollist ::= sclp scanpt STAR */
- 246, /* (106) selcollist ::= sclp scanpt nm DOT STAR */
- 257, /* (107) as ::= AS nm */
- 257, /* (108) as ::= */
- 247, /* (109) from ::= */
- 247, /* (110) from ::= FROM seltablist */
- 259, /* (111) stl_prefix ::= seltablist joinop */
- 259, /* (112) stl_prefix ::= */
- 258, /* (113) seltablist ::= stl_prefix nm dbnm as on_using */
- 258, /* (114) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
- 258, /* (115) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
- 258, /* (116) seltablist ::= stl_prefix LP select RP as on_using */
- 258, /* (117) seltablist ::= stl_prefix LP seltablist RP as on_using */
- 202, /* (118) dbnm ::= */
- 202, /* (119) dbnm ::= DOT nm */
- 240, /* (120) fullname ::= nm */
- 240, /* (121) fullname ::= nm DOT nm */
- 264, /* (122) xfullname ::= nm */
- 264, /* (123) xfullname ::= nm DOT nm */
- 264, /* (124) xfullname ::= nm DOT nm AS nm */
- 264, /* (125) xfullname ::= nm AS nm */
- 260, /* (126) joinop ::= COMMA|JOIN */
- 260, /* (127) joinop ::= JOIN_KW JOIN */
- 260, /* (128) joinop ::= JOIN_KW nm JOIN */
- 260, /* (129) joinop ::= JOIN_KW nm nm JOIN */
- 261, /* (130) on_using ::= ON expr */
- 261, /* (131) on_using ::= USING LP idlist RP */
- 261, /* (132) on_using ::= */
- 266, /* (133) indexed_opt ::= */
- 262, /* (134) indexed_by ::= INDEXED BY nm */
- 262, /* (135) indexed_by ::= NOT INDEXED */
- 251, /* (136) orderby_opt ::= */
- 251, /* (137) orderby_opt ::= ORDER BY sortlist */
- 233, /* (138) sortlist ::= sortlist COMMA expr sortorder nulls */
- 233, /* (139) sortlist ::= expr sortorder nulls */
- 221, /* (140) sortorder ::= ASC */
- 221, /* (141) sortorder ::= DESC */
- 221, /* (142) sortorder ::= */
- 267, /* (143) nulls ::= NULLS FIRST */
- 267, /* (144) nulls ::= NULLS LAST */
- 267, /* (145) nulls ::= */
- 249, /* (146) groupby_opt ::= */
- 249, /* (147) groupby_opt ::= GROUP BY nexprlist */
- 250, /* (148) having_opt ::= */
- 250, /* (149) having_opt ::= HAVING expr */
- 252, /* (150) limit_opt ::= */
- 252, /* (151) limit_opt ::= LIMIT expr */
- 252, /* (152) limit_opt ::= LIMIT expr OFFSET expr */
- 252, /* (153) limit_opt ::= LIMIT expr COMMA expr */
- 192, /* (154) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
- 248, /* (155) where_opt ::= */
- 248, /* (156) where_opt ::= WHERE expr */
- 269, /* (157) where_opt_ret ::= */
- 269, /* (158) where_opt_ret ::= WHERE expr */
- 269, /* (159) where_opt_ret ::= RETURNING selcollist */
- 269, /* (160) where_opt_ret ::= WHERE expr RETURNING selcollist */
- 192, /* (161) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
- 270, /* (162) setlist ::= setlist COMMA nm EQ expr */
- 270, /* (163) setlist ::= setlist COMMA LP idlist RP EQ expr */
- 270, /* (164) setlist ::= nm EQ expr */
- 270, /* (165) setlist ::= LP idlist RP EQ expr */
- 192, /* (166) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
- 192, /* (167) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
- 273, /* (168) upsert ::= */
- 273, /* (169) upsert ::= RETURNING selcollist */
- 273, /* (170) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
- 273, /* (171) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
- 273, /* (172) upsert ::= ON CONFLICT DO NOTHING returning */
- 273, /* (173) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
- 274, /* (174) returning ::= RETURNING selcollist */
- 271, /* (175) insert_cmd ::= INSERT orconf */
- 271, /* (176) insert_cmd ::= REPLACE */
- 272, /* (177) idlist_opt ::= */
- 272, /* (178) idlist_opt ::= LP idlist RP */
- 265, /* (179) idlist ::= idlist COMMA nm */
- 265, /* (180) idlist ::= nm */
- 219, /* (181) expr ::= LP expr RP */
- 219, /* (182) expr ::= ID|INDEXED */
- 219, /* (183) expr ::= JOIN_KW */
- 219, /* (184) expr ::= nm DOT nm */
- 219, /* (185) expr ::= nm DOT nm DOT nm */
- 218, /* (186) term ::= NULL|FLOAT|BLOB */
- 218, /* (187) term ::= STRING */
- 218, /* (188) term ::= INTEGER */
- 219, /* (189) expr ::= VARIABLE */
- 219, /* (190) expr ::= expr COLLATE ID|STRING */
- 219, /* (191) expr ::= CAST LP expr AS typetoken RP */
- 219, /* (192) expr ::= ID|INDEXED LP distinct exprlist RP */
- 219, /* (193) expr ::= ID|INDEXED LP STAR RP */
- 219, /* (194) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
- 219, /* (195) expr ::= ID|INDEXED LP STAR RP filter_over */
- 218, /* (196) term ::= CTIME_KW */
- 219, /* (197) expr ::= LP nexprlist COMMA expr RP */
- 219, /* (198) expr ::= expr AND expr */
- 219, /* (199) expr ::= expr OR expr */
- 219, /* (200) expr ::= expr LT|GT|GE|LE expr */
- 219, /* (201) expr ::= expr EQ|NE expr */
- 219, /* (202) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
- 219, /* (203) expr ::= expr PLUS|MINUS expr */
- 219, /* (204) expr ::= expr STAR|SLASH|REM expr */
- 219, /* (205) expr ::= expr CONCAT expr */
- 276, /* (206) likeop ::= NOT LIKE_KW|MATCH */
- 219, /* (207) expr ::= expr likeop expr */
- 219, /* (208) expr ::= expr likeop expr ESCAPE expr */
- 219, /* (209) expr ::= expr ISNULL|NOTNULL */
- 219, /* (210) expr ::= expr NOT NULL */
- 219, /* (211) expr ::= expr IS expr */
- 219, /* (212) expr ::= expr IS NOT expr */
- 219, /* (213) expr ::= expr IS NOT DISTINCT FROM expr */
- 219, /* (214) expr ::= expr IS DISTINCT FROM expr */
- 219, /* (215) expr ::= NOT expr */
- 219, /* (216) expr ::= BITNOT expr */
- 219, /* (217) expr ::= PLUS|MINUS expr */
- 219, /* (218) expr ::= expr PTR expr */
- 277, /* (219) between_op ::= BETWEEN */
- 277, /* (220) between_op ::= NOT BETWEEN */
- 219, /* (221) expr ::= expr between_op expr AND expr */
- 278, /* (222) in_op ::= IN */
- 278, /* (223) in_op ::= NOT IN */
- 219, /* (224) expr ::= expr in_op LP exprlist RP */
- 219, /* (225) expr ::= LP select RP */
- 219, /* (226) expr ::= expr in_op LP select RP */
- 219, /* (227) expr ::= expr in_op nm dbnm paren_exprlist */
- 219, /* (228) expr ::= EXISTS LP select RP */
- 219, /* (229) expr ::= CASE case_operand case_exprlist case_else END */
- 281, /* (230) case_exprlist ::= case_exprlist WHEN expr THEN expr */
- 281, /* (231) case_exprlist ::= WHEN expr THEN expr */
- 282, /* (232) case_else ::= ELSE expr */
- 282, /* (233) case_else ::= */
- 280, /* (234) case_operand ::= expr */
- 280, /* (235) case_operand ::= */
- 263, /* (236) exprlist ::= */
- 255, /* (237) nexprlist ::= nexprlist COMMA expr */
- 255, /* (238) nexprlist ::= expr */
- 279, /* (239) paren_exprlist ::= */
- 279, /* (240) paren_exprlist ::= LP exprlist RP */
- 192, /* (241) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
- 283, /* (242) uniqueflag ::= UNIQUE */
- 283, /* (243) uniqueflag ::= */
- 223, /* (244) eidlist_opt ::= */
- 223, /* (245) eidlist_opt ::= LP eidlist RP */
- 234, /* (246) eidlist ::= eidlist COMMA nm collate sortorder */
- 234, /* (247) eidlist ::= nm collate sortorder */
- 284, /* (248) collate ::= */
- 284, /* (249) collate ::= COLLATE ID|STRING */
- 192, /* (250) cmd ::= DROP INDEX ifexists fullname */
- 192, /* (251) cmd ::= VACUUM vinto */
- 192, /* (252) cmd ::= VACUUM nm vinto */
- 285, /* (253) vinto ::= INTO expr */
- 285, /* (254) vinto ::= */
- 192, /* (255) cmd ::= PRAGMA nm dbnm */
- 192, /* (256) cmd ::= PRAGMA nm dbnm EQ nmnum */
- 192, /* (257) cmd ::= PRAGMA nm dbnm LP nmnum RP */
- 192, /* (258) cmd ::= PRAGMA nm dbnm EQ minus_num */
- 192, /* (259) cmd ::= PRAGMA nm dbnm LP minus_num RP */
- 213, /* (260) plus_num ::= PLUS INTEGER|FLOAT */
- 214, /* (261) minus_num ::= MINUS INTEGER|FLOAT */
- 192, /* (262) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
- 287, /* (263) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
- 289, /* (264) trigger_time ::= BEFORE|AFTER */
- 289, /* (265) trigger_time ::= INSTEAD OF */
- 289, /* (266) trigger_time ::= */
- 290, /* (267) trigger_event ::= DELETE|INSERT */
- 290, /* (268) trigger_event ::= UPDATE */
- 290, /* (269) trigger_event ::= UPDATE OF idlist */
- 292, /* (270) when_clause ::= */
- 292, /* (271) when_clause ::= WHEN expr */
- 288, /* (272) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
- 288, /* (273) trigger_cmd_list ::= trigger_cmd SEMI */
- 294, /* (274) trnm ::= nm DOT nm */
- 295, /* (275) tridxby ::= INDEXED BY nm */
- 295, /* (276) tridxby ::= NOT INDEXED */
- 293, /* (277) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
- 293, /* (278) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
- 293, /* (279) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
- 293, /* (280) trigger_cmd ::= scanpt select scanpt */
- 219, /* (281) expr ::= RAISE LP IGNORE RP */
- 219, /* (282) expr ::= RAISE LP raisetype COMMA nm RP */
- 238, /* (283) raisetype ::= ROLLBACK */
- 238, /* (284) raisetype ::= ABORT */
- 238, /* (285) raisetype ::= FAIL */
- 192, /* (286) cmd ::= DROP TRIGGER ifexists fullname */
- 192, /* (287) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
- 192, /* (288) cmd ::= DETACH database_kw_opt expr */
- 297, /* (289) key_opt ::= */
- 297, /* (290) key_opt ::= KEY expr */
- 192, /* (291) cmd ::= REINDEX */
- 192, /* (292) cmd ::= REINDEX nm dbnm */
- 192, /* (293) cmd ::= ANALYZE */
- 192, /* (294) cmd ::= ANALYZE nm dbnm */
- 192, /* (295) cmd ::= ALTER TABLE fullname RENAME TO nm */
- 192, /* (296) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
- 192, /* (297) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
- 298, /* (298) add_column_fullname ::= fullname */
- 192, /* (299) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
- 192, /* (300) cmd ::= create_vtab */
- 192, /* (301) cmd ::= create_vtab LP vtabarglist RP */
- 300, /* (302) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
- 302, /* (303) vtabarg ::= */
- 303, /* (304) vtabargtoken ::= ANY */
- 303, /* (305) vtabargtoken ::= lp anylist RP */
- 304, /* (306) lp ::= LP */
- 268, /* (307) with ::= WITH wqlist */
- 268, /* (308) with ::= WITH RECURSIVE wqlist */
- 307, /* (309) wqas ::= AS */
- 307, /* (310) wqas ::= AS MATERIALIZED */
- 307, /* (311) wqas ::= AS NOT MATERIALIZED */
- 306, /* (312) wqitem ::= nm eidlist_opt wqas LP select RP */
- 243, /* (313) wqlist ::= wqitem */
- 243, /* (314) wqlist ::= wqlist COMMA wqitem */
- 308, /* (315) windowdefn_list ::= windowdefn */
- 308, /* (316) windowdefn_list ::= windowdefn_list COMMA windowdefn */
- 309, /* (317) windowdefn ::= nm AS LP window RP */
- 310, /* (318) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
- 310, /* (319) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
- 310, /* (320) window ::= ORDER BY sortlist frame_opt */
- 310, /* (321) window ::= nm ORDER BY sortlist frame_opt */
- 310, /* (322) window ::= frame_opt */
- 310, /* (323) window ::= nm frame_opt */
- 311, /* (324) frame_opt ::= */
- 311, /* (325) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
- 311, /* (326) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
- 315, /* (327) range_or_rows ::= RANGE|ROWS|GROUPS */
- 317, /* (328) frame_bound_s ::= frame_bound */
- 317, /* (329) frame_bound_s ::= UNBOUNDED PRECEDING */
- 318, /* (330) frame_bound_e ::= frame_bound */
- 318, /* (331) frame_bound_e ::= UNBOUNDED FOLLOWING */
- 316, /* (332) frame_bound ::= expr PRECEDING|FOLLOWING */
- 316, /* (333) frame_bound ::= CURRENT ROW */
- 319, /* (334) frame_exclude_opt ::= */
- 319, /* (335) frame_exclude_opt ::= EXCLUDE frame_exclude */
- 320, /* (336) frame_exclude ::= NO OTHERS */
- 320, /* (337) frame_exclude ::= CURRENT ROW */
- 320, /* (338) frame_exclude ::= GROUP|TIES */
- 253, /* (339) window_clause ::= WINDOW windowdefn_list */
- 275, /* (340) filter_over ::= filter_clause over_clause */
- 275, /* (341) filter_over ::= over_clause */
- 275, /* (342) filter_over ::= filter_clause */
- 314, /* (343) over_clause ::= OVER LP window RP */
- 314, /* (344) over_clause ::= OVER nm */
- 313, /* (345) filter_clause ::= FILTER LP WHERE expr RP */
- 187, /* (346) input ::= cmdlist */
- 188, /* (347) cmdlist ::= cmdlist ecmd */
- 188, /* (348) cmdlist ::= ecmd */
- 189, /* (349) ecmd ::= SEMI */
- 189, /* (350) ecmd ::= cmdx SEMI */
- 189, /* (351) ecmd ::= explain cmdx SEMI */
- 194, /* (352) trans_opt ::= */
- 194, /* (353) trans_opt ::= TRANSACTION */
- 194, /* (354) trans_opt ::= TRANSACTION nm */
- 196, /* (355) savepoint_opt ::= SAVEPOINT */
- 196, /* (356) savepoint_opt ::= */
- 192, /* (357) cmd ::= create_table create_table_args */
- 205, /* (358) table_option_set ::= table_option */
- 203, /* (359) columnlist ::= columnlist COMMA columnname carglist */
- 203, /* (360) columnlist ::= columnname carglist */
- 195, /* (361) nm ::= ID|INDEXED */
- 195, /* (362) nm ::= STRING */
- 195, /* (363) nm ::= JOIN_KW */
- 210, /* (364) typetoken ::= typename */
- 211, /* (365) typename ::= ID|STRING */
- 212, /* (366) signed ::= plus_num */
- 212, /* (367) signed ::= minus_num */
- 209, /* (368) carglist ::= carglist ccons */
- 209, /* (369) carglist ::= */
- 217, /* (370) ccons ::= NULL onconf */
- 217, /* (371) ccons ::= GENERATED ALWAYS AS generated */
- 217, /* (372) ccons ::= AS generated */
- 204, /* (373) conslist_opt ::= COMMA conslist */
- 230, /* (374) conslist ::= conslist tconscomma tcons */
- 230, /* (375) conslist ::= tcons */
- 231, /* (376) tconscomma ::= */
- 235, /* (377) defer_subclause_opt ::= defer_subclause */
- 237, /* (378) resolvetype ::= raisetype */
- 241, /* (379) selectnowith ::= oneselect */
- 242, /* (380) oneselect ::= values */
- 256, /* (381) sclp ::= selcollist COMMA */
- 257, /* (382) as ::= ID|STRING */
- 266, /* (383) indexed_opt ::= indexed_by */
- 274, /* (384) returning ::= */
- 219, /* (385) expr ::= term */
- 276, /* (386) likeop ::= LIKE_KW|MATCH */
- 263, /* (387) exprlist ::= nexprlist */
- 286, /* (388) nmnum ::= plus_num */
- 286, /* (389) nmnum ::= nm */
- 286, /* (390) nmnum ::= ON */
- 286, /* (391) nmnum ::= DELETE */
- 286, /* (392) nmnum ::= DEFAULT */
- 213, /* (393) plus_num ::= INTEGER|FLOAT */
- 291, /* (394) foreach_clause ::= */
- 291, /* (395) foreach_clause ::= FOR EACH ROW */
- 294, /* (396) trnm ::= nm */
- 295, /* (397) tridxby ::= */
- 296, /* (398) database_kw_opt ::= DATABASE */
- 296, /* (399) database_kw_opt ::= */
- 299, /* (400) kwcolumn_opt ::= */
- 299, /* (401) kwcolumn_opt ::= COLUMNKW */
- 301, /* (402) vtabarglist ::= vtabarg */
- 301, /* (403) vtabarglist ::= vtabarglist COMMA vtabarg */
- 302, /* (404) vtabarg ::= vtabarg vtabargtoken */
- 305, /* (405) anylist ::= */
- 305, /* (406) anylist ::= anylist LP anylist RP */
- 305, /* (407) anylist ::= anylist ANY */
- 268, /* (408) with ::= */
+ 192, /* (0) explain ::= EXPLAIN */
+ 192, /* (1) explain ::= EXPLAIN QUERY PLAN */
+ 191, /* (2) cmdx ::= cmd */
+ 193, /* (3) cmd ::= BEGIN transtype trans_opt */
+ 194, /* (4) transtype ::= */
+ 194, /* (5) transtype ::= DEFERRED */
+ 194, /* (6) transtype ::= IMMEDIATE */
+ 194, /* (7) transtype ::= EXCLUSIVE */
+ 194, /* (8) transtype ::= READONLY */
+ 193, /* (9) cmd ::= COMMIT|END trans_opt */
+ 193, /* (10) cmd ::= ROLLBACK trans_opt */
+ 193, /* (11) cmd ::= SAVEPOINT nm */
+ 193, /* (12) cmd ::= RELEASE savepoint_opt nm */
+ 193, /* (13) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
+ 198, /* (14) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
+ 200, /* (15) createkw ::= CREATE */
+ 202, /* (16) ifnotexists ::= */
+ 202, /* (17) ifnotexists ::= IF NOT EXISTS */
+ 201, /* (18) temp ::= TEMP */
+ 201, /* (19) temp ::= */
+ 199, /* (20) create_table_args ::= LP columnlist conslist_opt RP table_option_set */
+ 199, /* (21) create_table_args ::= AS select */
+ 206, /* (22) table_option_set ::= */
+ 206, /* (23) table_option_set ::= table_option_set COMMA table_option */
+ 208, /* (24) table_option ::= WITHOUT nm */
+ 208, /* (25) table_option ::= RANDOM nm */
+ 208, /* (26) table_option ::= nm */
+ 209, /* (27) columnname ::= nm typetoken */
+ 211, /* (28) typetoken ::= */
+ 211, /* (29) typetoken ::= typename LP signed RP */
+ 211, /* (30) typetoken ::= typename LP signed COMMA signed RP */
+ 212, /* (31) typename ::= typename ID|STRING */
+ 216, /* (32) scanpt ::= */
+ 217, /* (33) scantok ::= */
+ 218, /* (34) ccons ::= CONSTRAINT nm */
+ 218, /* (35) ccons ::= DEFAULT scantok term */
+ 218, /* (36) ccons ::= DEFAULT LP expr RP */
+ 218, /* (37) ccons ::= DEFAULT PLUS scantok term */
+ 218, /* (38) ccons ::= DEFAULT MINUS scantok term */
+ 218, /* (39) ccons ::= DEFAULT scantok ID|INDEXED */
+ 218, /* (40) ccons ::= NOT NULL onconf */
+ 218, /* (41) ccons ::= PRIMARY KEY sortorder onconf autoinc */
+ 218, /* (42) ccons ::= UNIQUE onconf */
+ 218, /* (43) ccons ::= CHECK LP expr RP */
+ 218, /* (44) ccons ::= REFERENCES nm eidlist_opt refargs */
+ 218, /* (45) ccons ::= defer_subclause */
+ 218, /* (46) ccons ::= COLLATE ID|STRING */
+ 227, /* (47) generated ::= LP expr RP */
+ 227, /* (48) generated ::= LP expr RP ID */
+ 223, /* (49) autoinc ::= */
+ 223, /* (50) autoinc ::= AUTOINCR */
+ 225, /* (51) refargs ::= */
+ 225, /* (52) refargs ::= refargs refarg */
+ 228, /* (53) refarg ::= MATCH nm */
+ 228, /* (54) refarg ::= ON INSERT refact */
+ 228, /* (55) refarg ::= ON DELETE refact */
+ 228, /* (56) refarg ::= ON UPDATE refact */
+ 229, /* (57) refact ::= SET NULL */
+ 229, /* (58) refact ::= SET DEFAULT */
+ 229, /* (59) refact ::= CASCADE */
+ 229, /* (60) refact ::= RESTRICT */
+ 229, /* (61) refact ::= NO ACTION */
+ 226, /* (62) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
+ 226, /* (63) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
+ 230, /* (64) init_deferred_pred_opt ::= */
+ 230, /* (65) init_deferred_pred_opt ::= INITIALLY DEFERRED */
+ 230, /* (66) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
+ 205, /* (67) conslist_opt ::= */
+ 232, /* (68) tconscomma ::= COMMA */
+ 233, /* (69) tcons ::= CONSTRAINT nm */
+ 233, /* (70) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
+ 233, /* (71) tcons ::= UNIQUE LP sortlist RP onconf */
+ 233, /* (72) tcons ::= CHECK LP expr RP onconf */
+ 233, /* (73) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
+ 236, /* (74) defer_subclause_opt ::= */
+ 221, /* (75) onconf ::= */
+ 221, /* (76) onconf ::= ON CONFLICT resolvetype */
+ 237, /* (77) orconf ::= */
+ 237, /* (78) orconf ::= OR resolvetype */
+ 238, /* (79) resolvetype ::= IGNORE */
+ 238, /* (80) resolvetype ::= REPLACE */
+ 193, /* (81) cmd ::= DROP TABLE ifexists fullname */
+ 240, /* (82) ifexists ::= IF EXISTS */
+ 240, /* (83) ifexists ::= */
+ 193, /* (84) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
+ 193, /* (85) cmd ::= DROP VIEW ifexists fullname */
+ 193, /* (86) cmd ::= createkw FUNCTION ifnotexists nm LANGUAGE nm AS STRING */
+ 193, /* (87) cmd ::= createkw FUNCTION ifnotexists nm LANGUAGE nm AS BLOB */
+ 193, /* (88) cmd ::= DROP FUNCTION ifexists nm */
+ 193, /* (89) cmd ::= select */
+ 207, /* (90) select ::= WITH wqlist selectnowith */
+ 207, /* (91) select ::= WITH RECURSIVE wqlist selectnowith */
+ 207, /* (92) select ::= selectnowith */
+ 242, /* (93) selectnowith ::= selectnowith multiselect_op oneselect */
+ 245, /* (94) multiselect_op ::= UNION */
+ 245, /* (95) multiselect_op ::= UNION ALL */
+ 245, /* (96) multiselect_op ::= EXCEPT|INTERSECT */
+ 243, /* (97) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
+ 243, /* (98) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
+ 255, /* (99) values ::= VALUES LP nexprlist RP */
+ 255, /* (100) values ::= values COMMA LP nexprlist RP */
+ 246, /* (101) distinct ::= DISTINCT */
+ 246, /* (102) distinct ::= ALL */
+ 246, /* (103) distinct ::= */
+ 257, /* (104) sclp ::= */
+ 247, /* (105) selcollist ::= sclp scanpt expr scanpt as */
+ 247, /* (106) selcollist ::= sclp scanpt STAR */
+ 247, /* (107) selcollist ::= sclp scanpt nm DOT STAR */
+ 258, /* (108) as ::= AS nm */
+ 258, /* (109) as ::= */
+ 248, /* (110) from ::= */
+ 248, /* (111) from ::= FROM seltablist */
+ 260, /* (112) stl_prefix ::= seltablist joinop */
+ 260, /* (113) stl_prefix ::= */
+ 259, /* (114) seltablist ::= stl_prefix nm dbnm as on_using */
+ 259, /* (115) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
+ 259, /* (116) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
+ 259, /* (117) seltablist ::= stl_prefix LP select RP as on_using */
+ 259, /* (118) seltablist ::= stl_prefix LP seltablist RP as on_using */
+ 203, /* (119) dbnm ::= */
+ 203, /* (120) dbnm ::= DOT nm */
+ 241, /* (121) fullname ::= nm */
+ 241, /* (122) fullname ::= nm DOT nm */
+ 265, /* (123) xfullname ::= nm */
+ 265, /* (124) xfullname ::= nm DOT nm */
+ 265, /* (125) xfullname ::= nm DOT nm AS nm */
+ 265, /* (126) xfullname ::= nm AS nm */
+ 261, /* (127) joinop ::= COMMA|JOIN */
+ 261, /* (128) joinop ::= JOIN_KW JOIN */
+ 261, /* (129) joinop ::= JOIN_KW nm JOIN */
+ 261, /* (130) joinop ::= JOIN_KW nm nm JOIN */
+ 262, /* (131) on_using ::= ON expr */
+ 262, /* (132) on_using ::= USING LP idlist RP */
+ 262, /* (133) on_using ::= */
+ 267, /* (134) indexed_opt ::= */
+ 263, /* (135) indexed_by ::= INDEXED BY nm */
+ 263, /* (136) indexed_by ::= NOT INDEXED */
+ 252, /* (137) orderby_opt ::= */
+ 252, /* (138) orderby_opt ::= ORDER BY sortlist */
+ 234, /* (139) sortlist ::= sortlist COMMA expr sortorder nulls */
+ 234, /* (140) sortlist ::= expr sortorder nulls */
+ 222, /* (141) sortorder ::= ASC */
+ 222, /* (142) sortorder ::= DESC */
+ 222, /* (143) sortorder ::= */
+ 268, /* (144) nulls ::= NULLS FIRST */
+ 268, /* (145) nulls ::= NULLS LAST */
+ 268, /* (146) nulls ::= */
+ 250, /* (147) groupby_opt ::= */
+ 250, /* (148) groupby_opt ::= GROUP BY nexprlist */
+ 251, /* (149) having_opt ::= */
+ 251, /* (150) having_opt ::= HAVING expr */
+ 253, /* (151) limit_opt ::= */
+ 253, /* (152) limit_opt ::= LIMIT expr */
+ 253, /* (153) limit_opt ::= LIMIT expr OFFSET expr */
+ 253, /* (154) limit_opt ::= LIMIT expr COMMA expr */
+ 193, /* (155) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
+ 249, /* (156) where_opt ::= */
+ 249, /* (157) where_opt ::= WHERE expr */
+ 270, /* (158) where_opt_ret ::= */
+ 270, /* (159) where_opt_ret ::= WHERE expr */
+ 270, /* (160) where_opt_ret ::= RETURNING selcollist */
+ 270, /* (161) where_opt_ret ::= WHERE expr RETURNING selcollist */
+ 193, /* (162) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
+ 271, /* (163) setlist ::= setlist COMMA nm EQ expr */
+ 271, /* (164) setlist ::= setlist COMMA LP idlist RP EQ expr */
+ 271, /* (165) setlist ::= nm EQ expr */
+ 271, /* (166) setlist ::= LP idlist RP EQ expr */
+ 193, /* (167) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
+ 193, /* (168) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
+ 274, /* (169) upsert ::= */
+ 274, /* (170) upsert ::= RETURNING selcollist */
+ 274, /* (171) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
+ 274, /* (172) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
+ 274, /* (173) upsert ::= ON CONFLICT DO NOTHING returning */
+ 274, /* (174) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
+ 275, /* (175) returning ::= RETURNING selcollist */
+ 272, /* (176) insert_cmd ::= INSERT orconf */
+ 272, /* (177) insert_cmd ::= REPLACE */
+ 273, /* (178) idlist_opt ::= */
+ 273, /* (179) idlist_opt ::= LP idlist RP */
+ 266, /* (180) idlist ::= idlist COMMA nm */
+ 266, /* (181) idlist ::= nm */
+ 220, /* (182) expr ::= LP expr RP */
+ 220, /* (183) expr ::= ID|INDEXED|JOIN_KW */
+ 220, /* (184) expr ::= nm DOT nm */
+ 220, /* (185) expr ::= nm DOT nm DOT nm */
+ 219, /* (186) term ::= NULL|FLOAT|BLOB */
+ 219, /* (187) term ::= STRING */
+ 219, /* (188) term ::= INTEGER */
+ 220, /* (189) expr ::= VARIABLE */
+ 220, /* (190) expr ::= expr COLLATE ID|STRING */
+ 220, /* (191) expr ::= CAST LP expr AS typetoken RP */
+ 220, /* (192) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */
+ 220, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */
+ 220, /* (194) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */
+ 220, /* (195) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */
+ 220, /* (196) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */
+ 220, /* (197) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */
+ 219, /* (198) term ::= CTIME_KW */
+ 220, /* (199) expr ::= LP nexprlist COMMA expr RP */
+ 220, /* (200) expr ::= expr AND expr */
+ 220, /* (201) expr ::= expr OR expr */
+ 220, /* (202) expr ::= expr LT|GT|GE|LE expr */
+ 220, /* (203) expr ::= expr EQ|NE expr */
+ 220, /* (204) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
+ 220, /* (205) expr ::= expr PLUS|MINUS expr */
+ 220, /* (206) expr ::= expr STAR|SLASH|REM expr */
+ 220, /* (207) expr ::= expr CONCAT expr */
+ 277, /* (208) likeop ::= NOT LIKE_KW|MATCH */
+ 220, /* (209) expr ::= expr likeop expr */
+ 220, /* (210) expr ::= expr likeop expr ESCAPE expr */
+ 220, /* (211) expr ::= expr ISNULL|NOTNULL */
+ 220, /* (212) expr ::= expr NOT NULL */
+ 220, /* (213) expr ::= expr IS expr */
+ 220, /* (214) expr ::= expr IS NOT expr */
+ 220, /* (215) expr ::= expr IS NOT DISTINCT FROM expr */
+ 220, /* (216) expr ::= expr IS DISTINCT FROM expr */
+ 220, /* (217) expr ::= NOT expr */
+ 220, /* (218) expr ::= BITNOT expr */
+ 220, /* (219) expr ::= PLUS|MINUS expr */
+ 220, /* (220) expr ::= expr PTR expr */
+ 278, /* (221) between_op ::= BETWEEN */
+ 278, /* (222) between_op ::= NOT BETWEEN */
+ 220, /* (223) expr ::= expr between_op expr AND expr */
+ 279, /* (224) in_op ::= IN */
+ 279, /* (225) in_op ::= NOT IN */
+ 220, /* (226) expr ::= expr in_op LP exprlist RP */
+ 220, /* (227) expr ::= LP select RP */
+ 220, /* (228) expr ::= expr in_op LP select RP */
+ 220, /* (229) expr ::= expr in_op nm dbnm paren_exprlist */
+ 220, /* (230) expr ::= EXISTS LP select RP */
+ 220, /* (231) expr ::= CASE case_operand case_exprlist case_else END */
+ 282, /* (232) case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ 282, /* (233) case_exprlist ::= WHEN expr THEN expr */
+ 283, /* (234) case_else ::= ELSE expr */
+ 283, /* (235) case_else ::= */
+ 281, /* (236) case_operand ::= */
+ 264, /* (237) exprlist ::= */
+ 256, /* (238) nexprlist ::= nexprlist COMMA expr */
+ 256, /* (239) nexprlist ::= expr */
+ 280, /* (240) paren_exprlist ::= */
+ 280, /* (241) paren_exprlist ::= LP exprlist RP */
+ 193, /* (242) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+ 284, /* (243) uniqueflag ::= UNIQUE */
+ 284, /* (244) uniqueflag ::= */
+ 224, /* (245) eidlist_opt ::= */
+ 224, /* (246) eidlist_opt ::= LP eidlist RP */
+ 235, /* (247) eidlist ::= eidlist COMMA nm collate sortorder */
+ 235, /* (248) eidlist ::= nm collate sortorder */
+ 285, /* (249) collate ::= */
+ 285, /* (250) collate ::= COLLATE ID|STRING */
+ 193, /* (251) cmd ::= DROP INDEX ifexists fullname */
+ 193, /* (252) cmd ::= VACUUM vinto */
+ 193, /* (253) cmd ::= VACUUM nm vinto */
+ 286, /* (254) vinto ::= INTO expr */
+ 286, /* (255) vinto ::= */
+ 193, /* (256) cmd ::= PRAGMA nm dbnm */
+ 193, /* (257) cmd ::= PRAGMA nm dbnm EQ nmnum */
+ 193, /* (258) cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ 193, /* (259) cmd ::= PRAGMA nm dbnm EQ minus_num */
+ 193, /* (260) cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ 214, /* (261) plus_num ::= PLUS INTEGER|FLOAT */
+ 215, /* (262) minus_num ::= MINUS INTEGER|FLOAT */
+ 193, /* (263) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ 288, /* (264) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ 290, /* (265) trigger_time ::= BEFORE|AFTER */
+ 290, /* (266) trigger_time ::= INSTEAD OF */
+ 290, /* (267) trigger_time ::= */
+ 291, /* (268) trigger_event ::= DELETE|INSERT */
+ 291, /* (269) trigger_event ::= UPDATE */
+ 291, /* (270) trigger_event ::= UPDATE OF idlist */
+ 293, /* (271) when_clause ::= */
+ 293, /* (272) when_clause ::= WHEN expr */
+ 289, /* (273) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ 289, /* (274) trigger_cmd_list ::= trigger_cmd SEMI */
+ 295, /* (275) trnm ::= nm DOT nm */
+ 296, /* (276) tridxby ::= INDEXED BY nm */
+ 296, /* (277) tridxby ::= NOT INDEXED */
+ 294, /* (278) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
+ 294, /* (279) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
+ 294, /* (280) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
+ 294, /* (281) trigger_cmd ::= scanpt select scanpt */
+ 220, /* (282) expr ::= RAISE LP IGNORE RP */
+ 220, /* (283) expr ::= RAISE LP raisetype COMMA nm RP */
+ 239, /* (284) raisetype ::= ROLLBACK */
+ 239, /* (285) raisetype ::= ABORT */
+ 239, /* (286) raisetype ::= FAIL */
+ 193, /* (287) cmd ::= DROP TRIGGER ifexists fullname */
+ 193, /* (288) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ 193, /* (289) cmd ::= DETACH database_kw_opt expr */
+ 298, /* (290) key_opt ::= */
+ 298, /* (291) key_opt ::= KEY expr */
+ 193, /* (292) cmd ::= REINDEX */
+ 193, /* (293) cmd ::= REINDEX nm dbnm */
+ 193, /* (294) cmd ::= ANALYZE */
+ 193, /* (295) cmd ::= ANALYZE nm dbnm */
+ 193, /* (296) cmd ::= ALTER TABLE fullname RENAME TO nm */
+ 193, /* (297) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+ 193, /* (298) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
+ 299, /* (299) add_column_fullname ::= fullname */
+ 193, /* (300) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
+ 193, /* (301) cmd ::= ALTER TABLE fullname ALTER COLUMNKW columnname TO columnname carglist */
+ 193, /* (302) cmd ::= create_vtab */
+ 193, /* (303) cmd ::= create_vtab LP vtabarglist RP */
+ 301, /* (304) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+ 303, /* (305) vtabarg ::= */
+ 304, /* (306) vtabargtoken ::= ANY */
+ 304, /* (307) vtabargtoken ::= lp anylist RP */
+ 305, /* (308) lp ::= LP */
+ 269, /* (309) with ::= WITH wqlist */
+ 269, /* (310) with ::= WITH RECURSIVE wqlist */
+ 308, /* (311) wqas ::= AS */
+ 308, /* (312) wqas ::= AS MATERIALIZED */
+ 308, /* (313) wqas ::= AS NOT MATERIALIZED */
+ 307, /* (314) wqitem ::= nm eidlist_opt wqas LP select RP */
+ 244, /* (315) wqlist ::= wqitem */
+ 244, /* (316) wqlist ::= wqlist COMMA wqitem */
+ 309, /* (317) windowdefn_list ::= windowdefn_list COMMA windowdefn */
+ 310, /* (318) windowdefn ::= nm AS LP window RP */
+ 311, /* (319) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+ 311, /* (320) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+ 311, /* (321) window ::= ORDER BY sortlist frame_opt */
+ 311, /* (322) window ::= nm ORDER BY sortlist frame_opt */
+ 311, /* (323) window ::= nm frame_opt */
+ 312, /* (324) frame_opt ::= */
+ 312, /* (325) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
+ 312, /* (326) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
+ 316, /* (327) range_or_rows ::= RANGE|ROWS|GROUPS */
+ 318, /* (328) frame_bound_s ::= frame_bound */
+ 318, /* (329) frame_bound_s ::= UNBOUNDED PRECEDING */
+ 319, /* (330) frame_bound_e ::= frame_bound */
+ 319, /* (331) frame_bound_e ::= UNBOUNDED FOLLOWING */
+ 317, /* (332) frame_bound ::= expr PRECEDING|FOLLOWING */
+ 317, /* (333) frame_bound ::= CURRENT ROW */
+ 320, /* (334) frame_exclude_opt ::= */
+ 320, /* (335) frame_exclude_opt ::= EXCLUDE frame_exclude */
+ 321, /* (336) frame_exclude ::= NO OTHERS */
+ 321, /* (337) frame_exclude ::= CURRENT ROW */
+ 321, /* (338) frame_exclude ::= GROUP|TIES */
+ 254, /* (339) window_clause ::= WINDOW windowdefn_list */
+ 276, /* (340) filter_over ::= filter_clause over_clause */
+ 276, /* (341) filter_over ::= over_clause */
+ 276, /* (342) filter_over ::= filter_clause */
+ 315, /* (343) over_clause ::= OVER LP window RP */
+ 315, /* (344) over_clause ::= OVER nm */
+ 314, /* (345) filter_clause ::= FILTER LP WHERE expr RP */
+ 188, /* (346) input ::= cmdlist */
+ 189, /* (347) cmdlist ::= cmdlist ecmd */
+ 189, /* (348) cmdlist ::= ecmd */
+ 190, /* (349) ecmd ::= SEMI */
+ 190, /* (350) ecmd ::= cmdx SEMI */
+ 190, /* (351) ecmd ::= explain cmdx SEMI */
+ 195, /* (352) trans_opt ::= */
+ 195, /* (353) trans_opt ::= TRANSACTION */
+ 195, /* (354) trans_opt ::= TRANSACTION nm */
+ 197, /* (355) savepoint_opt ::= SAVEPOINT */
+ 197, /* (356) savepoint_opt ::= */
+ 193, /* (357) cmd ::= create_table create_table_args */
+ 206, /* (358) table_option_set ::= table_option */
+ 204, /* (359) columnlist ::= columnlist COMMA columnname carglist */
+ 204, /* (360) columnlist ::= columnname carglist */
+ 196, /* (361) nm ::= ID|INDEXED|JOIN_KW */
+ 196, /* (362) nm ::= STRING */
+ 211, /* (363) typetoken ::= typename */
+ 212, /* (364) typename ::= ID|STRING */
+ 213, /* (365) signed ::= plus_num */
+ 213, /* (366) signed ::= minus_num */
+ 210, /* (367) carglist ::= carglist ccons */
+ 210, /* (368) carglist ::= */
+ 218, /* (369) ccons ::= NULL onconf */
+ 218, /* (370) ccons ::= GENERATED ALWAYS AS generated */
+ 218, /* (371) ccons ::= AS generated */
+ 205, /* (372) conslist_opt ::= COMMA conslist */
+ 231, /* (373) conslist ::= conslist tconscomma tcons */
+ 231, /* (374) conslist ::= tcons */
+ 232, /* (375) tconscomma ::= */
+ 236, /* (376) defer_subclause_opt ::= defer_subclause */
+ 238, /* (377) resolvetype ::= raisetype */
+ 242, /* (378) selectnowith ::= oneselect */
+ 243, /* (379) oneselect ::= values */
+ 257, /* (380) sclp ::= selcollist COMMA */
+ 258, /* (381) as ::= ID|STRING */
+ 267, /* (382) indexed_opt ::= indexed_by */
+ 275, /* (383) returning ::= */
+ 220, /* (384) expr ::= term */
+ 277, /* (385) likeop ::= LIKE_KW|MATCH */
+ 281, /* (386) case_operand ::= expr */
+ 264, /* (387) exprlist ::= nexprlist */
+ 287, /* (388) nmnum ::= plus_num */
+ 287, /* (389) nmnum ::= nm */
+ 287, /* (390) nmnum ::= ON */
+ 287, /* (391) nmnum ::= DELETE */
+ 287, /* (392) nmnum ::= DEFAULT */
+ 214, /* (393) plus_num ::= INTEGER|FLOAT */
+ 292, /* (394) foreach_clause ::= */
+ 292, /* (395) foreach_clause ::= FOR EACH ROW */
+ 295, /* (396) trnm ::= nm */
+ 296, /* (397) tridxby ::= */
+ 297, /* (398) database_kw_opt ::= DATABASE */
+ 297, /* (399) database_kw_opt ::= */
+ 300, /* (400) kwcolumn_opt ::= */
+ 300, /* (401) kwcolumn_opt ::= COLUMNKW */
+ 302, /* (402) vtabarglist ::= vtabarg */
+ 302, /* (403) vtabarglist ::= vtabarglist COMMA vtabarg */
+ 303, /* (404) vtabarg ::= vtabarg vtabargtoken */
+ 306, /* (405) anylist ::= */
+ 306, /* (406) anylist ::= anylist LP anylist RP */
+ 306, /* (407) anylist ::= anylist ANY */
+ 269, /* (408) with ::= */
+ 309, /* (409) windowdefn_list ::= windowdefn */
+ 311, /* (410) window ::= frame_opt */
};
/* For rule J, yyRuleInfoNRhs[J] contains the negative of the number
@@ -171323,182 +174991,182 @@ static const signed char yyRuleInfoNRhs[] = {
-1, /* (5) transtype ::= DEFERRED */
-1, /* (6) transtype ::= IMMEDIATE */
-1, /* (7) transtype ::= EXCLUSIVE */
- -2, /* (8) cmd ::= COMMIT|END trans_opt */
- -2, /* (9) cmd ::= ROLLBACK trans_opt */
- -2, /* (10) cmd ::= SAVEPOINT nm */
- -3, /* (11) cmd ::= RELEASE savepoint_opt nm */
- -5, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
- -6, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
- -1, /* (14) createkw ::= CREATE */
- 0, /* (15) ifnotexists ::= */
- -3, /* (16) ifnotexists ::= IF NOT EXISTS */
- -1, /* (17) temp ::= TEMP */
- 0, /* (18) temp ::= */
- -5, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */
- -2, /* (20) create_table_args ::= AS select */
- 0, /* (21) table_option_set ::= */
- -3, /* (22) table_option_set ::= table_option_set COMMA table_option */
- -2, /* (23) table_option ::= WITHOUT nm */
- -2, /* (24) table_option ::= RANDOM nm */
- -1, /* (25) table_option ::= nm */
- -2, /* (26) columnname ::= nm typetoken */
- 0, /* (27) typetoken ::= */
- -4, /* (28) typetoken ::= typename LP signed RP */
- -6, /* (29) typetoken ::= typename LP signed COMMA signed RP */
- -2, /* (30) typename ::= typename ID|STRING */
- 0, /* (31) scanpt ::= */
- 0, /* (32) scantok ::= */
- -2, /* (33) ccons ::= CONSTRAINT nm */
- -3, /* (34) ccons ::= DEFAULT scantok term */
- -4, /* (35) ccons ::= DEFAULT LP expr RP */
- -4, /* (36) ccons ::= DEFAULT PLUS scantok term */
- -4, /* (37) ccons ::= DEFAULT MINUS scantok term */
- -3, /* (38) ccons ::= DEFAULT scantok ID|INDEXED */
- -3, /* (39) ccons ::= NOT NULL onconf */
- -5, /* (40) ccons ::= PRIMARY KEY sortorder onconf autoinc */
- -2, /* (41) ccons ::= UNIQUE onconf */
- -4, /* (42) ccons ::= CHECK LP expr RP */
- -4, /* (43) ccons ::= REFERENCES nm eidlist_opt refargs */
- -1, /* (44) ccons ::= defer_subclause */
- -2, /* (45) ccons ::= COLLATE ID|STRING */
- -3, /* (46) generated ::= LP expr RP */
- -4, /* (47) generated ::= LP expr RP ID */
- 0, /* (48) autoinc ::= */
- -1, /* (49) autoinc ::= AUTOINCR */
- 0, /* (50) refargs ::= */
- -2, /* (51) refargs ::= refargs refarg */
- -2, /* (52) refarg ::= MATCH nm */
- -3, /* (53) refarg ::= ON INSERT refact */
- -3, /* (54) refarg ::= ON DELETE refact */
- -3, /* (55) refarg ::= ON UPDATE refact */
- -2, /* (56) refact ::= SET NULL */
- -2, /* (57) refact ::= SET DEFAULT */
- -1, /* (58) refact ::= CASCADE */
- -1, /* (59) refact ::= RESTRICT */
- -2, /* (60) refact ::= NO ACTION */
- -3, /* (61) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
- -2, /* (62) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
- 0, /* (63) init_deferred_pred_opt ::= */
- -2, /* (64) init_deferred_pred_opt ::= INITIALLY DEFERRED */
- -2, /* (65) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
- 0, /* (66) conslist_opt ::= */
- -1, /* (67) tconscomma ::= COMMA */
- -2, /* (68) tcons ::= CONSTRAINT nm */
- -7, /* (69) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
- -5, /* (70) tcons ::= UNIQUE LP sortlist RP onconf */
- -5, /* (71) tcons ::= CHECK LP expr RP onconf */
- -10, /* (72) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
- 0, /* (73) defer_subclause_opt ::= */
- 0, /* (74) onconf ::= */
- -3, /* (75) onconf ::= ON CONFLICT resolvetype */
- 0, /* (76) orconf ::= */
- -2, /* (77) orconf ::= OR resolvetype */
- -1, /* (78) resolvetype ::= IGNORE */
- -1, /* (79) resolvetype ::= REPLACE */
- -4, /* (80) cmd ::= DROP TABLE ifexists fullname */
- -2, /* (81) ifexists ::= IF EXISTS */
- 0, /* (82) ifexists ::= */
- -9, /* (83) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
- -4, /* (84) cmd ::= DROP VIEW ifexists fullname */
- -8, /* (85) cmd ::= createkw FUNCTION ifnotexists nm LANGUAGE nm AS STRING */
- -8, /* (86) cmd ::= createkw FUNCTION ifnotexists nm LANGUAGE nm AS BLOB */
- -4, /* (87) cmd ::= DROP FUNCTION ifexists nm */
- -1, /* (88) cmd ::= select */
- -3, /* (89) select ::= WITH wqlist selectnowith */
- -4, /* (90) select ::= WITH RECURSIVE wqlist selectnowith */
- -1, /* (91) select ::= selectnowith */
- -3, /* (92) selectnowith ::= selectnowith multiselect_op oneselect */
- -1, /* (93) multiselect_op ::= UNION */
- -2, /* (94) multiselect_op ::= UNION ALL */
- -1, /* (95) multiselect_op ::= EXCEPT|INTERSECT */
- -9, /* (96) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
- -10, /* (97) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
- -4, /* (98) values ::= VALUES LP nexprlist RP */
- -5, /* (99) values ::= values COMMA LP nexprlist RP */
- -1, /* (100) distinct ::= DISTINCT */
- -1, /* (101) distinct ::= ALL */
- 0, /* (102) distinct ::= */
- 0, /* (103) sclp ::= */
- -5, /* (104) selcollist ::= sclp scanpt expr scanpt as */
- -3, /* (105) selcollist ::= sclp scanpt STAR */
- -5, /* (106) selcollist ::= sclp scanpt nm DOT STAR */
- -2, /* (107) as ::= AS nm */
- 0, /* (108) as ::= */
- 0, /* (109) from ::= */
- -2, /* (110) from ::= FROM seltablist */
- -2, /* (111) stl_prefix ::= seltablist joinop */
- 0, /* (112) stl_prefix ::= */
- -5, /* (113) seltablist ::= stl_prefix nm dbnm as on_using */
- -6, /* (114) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
- -8, /* (115) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
- -6, /* (116) seltablist ::= stl_prefix LP select RP as on_using */
- -6, /* (117) seltablist ::= stl_prefix LP seltablist RP as on_using */
- 0, /* (118) dbnm ::= */
- -2, /* (119) dbnm ::= DOT nm */
- -1, /* (120) fullname ::= nm */
- -3, /* (121) fullname ::= nm DOT nm */
- -1, /* (122) xfullname ::= nm */
- -3, /* (123) xfullname ::= nm DOT nm */
- -5, /* (124) xfullname ::= nm DOT nm AS nm */
- -3, /* (125) xfullname ::= nm AS nm */
- -1, /* (126) joinop ::= COMMA|JOIN */
- -2, /* (127) joinop ::= JOIN_KW JOIN */
- -3, /* (128) joinop ::= JOIN_KW nm JOIN */
- -4, /* (129) joinop ::= JOIN_KW nm nm JOIN */
- -2, /* (130) on_using ::= ON expr */
- -4, /* (131) on_using ::= USING LP idlist RP */
- 0, /* (132) on_using ::= */
- 0, /* (133) indexed_opt ::= */
- -3, /* (134) indexed_by ::= INDEXED BY nm */
- -2, /* (135) indexed_by ::= NOT INDEXED */
- 0, /* (136) orderby_opt ::= */
- -3, /* (137) orderby_opt ::= ORDER BY sortlist */
- -5, /* (138) sortlist ::= sortlist COMMA expr sortorder nulls */
- -3, /* (139) sortlist ::= expr sortorder nulls */
- -1, /* (140) sortorder ::= ASC */
- -1, /* (141) sortorder ::= DESC */
- 0, /* (142) sortorder ::= */
- -2, /* (143) nulls ::= NULLS FIRST */
- -2, /* (144) nulls ::= NULLS LAST */
- 0, /* (145) nulls ::= */
- 0, /* (146) groupby_opt ::= */
- -3, /* (147) groupby_opt ::= GROUP BY nexprlist */
- 0, /* (148) having_opt ::= */
- -2, /* (149) having_opt ::= HAVING expr */
- 0, /* (150) limit_opt ::= */
- -2, /* (151) limit_opt ::= LIMIT expr */
- -4, /* (152) limit_opt ::= LIMIT expr OFFSET expr */
- -4, /* (153) limit_opt ::= LIMIT expr COMMA expr */
- -6, /* (154) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
- 0, /* (155) where_opt ::= */
- -2, /* (156) where_opt ::= WHERE expr */
- 0, /* (157) where_opt_ret ::= */
- -2, /* (158) where_opt_ret ::= WHERE expr */
- -2, /* (159) where_opt_ret ::= RETURNING selcollist */
- -4, /* (160) where_opt_ret ::= WHERE expr RETURNING selcollist */
- -9, /* (161) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
- -5, /* (162) setlist ::= setlist COMMA nm EQ expr */
- -7, /* (163) setlist ::= setlist COMMA LP idlist RP EQ expr */
- -3, /* (164) setlist ::= nm EQ expr */
- -5, /* (165) setlist ::= LP idlist RP EQ expr */
- -7, /* (166) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
- -8, /* (167) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
- 0, /* (168) upsert ::= */
- -2, /* (169) upsert ::= RETURNING selcollist */
- -12, /* (170) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
- -9, /* (171) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
- -5, /* (172) upsert ::= ON CONFLICT DO NOTHING returning */
- -8, /* (173) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
- -2, /* (174) returning ::= RETURNING selcollist */
- -2, /* (175) insert_cmd ::= INSERT orconf */
- -1, /* (176) insert_cmd ::= REPLACE */
- 0, /* (177) idlist_opt ::= */
- -3, /* (178) idlist_opt ::= LP idlist RP */
- -3, /* (179) idlist ::= idlist COMMA nm */
- -1, /* (180) idlist ::= nm */
- -3, /* (181) expr ::= LP expr RP */
- -1, /* (182) expr ::= ID|INDEXED */
- -1, /* (183) expr ::= JOIN_KW */
+ -1, /* (8) transtype ::= READONLY */
+ -2, /* (9) cmd ::= COMMIT|END trans_opt */
+ -2, /* (10) cmd ::= ROLLBACK trans_opt */
+ -2, /* (11) cmd ::= SAVEPOINT nm */
+ -3, /* (12) cmd ::= RELEASE savepoint_opt nm */
+ -5, /* (13) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
+ -6, /* (14) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
+ -1, /* (15) createkw ::= CREATE */
+ 0, /* (16) ifnotexists ::= */
+ -3, /* (17) ifnotexists ::= IF NOT EXISTS */
+ -1, /* (18) temp ::= TEMP */
+ 0, /* (19) temp ::= */
+ -5, /* (20) create_table_args ::= LP columnlist conslist_opt RP table_option_set */
+ -2, /* (21) create_table_args ::= AS select */
+ 0, /* (22) table_option_set ::= */
+ -3, /* (23) table_option_set ::= table_option_set COMMA table_option */
+ -2, /* (24) table_option ::= WITHOUT nm */
+ -2, /* (25) table_option ::= RANDOM nm */
+ -1, /* (26) table_option ::= nm */
+ -2, /* (27) columnname ::= nm typetoken */
+ 0, /* (28) typetoken ::= */
+ -4, /* (29) typetoken ::= typename LP signed RP */
+ -6, /* (30) typetoken ::= typename LP signed COMMA signed RP */
+ -2, /* (31) typename ::= typename ID|STRING */
+ 0, /* (32) scanpt ::= */
+ 0, /* (33) scantok ::= */
+ -2, /* (34) ccons ::= CONSTRAINT nm */
+ -3, /* (35) ccons ::= DEFAULT scantok term */
+ -4, /* (36) ccons ::= DEFAULT LP expr RP */
+ -4, /* (37) ccons ::= DEFAULT PLUS scantok term */
+ -4, /* (38) ccons ::= DEFAULT MINUS scantok term */
+ -3, /* (39) ccons ::= DEFAULT scantok ID|INDEXED */
+ -3, /* (40) ccons ::= NOT NULL onconf */
+ -5, /* (41) ccons ::= PRIMARY KEY sortorder onconf autoinc */
+ -2, /* (42) ccons ::= UNIQUE onconf */
+ -4, /* (43) ccons ::= CHECK LP expr RP */
+ -4, /* (44) ccons ::= REFERENCES nm eidlist_opt refargs */
+ -1, /* (45) ccons ::= defer_subclause */
+ -2, /* (46) ccons ::= COLLATE ID|STRING */
+ -3, /* (47) generated ::= LP expr RP */
+ -4, /* (48) generated ::= LP expr RP ID */
+ 0, /* (49) autoinc ::= */
+ -1, /* (50) autoinc ::= AUTOINCR */
+ 0, /* (51) refargs ::= */
+ -2, /* (52) refargs ::= refargs refarg */
+ -2, /* (53) refarg ::= MATCH nm */
+ -3, /* (54) refarg ::= ON INSERT refact */
+ -3, /* (55) refarg ::= ON DELETE refact */
+ -3, /* (56) refarg ::= ON UPDATE refact */
+ -2, /* (57) refact ::= SET NULL */
+ -2, /* (58) refact ::= SET DEFAULT */
+ -1, /* (59) refact ::= CASCADE */
+ -1, /* (60) refact ::= RESTRICT */
+ -2, /* (61) refact ::= NO ACTION */
+ -3, /* (62) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
+ -2, /* (63) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
+ 0, /* (64) init_deferred_pred_opt ::= */
+ -2, /* (65) init_deferred_pred_opt ::= INITIALLY DEFERRED */
+ -2, /* (66) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
+ 0, /* (67) conslist_opt ::= */
+ -1, /* (68) tconscomma ::= COMMA */
+ -2, /* (69) tcons ::= CONSTRAINT nm */
+ -7, /* (70) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
+ -5, /* (71) tcons ::= UNIQUE LP sortlist RP onconf */
+ -5, /* (72) tcons ::= CHECK LP expr RP onconf */
+ -10, /* (73) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
+ 0, /* (74) defer_subclause_opt ::= */
+ 0, /* (75) onconf ::= */
+ -3, /* (76) onconf ::= ON CONFLICT resolvetype */
+ 0, /* (77) orconf ::= */
+ -2, /* (78) orconf ::= OR resolvetype */
+ -1, /* (79) resolvetype ::= IGNORE */
+ -1, /* (80) resolvetype ::= REPLACE */
+ -4, /* (81) cmd ::= DROP TABLE ifexists fullname */
+ -2, /* (82) ifexists ::= IF EXISTS */
+ 0, /* (83) ifexists ::= */
+ -9, /* (84) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
+ -4, /* (85) cmd ::= DROP VIEW ifexists fullname */
+ -8, /* (86) cmd ::= createkw FUNCTION ifnotexists nm LANGUAGE nm AS STRING */
+ -8, /* (87) cmd ::= createkw FUNCTION ifnotexists nm LANGUAGE nm AS BLOB */
+ -4, /* (88) cmd ::= DROP FUNCTION ifexists nm */
+ -1, /* (89) cmd ::= select */
+ -3, /* (90) select ::= WITH wqlist selectnowith */
+ -4, /* (91) select ::= WITH RECURSIVE wqlist selectnowith */
+ -1, /* (92) select ::= selectnowith */
+ -3, /* (93) selectnowith ::= selectnowith multiselect_op oneselect */
+ -1, /* (94) multiselect_op ::= UNION */
+ -2, /* (95) multiselect_op ::= UNION ALL */
+ -1, /* (96) multiselect_op ::= EXCEPT|INTERSECT */
+ -9, /* (97) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
+ -10, /* (98) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
+ -4, /* (99) values ::= VALUES LP nexprlist RP */
+ -5, /* (100) values ::= values COMMA LP nexprlist RP */
+ -1, /* (101) distinct ::= DISTINCT */
+ -1, /* (102) distinct ::= ALL */
+ 0, /* (103) distinct ::= */
+ 0, /* (104) sclp ::= */
+ -5, /* (105) selcollist ::= sclp scanpt expr scanpt as */
+ -3, /* (106) selcollist ::= sclp scanpt STAR */
+ -5, /* (107) selcollist ::= sclp scanpt nm DOT STAR */
+ -2, /* (108) as ::= AS nm */
+ 0, /* (109) as ::= */
+ 0, /* (110) from ::= */
+ -2, /* (111) from ::= FROM seltablist */
+ -2, /* (112) stl_prefix ::= seltablist joinop */
+ 0, /* (113) stl_prefix ::= */
+ -5, /* (114) seltablist ::= stl_prefix nm dbnm as on_using */
+ -6, /* (115) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
+ -8, /* (116) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
+ -6, /* (117) seltablist ::= stl_prefix LP select RP as on_using */
+ -6, /* (118) seltablist ::= stl_prefix LP seltablist RP as on_using */
+ 0, /* (119) dbnm ::= */
+ -2, /* (120) dbnm ::= DOT nm */
+ -1, /* (121) fullname ::= nm */
+ -3, /* (122) fullname ::= nm DOT nm */
+ -1, /* (123) xfullname ::= nm */
+ -3, /* (124) xfullname ::= nm DOT nm */
+ -5, /* (125) xfullname ::= nm DOT nm AS nm */
+ -3, /* (126) xfullname ::= nm AS nm */
+ -1, /* (127) joinop ::= COMMA|JOIN */
+ -2, /* (128) joinop ::= JOIN_KW JOIN */
+ -3, /* (129) joinop ::= JOIN_KW nm JOIN */
+ -4, /* (130) joinop ::= JOIN_KW nm nm JOIN */
+ -2, /* (131) on_using ::= ON expr */
+ -4, /* (132) on_using ::= USING LP idlist RP */
+ 0, /* (133) on_using ::= */
+ 0, /* (134) indexed_opt ::= */
+ -3, /* (135) indexed_by ::= INDEXED BY nm */
+ -2, /* (136) indexed_by ::= NOT INDEXED */
+ 0, /* (137) orderby_opt ::= */
+ -3, /* (138) orderby_opt ::= ORDER BY sortlist */
+ -5, /* (139) sortlist ::= sortlist COMMA expr sortorder nulls */
+ -3, /* (140) sortlist ::= expr sortorder nulls */
+ -1, /* (141) sortorder ::= ASC */
+ -1, /* (142) sortorder ::= DESC */
+ 0, /* (143) sortorder ::= */
+ -2, /* (144) nulls ::= NULLS FIRST */
+ -2, /* (145) nulls ::= NULLS LAST */
+ 0, /* (146) nulls ::= */
+ 0, /* (147) groupby_opt ::= */
+ -3, /* (148) groupby_opt ::= GROUP BY nexprlist */
+ 0, /* (149) having_opt ::= */
+ -2, /* (150) having_opt ::= HAVING expr */
+ 0, /* (151) limit_opt ::= */
+ -2, /* (152) limit_opt ::= LIMIT expr */
+ -4, /* (153) limit_opt ::= LIMIT expr OFFSET expr */
+ -4, /* (154) limit_opt ::= LIMIT expr COMMA expr */
+ -6, /* (155) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
+ 0, /* (156) where_opt ::= */
+ -2, /* (157) where_opt ::= WHERE expr */
+ 0, /* (158) where_opt_ret ::= */
+ -2, /* (159) where_opt_ret ::= WHERE expr */
+ -2, /* (160) where_opt_ret ::= RETURNING selcollist */
+ -4, /* (161) where_opt_ret ::= WHERE expr RETURNING selcollist */
+ -9, /* (162) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
+ -5, /* (163) setlist ::= setlist COMMA nm EQ expr */
+ -7, /* (164) setlist ::= setlist COMMA LP idlist RP EQ expr */
+ -3, /* (165) setlist ::= nm EQ expr */
+ -5, /* (166) setlist ::= LP idlist RP EQ expr */
+ -7, /* (167) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
+ -8, /* (168) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
+ 0, /* (169) upsert ::= */
+ -2, /* (170) upsert ::= RETURNING selcollist */
+ -12, /* (171) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
+ -9, /* (172) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
+ -5, /* (173) upsert ::= ON CONFLICT DO NOTHING returning */
+ -8, /* (174) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
+ -2, /* (175) returning ::= RETURNING selcollist */
+ -2, /* (176) insert_cmd ::= INSERT orconf */
+ -1, /* (177) insert_cmd ::= REPLACE */
+ 0, /* (178) idlist_opt ::= */
+ -3, /* (179) idlist_opt ::= LP idlist RP */
+ -3, /* (180) idlist ::= idlist COMMA nm */
+ -1, /* (181) idlist ::= nm */
+ -3, /* (182) expr ::= LP expr RP */
+ -1, /* (183) expr ::= ID|INDEXED|JOIN_KW */
-3, /* (184) expr ::= nm DOT nm */
-5, /* (185) expr ::= nm DOT nm DOT nm */
-1, /* (186) term ::= NULL|FLOAT|BLOB */
@@ -171507,137 +175175,137 @@ static const signed char yyRuleInfoNRhs[] = {
-1, /* (189) expr ::= VARIABLE */
-3, /* (190) expr ::= expr COLLATE ID|STRING */
-6, /* (191) expr ::= CAST LP expr AS typetoken RP */
- -5, /* (192) expr ::= ID|INDEXED LP distinct exprlist RP */
- -4, /* (193) expr ::= ID|INDEXED LP STAR RP */
- -6, /* (194) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
- -5, /* (195) expr ::= ID|INDEXED LP STAR RP filter_over */
- -1, /* (196) term ::= CTIME_KW */
- -5, /* (197) expr ::= LP nexprlist COMMA expr RP */
- -3, /* (198) expr ::= expr AND expr */
- -3, /* (199) expr ::= expr OR expr */
- -3, /* (200) expr ::= expr LT|GT|GE|LE expr */
- -3, /* (201) expr ::= expr EQ|NE expr */
- -3, /* (202) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
- -3, /* (203) expr ::= expr PLUS|MINUS expr */
- -3, /* (204) expr ::= expr STAR|SLASH|REM expr */
- -3, /* (205) expr ::= expr CONCAT expr */
- -2, /* (206) likeop ::= NOT LIKE_KW|MATCH */
- -3, /* (207) expr ::= expr likeop expr */
- -5, /* (208) expr ::= expr likeop expr ESCAPE expr */
- -2, /* (209) expr ::= expr ISNULL|NOTNULL */
- -3, /* (210) expr ::= expr NOT NULL */
- -3, /* (211) expr ::= expr IS expr */
- -4, /* (212) expr ::= expr IS NOT expr */
- -6, /* (213) expr ::= expr IS NOT DISTINCT FROM expr */
- -5, /* (214) expr ::= expr IS DISTINCT FROM expr */
- -2, /* (215) expr ::= NOT expr */
- -2, /* (216) expr ::= BITNOT expr */
- -2, /* (217) expr ::= PLUS|MINUS expr */
- -3, /* (218) expr ::= expr PTR expr */
- -1, /* (219) between_op ::= BETWEEN */
- -2, /* (220) between_op ::= NOT BETWEEN */
- -5, /* (221) expr ::= expr between_op expr AND expr */
- -1, /* (222) in_op ::= IN */
- -2, /* (223) in_op ::= NOT IN */
- -5, /* (224) expr ::= expr in_op LP exprlist RP */
- -3, /* (225) expr ::= LP select RP */
- -5, /* (226) expr ::= expr in_op LP select RP */
- -5, /* (227) expr ::= expr in_op nm dbnm paren_exprlist */
- -4, /* (228) expr ::= EXISTS LP select RP */
- -5, /* (229) expr ::= CASE case_operand case_exprlist case_else END */
- -5, /* (230) case_exprlist ::= case_exprlist WHEN expr THEN expr */
- -4, /* (231) case_exprlist ::= WHEN expr THEN expr */
- -2, /* (232) case_else ::= ELSE expr */
- 0, /* (233) case_else ::= */
- -1, /* (234) case_operand ::= expr */
- 0, /* (235) case_operand ::= */
- 0, /* (236) exprlist ::= */
- -3, /* (237) nexprlist ::= nexprlist COMMA expr */
- -1, /* (238) nexprlist ::= expr */
- 0, /* (239) paren_exprlist ::= */
- -3, /* (240) paren_exprlist ::= LP exprlist RP */
- -12, /* (241) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
- -1, /* (242) uniqueflag ::= UNIQUE */
- 0, /* (243) uniqueflag ::= */
- 0, /* (244) eidlist_opt ::= */
- -3, /* (245) eidlist_opt ::= LP eidlist RP */
- -5, /* (246) eidlist ::= eidlist COMMA nm collate sortorder */
- -3, /* (247) eidlist ::= nm collate sortorder */
- 0, /* (248) collate ::= */
- -2, /* (249) collate ::= COLLATE ID|STRING */
- -4, /* (250) cmd ::= DROP INDEX ifexists fullname */
- -2, /* (251) cmd ::= VACUUM vinto */
- -3, /* (252) cmd ::= VACUUM nm vinto */
- -2, /* (253) vinto ::= INTO expr */
- 0, /* (254) vinto ::= */
- -3, /* (255) cmd ::= PRAGMA nm dbnm */
- -5, /* (256) cmd ::= PRAGMA nm dbnm EQ nmnum */
- -6, /* (257) cmd ::= PRAGMA nm dbnm LP nmnum RP */
- -5, /* (258) cmd ::= PRAGMA nm dbnm EQ minus_num */
- -6, /* (259) cmd ::= PRAGMA nm dbnm LP minus_num RP */
- -2, /* (260) plus_num ::= PLUS INTEGER|FLOAT */
- -2, /* (261) minus_num ::= MINUS INTEGER|FLOAT */
- -5, /* (262) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
- -11, /* (263) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
- -1, /* (264) trigger_time ::= BEFORE|AFTER */
- -2, /* (265) trigger_time ::= INSTEAD OF */
- 0, /* (266) trigger_time ::= */
- -1, /* (267) trigger_event ::= DELETE|INSERT */
- -1, /* (268) trigger_event ::= UPDATE */
- -3, /* (269) trigger_event ::= UPDATE OF idlist */
- 0, /* (270) when_clause ::= */
- -2, /* (271) when_clause ::= WHEN expr */
- -3, /* (272) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
- -2, /* (273) trigger_cmd_list ::= trigger_cmd SEMI */
- -3, /* (274) trnm ::= nm DOT nm */
- -3, /* (275) tridxby ::= INDEXED BY nm */
- -2, /* (276) tridxby ::= NOT INDEXED */
- -9, /* (277) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
- -8, /* (278) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
- -6, /* (279) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
- -3, /* (280) trigger_cmd ::= scanpt select scanpt */
- -4, /* (281) expr ::= RAISE LP IGNORE RP */
- -6, /* (282) expr ::= RAISE LP raisetype COMMA nm RP */
- -1, /* (283) raisetype ::= ROLLBACK */
- -1, /* (284) raisetype ::= ABORT */
- -1, /* (285) raisetype ::= FAIL */
- -4, /* (286) cmd ::= DROP TRIGGER ifexists fullname */
- -6, /* (287) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
- -3, /* (288) cmd ::= DETACH database_kw_opt expr */
- 0, /* (289) key_opt ::= */
- -2, /* (290) key_opt ::= KEY expr */
- -1, /* (291) cmd ::= REINDEX */
- -3, /* (292) cmd ::= REINDEX nm dbnm */
- -1, /* (293) cmd ::= ANALYZE */
- -3, /* (294) cmd ::= ANALYZE nm dbnm */
- -6, /* (295) cmd ::= ALTER TABLE fullname RENAME TO nm */
- -7, /* (296) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
- -6, /* (297) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
- -1, /* (298) add_column_fullname ::= fullname */
- -8, /* (299) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
- -1, /* (300) cmd ::= create_vtab */
- -4, /* (301) cmd ::= create_vtab LP vtabarglist RP */
- -8, /* (302) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
- 0, /* (303) vtabarg ::= */
- -1, /* (304) vtabargtoken ::= ANY */
- -3, /* (305) vtabargtoken ::= lp anylist RP */
- -1, /* (306) lp ::= LP */
- -2, /* (307) with ::= WITH wqlist */
- -3, /* (308) with ::= WITH RECURSIVE wqlist */
- -1, /* (309) wqas ::= AS */
- -2, /* (310) wqas ::= AS MATERIALIZED */
- -3, /* (311) wqas ::= AS NOT MATERIALIZED */
- -6, /* (312) wqitem ::= nm eidlist_opt wqas LP select RP */
- -1, /* (313) wqlist ::= wqitem */
- -3, /* (314) wqlist ::= wqlist COMMA wqitem */
- -1, /* (315) windowdefn_list ::= windowdefn */
- -3, /* (316) windowdefn_list ::= windowdefn_list COMMA windowdefn */
- -5, /* (317) windowdefn ::= nm AS LP window RP */
- -5, /* (318) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
- -6, /* (319) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
- -4, /* (320) window ::= ORDER BY sortlist frame_opt */
- -5, /* (321) window ::= nm ORDER BY sortlist frame_opt */
- -1, /* (322) window ::= frame_opt */
+ -5, /* (192) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */
+ -8, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */
+ -4, /* (194) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */
+ -6, /* (195) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */
+ -9, /* (196) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */
+ -5, /* (197) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */
+ -1, /* (198) term ::= CTIME_KW */
+ -5, /* (199) expr ::= LP nexprlist COMMA expr RP */
+ -3, /* (200) expr ::= expr AND expr */
+ -3, /* (201) expr ::= expr OR expr */
+ -3, /* (202) expr ::= expr LT|GT|GE|LE expr */
+ -3, /* (203) expr ::= expr EQ|NE expr */
+ -3, /* (204) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
+ -3, /* (205) expr ::= expr PLUS|MINUS expr */
+ -3, /* (206) expr ::= expr STAR|SLASH|REM expr */
+ -3, /* (207) expr ::= expr CONCAT expr */
+ -2, /* (208) likeop ::= NOT LIKE_KW|MATCH */
+ -3, /* (209) expr ::= expr likeop expr */
+ -5, /* (210) expr ::= expr likeop expr ESCAPE expr */
+ -2, /* (211) expr ::= expr ISNULL|NOTNULL */
+ -3, /* (212) expr ::= expr NOT NULL */
+ -3, /* (213) expr ::= expr IS expr */
+ -4, /* (214) expr ::= expr IS NOT expr */
+ -6, /* (215) expr ::= expr IS NOT DISTINCT FROM expr */
+ -5, /* (216) expr ::= expr IS DISTINCT FROM expr */
+ -2, /* (217) expr ::= NOT expr */
+ -2, /* (218) expr ::= BITNOT expr */
+ -2, /* (219) expr ::= PLUS|MINUS expr */
+ -3, /* (220) expr ::= expr PTR expr */
+ -1, /* (221) between_op ::= BETWEEN */
+ -2, /* (222) between_op ::= NOT BETWEEN */
+ -5, /* (223) expr ::= expr between_op expr AND expr */
+ -1, /* (224) in_op ::= IN */
+ -2, /* (225) in_op ::= NOT IN */
+ -5, /* (226) expr ::= expr in_op LP exprlist RP */
+ -3, /* (227) expr ::= LP select RP */
+ -5, /* (228) expr ::= expr in_op LP select RP */
+ -5, /* (229) expr ::= expr in_op nm dbnm paren_exprlist */
+ -4, /* (230) expr ::= EXISTS LP select RP */
+ -5, /* (231) expr ::= CASE case_operand case_exprlist case_else END */
+ -5, /* (232) case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ -4, /* (233) case_exprlist ::= WHEN expr THEN expr */
+ -2, /* (234) case_else ::= ELSE expr */
+ 0, /* (235) case_else ::= */
+ 0, /* (236) case_operand ::= */
+ 0, /* (237) exprlist ::= */
+ -3, /* (238) nexprlist ::= nexprlist COMMA expr */
+ -1, /* (239) nexprlist ::= expr */
+ 0, /* (240) paren_exprlist ::= */
+ -3, /* (241) paren_exprlist ::= LP exprlist RP */
+ -12, /* (242) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+ -1, /* (243) uniqueflag ::= UNIQUE */
+ 0, /* (244) uniqueflag ::= */
+ 0, /* (245) eidlist_opt ::= */
+ -3, /* (246) eidlist_opt ::= LP eidlist RP */
+ -5, /* (247) eidlist ::= eidlist COMMA nm collate sortorder */
+ -3, /* (248) eidlist ::= nm collate sortorder */
+ 0, /* (249) collate ::= */
+ -2, /* (250) collate ::= COLLATE ID|STRING */
+ -4, /* (251) cmd ::= DROP INDEX ifexists fullname */
+ -2, /* (252) cmd ::= VACUUM vinto */
+ -3, /* (253) cmd ::= VACUUM nm vinto */
+ -2, /* (254) vinto ::= INTO expr */
+ 0, /* (255) vinto ::= */
+ -3, /* (256) cmd ::= PRAGMA nm dbnm */
+ -5, /* (257) cmd ::= PRAGMA nm dbnm EQ nmnum */
+ -6, /* (258) cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ -5, /* (259) cmd ::= PRAGMA nm dbnm EQ minus_num */
+ -6, /* (260) cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ -2, /* (261) plus_num ::= PLUS INTEGER|FLOAT */
+ -2, /* (262) minus_num ::= MINUS INTEGER|FLOAT */
+ -5, /* (263) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ -11, /* (264) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ -1, /* (265) trigger_time ::= BEFORE|AFTER */
+ -2, /* (266) trigger_time ::= INSTEAD OF */
+ 0, /* (267) trigger_time ::= */
+ -1, /* (268) trigger_event ::= DELETE|INSERT */
+ -1, /* (269) trigger_event ::= UPDATE */
+ -3, /* (270) trigger_event ::= UPDATE OF idlist */
+ 0, /* (271) when_clause ::= */
+ -2, /* (272) when_clause ::= WHEN expr */
+ -3, /* (273) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ -2, /* (274) trigger_cmd_list ::= trigger_cmd SEMI */
+ -3, /* (275) trnm ::= nm DOT nm */
+ -3, /* (276) tridxby ::= INDEXED BY nm */
+ -2, /* (277) tridxby ::= NOT INDEXED */
+ -9, /* (278) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
+ -8, /* (279) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
+ -6, /* (280) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
+ -3, /* (281) trigger_cmd ::= scanpt select scanpt */
+ -4, /* (282) expr ::= RAISE LP IGNORE RP */
+ -6, /* (283) expr ::= RAISE LP raisetype COMMA nm RP */
+ -1, /* (284) raisetype ::= ROLLBACK */
+ -1, /* (285) raisetype ::= ABORT */
+ -1, /* (286) raisetype ::= FAIL */
+ -4, /* (287) cmd ::= DROP TRIGGER ifexists fullname */
+ -6, /* (288) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ -3, /* (289) cmd ::= DETACH database_kw_opt expr */
+ 0, /* (290) key_opt ::= */
+ -2, /* (291) key_opt ::= KEY expr */
+ -1, /* (292) cmd ::= REINDEX */
+ -3, /* (293) cmd ::= REINDEX nm dbnm */
+ -1, /* (294) cmd ::= ANALYZE */
+ -3, /* (295) cmd ::= ANALYZE nm dbnm */
+ -6, /* (296) cmd ::= ALTER TABLE fullname RENAME TO nm */
+ -7, /* (297) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+ -6, /* (298) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
+ -1, /* (299) add_column_fullname ::= fullname */
+ -8, /* (300) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
+ -9, /* (301) cmd ::= ALTER TABLE fullname ALTER COLUMNKW columnname TO columnname carglist */
+ -1, /* (302) cmd ::= create_vtab */
+ -4, /* (303) cmd ::= create_vtab LP vtabarglist RP */
+ -8, /* (304) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+ 0, /* (305) vtabarg ::= */
+ -1, /* (306) vtabargtoken ::= ANY */
+ -3, /* (307) vtabargtoken ::= lp anylist RP */
+ -1, /* (308) lp ::= LP */
+ -2, /* (309) with ::= WITH wqlist */
+ -3, /* (310) with ::= WITH RECURSIVE wqlist */
+ -1, /* (311) wqas ::= AS */
+ -2, /* (312) wqas ::= AS MATERIALIZED */
+ -3, /* (313) wqas ::= AS NOT MATERIALIZED */
+ -6, /* (314) wqitem ::= nm eidlist_opt wqas LP select RP */
+ -1, /* (315) wqlist ::= wqitem */
+ -3, /* (316) wqlist ::= wqlist COMMA wqitem */
+ -3, /* (317) windowdefn_list ::= windowdefn_list COMMA windowdefn */
+ -5, /* (318) windowdefn ::= nm AS LP window RP */
+ -5, /* (319) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+ -6, /* (320) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+ -4, /* (321) window ::= ORDER BY sortlist frame_opt */
+ -5, /* (322) window ::= nm ORDER BY sortlist frame_opt */
-2, /* (323) window ::= nm frame_opt */
0, /* (324) frame_opt ::= */
-3, /* (325) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
@@ -171676,32 +175344,32 @@ static const signed char yyRuleInfoNRhs[] = {
-1, /* (358) table_option_set ::= table_option */
-4, /* (359) columnlist ::= columnlist COMMA columnname carglist */
-2, /* (360) columnlist ::= columnname carglist */
- -1, /* (361) nm ::= ID|INDEXED */
+ -1, /* (361) nm ::= ID|INDEXED|JOIN_KW */
-1, /* (362) nm ::= STRING */
- -1, /* (363) nm ::= JOIN_KW */
- -1, /* (364) typetoken ::= typename */
- -1, /* (365) typename ::= ID|STRING */
- -1, /* (366) signed ::= plus_num */
- -1, /* (367) signed ::= minus_num */
- -2, /* (368) carglist ::= carglist ccons */
- 0, /* (369) carglist ::= */
- -2, /* (370) ccons ::= NULL onconf */
- -4, /* (371) ccons ::= GENERATED ALWAYS AS generated */
- -2, /* (372) ccons ::= AS generated */
- -2, /* (373) conslist_opt ::= COMMA conslist */
- -3, /* (374) conslist ::= conslist tconscomma tcons */
- -1, /* (375) conslist ::= tcons */
- 0, /* (376) tconscomma ::= */
- -1, /* (377) defer_subclause_opt ::= defer_subclause */
- -1, /* (378) resolvetype ::= raisetype */
- -1, /* (379) selectnowith ::= oneselect */
- -1, /* (380) oneselect ::= values */
- -2, /* (381) sclp ::= selcollist COMMA */
- -1, /* (382) as ::= ID|STRING */
- -1, /* (383) indexed_opt ::= indexed_by */
- 0, /* (384) returning ::= */
- -1, /* (385) expr ::= term */
- -1, /* (386) likeop ::= LIKE_KW|MATCH */
+ -1, /* (363) typetoken ::= typename */
+ -1, /* (364) typename ::= ID|STRING */
+ -1, /* (365) signed ::= plus_num */
+ -1, /* (366) signed ::= minus_num */
+ -2, /* (367) carglist ::= carglist ccons */
+ 0, /* (368) carglist ::= */
+ -2, /* (369) ccons ::= NULL onconf */
+ -4, /* (370) ccons ::= GENERATED ALWAYS AS generated */
+ -2, /* (371) ccons ::= AS generated */
+ -2, /* (372) conslist_opt ::= COMMA conslist */
+ -3, /* (373) conslist ::= conslist tconscomma tcons */
+ -1, /* (374) conslist ::= tcons */
+ 0, /* (375) tconscomma ::= */
+ -1, /* (376) defer_subclause_opt ::= defer_subclause */
+ -1, /* (377) resolvetype ::= raisetype */
+ -1, /* (378) selectnowith ::= oneselect */
+ -1, /* (379) oneselect ::= values */
+ -2, /* (380) sclp ::= selcollist COMMA */
+ -1, /* (381) as ::= ID|STRING */
+ -1, /* (382) indexed_opt ::= indexed_by */
+ 0, /* (383) returning ::= */
+ -1, /* (384) expr ::= term */
+ -1, /* (385) likeop ::= LIKE_KW|MATCH */
+ -1, /* (386) case_operand ::= expr */
-1, /* (387) exprlist ::= nexprlist */
-1, /* (388) nmnum ::= plus_num */
-1, /* (389) nmnum ::= nm */
@@ -171724,6 +175392,8 @@ static const signed char yyRuleInfoNRhs[] = {
-4, /* (406) anylist ::= anylist LP anylist RP */
-2, /* (407) anylist ::= anylist ANY */
0, /* (408) with ::= */
+ -1, /* (409) windowdefn_list ::= windowdefn */
+ -1, /* (410) window ::= frame_opt */
};
static void yy_accept(yyParser*); /* Forward Declaration */
@@ -171766,171 +175436,174 @@ static YYACTIONTYPE yy_reduce(
/********** Begin reduce actions **********************************************/
YYMINORTYPE yylhsminor;
case 0: /* explain ::= EXPLAIN */
-{ pParse->explain = 1; }
+{ if( pParse->pReprepare==0 ) pParse->explain = 1; }
break;
case 1: /* explain ::= EXPLAIN QUERY PLAN */
-{ pParse->explain = 2; }
+{ if( pParse->pReprepare==0 ) pParse->explain = 2; }
break;
case 2: /* cmdx ::= cmd */
{ sqlite3FinishCoding(pParse); }
break;
case 3: /* cmd ::= BEGIN transtype trans_opt */
-{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy436);}
+{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy144);}
break;
case 4: /* transtype ::= */
-{yymsp[1].minor.yy436 = TK_DEFERRED;}
+{yymsp[1].minor.yy144 = TK_DEFERRED;}
break;
case 5: /* transtype ::= DEFERRED */
case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6);
case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7);
case 327: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==327);
-{yymsp[0].minor.yy436 = yymsp[0].major; /*A-overwrites-X*/}
+{yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-X*/}
break;
- case 8: /* cmd ::= COMMIT|END trans_opt */
- case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9);
+ case 8: /* transtype ::= READONLY */
+{yymsp[0].minor.yy144 = TK_DEFERRED; /*yymsp[0].minor.yy144-overwrites-X*/}
+ break;
+ case 9: /* cmd ::= COMMIT|END trans_opt */
+ case 10: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==10);
{sqlite3EndTransaction(pParse,yymsp[-1].major);}
break;
- case 10: /* cmd ::= SAVEPOINT nm */
+ case 11: /* cmd ::= SAVEPOINT nm */
{
sqlite3Savepoint(pParse, SAVEPOINT_BEGIN, &yymsp[0].minor.yy0);
}
break;
- case 11: /* cmd ::= RELEASE savepoint_opt nm */
+ case 12: /* cmd ::= RELEASE savepoint_opt nm */
{
sqlite3Savepoint(pParse, SAVEPOINT_RELEASE, &yymsp[0].minor.yy0);
}
break;
- case 12: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
+ case 13: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
{
sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0);
}
break;
- case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
+ case 14: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
{
- sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy436,0,0,yymsp[-2].minor.yy436);
+ sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy144,0,0,yymsp[-2].minor.yy144);
}
break;
- case 14: /* createkw ::= CREATE */
+ case 15: /* createkw ::= CREATE */
{disableLookaside(pParse);}
break;
- case 15: /* ifnotexists ::= */
- case 18: /* temp ::= */ yytestcase(yyruleno==18);
- case 48: /* autoinc ::= */ yytestcase(yyruleno==48);
- case 63: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==63);
- case 73: /* defer_subclause_opt ::= */ yytestcase(yyruleno==73);
- case 82: /* ifexists ::= */ yytestcase(yyruleno==82);
- case 102: /* distinct ::= */ yytestcase(yyruleno==102);
- case 248: /* collate ::= */ yytestcase(yyruleno==248);
-{yymsp[1].minor.yy436 = 0;}
+ case 16: /* ifnotexists ::= */
+ case 19: /* temp ::= */ yytestcase(yyruleno==19);
+ case 49: /* autoinc ::= */ yytestcase(yyruleno==49);
+ case 64: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==64);
+ case 74: /* defer_subclause_opt ::= */ yytestcase(yyruleno==74);
+ case 83: /* ifexists ::= */ yytestcase(yyruleno==83);
+ case 103: /* distinct ::= */ yytestcase(yyruleno==103);
+ case 249: /* collate ::= */ yytestcase(yyruleno==249);
+{yymsp[1].minor.yy144 = 0;}
break;
- case 16: /* ifnotexists ::= IF NOT EXISTS */
-{yymsp[-2].minor.yy436 = 1;}
+ case 17: /* ifnotexists ::= IF NOT EXISTS */
+{yymsp[-2].minor.yy144 = 1;}
break;
- case 17: /* temp ::= TEMP */
-{yymsp[0].minor.yy436 = pParse->db->init.busy==0;}
+ case 18: /* temp ::= TEMP */
+{yymsp[0].minor.yy144 = pParse->db->init.busy==0;}
break;
- case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_option_set */
+ case 20: /* create_table_args ::= LP columnlist conslist_opt RP table_option_set */
{
- sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy135,0);
+ sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy391,0);
}
break;
- case 20: /* create_table_args ::= AS select */
+ case 21: /* create_table_args ::= AS select */
{
- sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy136);
- sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy136);
+ sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy555);
+ sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy555);
}
break;
- case 21: /* table_option_set ::= */
-{yymsp[1].minor.yy135 = 0;}
+ case 22: /* table_option_set ::= */
+{yymsp[1].minor.yy391 = 0;}
break;
- case 22: /* table_option_set ::= table_option_set COMMA table_option */
-{yylhsminor.yy135 = yymsp[-2].minor.yy135|yymsp[0].minor.yy135;}
- yymsp[-2].minor.yy135 = yylhsminor.yy135;
+ case 23: /* table_option_set ::= table_option_set COMMA table_option */
+{yylhsminor.yy391 = yymsp[-2].minor.yy391|yymsp[0].minor.yy391;}
+ yymsp[-2].minor.yy391 = yylhsminor.yy391;
break;
- case 23: /* table_option ::= WITHOUT nm */
+ case 24: /* table_option ::= WITHOUT nm */
{
if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){
- yymsp[-1].minor.yy135 = TF_WithoutRowid | TF_NoVisibleRowid;
+ yymsp[-1].minor.yy391 = TF_WithoutRowid | TF_NoVisibleRowid;
}else{
- yymsp[-1].minor.yy135 = 0;
+ yymsp[-1].minor.yy391 = 0;
sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
}
}
break;
- case 24: /* table_option ::= RANDOM nm */
+ case 25: /* table_option ::= RANDOM nm */
{
if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){
- yymsp[-1].minor.yy135 = TF_RandomRowid;
+ yymsp[-1].minor.yy391 = TF_RandomRowid;
}else{
- yymsp[-1].minor.yy135 = 0;
+ yymsp[-1].minor.yy391 = 0;
sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
}
}
break;
- case 25: /* table_option ::= nm */
+ case 26: /* table_option ::= nm */
{
if( yymsp[0].minor.yy0.n==6 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"strict",6)==0 ){
- yylhsminor.yy135 = TF_Strict;
+ yylhsminor.yy391 = TF_Strict;
}else{
- yylhsminor.yy135 = 0;
+ yylhsminor.yy391 = 0;
sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
}
}
- yymsp[0].minor.yy135 = yylhsminor.yy135;
+ yymsp[0].minor.yy391 = yylhsminor.yy391;
break;
- case 26: /* columnname ::= nm typetoken */
+ case 27: /* columnname ::= nm typetoken */
{sqlite3AddColumn(pParse,yymsp[-1].minor.yy0,yymsp[0].minor.yy0);}
break;
- case 27: /* typetoken ::= */
- case 66: /* conslist_opt ::= */ yytestcase(yyruleno==66);
- case 108: /* as ::= */ yytestcase(yyruleno==108);
+ case 28: /* typetoken ::= */
+ case 67: /* conslist_opt ::= */ yytestcase(yyruleno==67);
+ case 109: /* as ::= */ yytestcase(yyruleno==109);
{yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;}
break;
- case 28: /* typetoken ::= typename LP signed RP */
+ case 29: /* typetoken ::= typename LP signed RP */
{
yymsp[-3].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z);
}
break;
- case 29: /* typetoken ::= typename LP signed COMMA signed RP */
+ case 30: /* typetoken ::= typename LP signed COMMA signed RP */
{
yymsp[-5].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z);
}
break;
- case 30: /* typename ::= typename ID|STRING */
+ case 31: /* typename ::= typename ID|STRING */
{yymsp[-1].minor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);}
break;
- case 31: /* scanpt ::= */
+ case 32: /* scanpt ::= */
{
assert( yyLookahead!=YYNOCODE );
- yymsp[1].minor.yy594 = yyLookaheadToken.z;
+ yymsp[1].minor.yy168 = yyLookaheadToken.z;
}
break;
- case 32: /* scantok ::= */
+ case 33: /* scantok ::= */
{
assert( yyLookahead!=YYNOCODE );
yymsp[1].minor.yy0 = yyLookaheadToken;
}
break;
- case 33: /* ccons ::= CONSTRAINT nm */
- case 68: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==68);
+ case 34: /* ccons ::= CONSTRAINT nm */
+ case 69: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==69);
{pParse->constraintName = yymsp[0].minor.yy0;}
break;
- case 34: /* ccons ::= DEFAULT scantok term */
-{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy224,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
+ case 35: /* ccons ::= DEFAULT scantok term */
+{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy454,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
break;
- case 35: /* ccons ::= DEFAULT LP expr RP */
-{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy224,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);}
+ case 36: /* ccons ::= DEFAULT LP expr RP */
+{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy454,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);}
break;
- case 36: /* ccons ::= DEFAULT PLUS scantok term */
-{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy224,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
+ case 37: /* ccons ::= DEFAULT PLUS scantok term */
+{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy454,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
break;
- case 37: /* ccons ::= DEFAULT MINUS scantok term */
+ case 38: /* ccons ::= DEFAULT MINUS scantok term */
{
- Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy224, 0);
+ Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy454, 0);
sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);
}
break;
- case 38: /* ccons ::= DEFAULT scantok ID|INDEXED */
+ case 39: /* ccons ::= DEFAULT scantok ID|INDEXED */
{
Expr *p = tokenExpr(pParse, TK_STRING, yymsp[0].minor.yy0);
if( p ){
@@ -171940,177 +175613,176 @@ static YYACTIONTYPE yy_reduce(
sqlite3AddDefaultValue(pParse,p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.z+yymsp[0].minor.yy0.n);
}
break;
- case 39: /* ccons ::= NOT NULL onconf */
-{sqlite3AddNotNull(pParse, yymsp[0].minor.yy436);}
+ case 40: /* ccons ::= NOT NULL onconf */
+{sqlite3AddNotNull(pParse, yymsp[0].minor.yy144);}
break;
- case 40: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
-{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy436,yymsp[0].minor.yy436,yymsp[-2].minor.yy436);}
+ case 41: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
+{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy144,yymsp[0].minor.yy144,yymsp[-2].minor.yy144);}
break;
- case 41: /* ccons ::= UNIQUE onconf */
-{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy436,0,0,0,0,
+ case 42: /* ccons ::= UNIQUE onconf */
+{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy144,0,0,0,0,
SQLITE_IDXTYPE_UNIQUE);}
break;
- case 42: /* ccons ::= CHECK LP expr RP */
-{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy224,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);}
+ case 43: /* ccons ::= CHECK LP expr RP */
+{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy454,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);}
break;
- case 43: /* ccons ::= REFERENCES nm eidlist_opt refargs */
-{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy586,yymsp[0].minor.yy436);}
+ case 44: /* ccons ::= REFERENCES nm eidlist_opt refargs */
+{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy14,yymsp[0].minor.yy144);}
break;
- case 44: /* ccons ::= defer_subclause */
-{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy436);}
+ case 45: /* ccons ::= defer_subclause */
+{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy144);}
break;
- case 45: /* ccons ::= COLLATE ID|STRING */
+ case 46: /* ccons ::= COLLATE ID|STRING */
{sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);}
break;
- case 46: /* generated ::= LP expr RP */
-{sqlite3AddGenerated(pParse,yymsp[-1].minor.yy224,0);}
+ case 47: /* generated ::= LP expr RP */
+{sqlite3AddGenerated(pParse,yymsp[-1].minor.yy454,0);}
break;
- case 47: /* generated ::= LP expr RP ID */
-{sqlite3AddGenerated(pParse,yymsp[-2].minor.yy224,&yymsp[0].minor.yy0);}
+ case 48: /* generated ::= LP expr RP ID */
+{sqlite3AddGenerated(pParse,yymsp[-2].minor.yy454,&yymsp[0].minor.yy0);}
break;
- case 49: /* autoinc ::= AUTOINCR */
-{yymsp[0].minor.yy436 = 1;}
+ case 50: /* autoinc ::= AUTOINCR */
+{yymsp[0].minor.yy144 = 1;}
break;
- case 50: /* refargs ::= */
-{ yymsp[1].minor.yy436 = OE_None*0x0101; /* EV: R-19803-45884 */}
+ case 51: /* refargs ::= */
+{ yymsp[1].minor.yy144 = OE_None*0x0101; /* EV: R-19803-45884 */}
break;
- case 51: /* refargs ::= refargs refarg */
-{ yymsp[-1].minor.yy436 = (yymsp[-1].minor.yy436 & ~yymsp[0].minor.yy275.mask) | yymsp[0].minor.yy275.value; }
+ case 52: /* refargs ::= refargs refarg */
+{ yymsp[-1].minor.yy144 = (yymsp[-1].minor.yy144 & ~yymsp[0].minor.yy383.mask) | yymsp[0].minor.yy383.value; }
break;
- case 52: /* refarg ::= MATCH nm */
-{ yymsp[-1].minor.yy275.value = 0; yymsp[-1].minor.yy275.mask = 0x000000; }
+ case 53: /* refarg ::= MATCH nm */
+{ yymsp[-1].minor.yy383.value = 0; yymsp[-1].minor.yy383.mask = 0x000000; }
break;
- case 53: /* refarg ::= ON INSERT refact */
-{ yymsp[-2].minor.yy275.value = 0; yymsp[-2].minor.yy275.mask = 0x000000; }
+ case 54: /* refarg ::= ON INSERT refact */
+{ yymsp[-2].minor.yy383.value = 0; yymsp[-2].minor.yy383.mask = 0x000000; }
break;
- case 54: /* refarg ::= ON DELETE refact */
-{ yymsp[-2].minor.yy275.value = yymsp[0].minor.yy436; yymsp[-2].minor.yy275.mask = 0x0000ff; }
+ case 55: /* refarg ::= ON DELETE refact */
+{ yymsp[-2].minor.yy383.value = yymsp[0].minor.yy144; yymsp[-2].minor.yy383.mask = 0x0000ff; }
break;
- case 55: /* refarg ::= ON UPDATE refact */
-{ yymsp[-2].minor.yy275.value = yymsp[0].minor.yy436<<8; yymsp[-2].minor.yy275.mask = 0x00ff00; }
+ case 56: /* refarg ::= ON UPDATE refact */
+{ yymsp[-2].minor.yy383.value = yymsp[0].minor.yy144<<8; yymsp[-2].minor.yy383.mask = 0x00ff00; }
break;
- case 56: /* refact ::= SET NULL */
-{ yymsp[-1].minor.yy436 = OE_SetNull; /* EV: R-33326-45252 */}
+ case 57: /* refact ::= SET NULL */
+{ yymsp[-1].minor.yy144 = OE_SetNull; /* EV: R-33326-45252 */}
break;
- case 57: /* refact ::= SET DEFAULT */
-{ yymsp[-1].minor.yy436 = OE_SetDflt; /* EV: R-33326-45252 */}
+ case 58: /* refact ::= SET DEFAULT */
+{ yymsp[-1].minor.yy144 = OE_SetDflt; /* EV: R-33326-45252 */}
break;
- case 58: /* refact ::= CASCADE */
-{ yymsp[0].minor.yy436 = OE_Cascade; /* EV: R-33326-45252 */}
+ case 59: /* refact ::= CASCADE */
+{ yymsp[0].minor.yy144 = OE_Cascade; /* EV: R-33326-45252 */}
break;
- case 59: /* refact ::= RESTRICT */
-{ yymsp[0].minor.yy436 = OE_Restrict; /* EV: R-33326-45252 */}
+ case 60: /* refact ::= RESTRICT */
+{ yymsp[0].minor.yy144 = OE_Restrict; /* EV: R-33326-45252 */}
break;
- case 60: /* refact ::= NO ACTION */
-{ yymsp[-1].minor.yy436 = OE_None; /* EV: R-33326-45252 */}
+ case 61: /* refact ::= NO ACTION */
+{ yymsp[-1].minor.yy144 = OE_None; /* EV: R-33326-45252 */}
break;
- case 61: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
-{yymsp[-2].minor.yy436 = 0;}
+ case 62: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
+{yymsp[-2].minor.yy144 = 0;}
break;
- case 62: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
- case 77: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==77);
- case 175: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==175);
-{yymsp[-1].minor.yy436 = yymsp[0].minor.yy436;}
+ case 63: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
+ case 78: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==78);
+ case 176: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==176);
+{yymsp[-1].minor.yy144 = yymsp[0].minor.yy144;}
break;
- case 64: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
- case 81: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==81);
- case 220: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==220);
- case 223: /* in_op ::= NOT IN */ yytestcase(yyruleno==223);
- case 249: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==249);
-{yymsp[-1].minor.yy436 = 1;}
+ case 65: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
+ case 82: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==82);
+ case 222: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==222);
+ case 225: /* in_op ::= NOT IN */ yytestcase(yyruleno==225);
+ case 250: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==250);
+{yymsp[-1].minor.yy144 = 1;}
break;
- case 65: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
-{yymsp[-1].minor.yy436 = 0;}
+ case 66: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
+{yymsp[-1].minor.yy144 = 0;}
break;
- case 67: /* tconscomma ::= COMMA */
+ case 68: /* tconscomma ::= COMMA */
{pParse->constraintName.n = 0;}
break;
- case 69: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
-{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy586,yymsp[0].minor.yy436,yymsp[-2].minor.yy436,0);}
+ case 70: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
+{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy14,yymsp[0].minor.yy144,yymsp[-2].minor.yy144,0);}
break;
- case 70: /* tcons ::= UNIQUE LP sortlist RP onconf */
-{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy586,yymsp[0].minor.yy436,0,0,0,0,
+ case 71: /* tcons ::= UNIQUE LP sortlist RP onconf */
+{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy14,yymsp[0].minor.yy144,0,0,0,0,
SQLITE_IDXTYPE_UNIQUE);}
break;
- case 71: /* tcons ::= CHECK LP expr RP onconf */
-{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy224,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);}
+ case 72: /* tcons ::= CHECK LP expr RP onconf */
+{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy454,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);}
break;
- case 72: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
+ case 73: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
{
- sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy586, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy586, yymsp[-1].minor.yy436);
- sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy436);
+ sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy14, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[-1].minor.yy144);
+ sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy144);
}
break;
- case 74: /* onconf ::= */
- case 76: /* orconf ::= */ yytestcase(yyruleno==76);
-{yymsp[1].minor.yy436 = OE_Default;}
+ case 75: /* onconf ::= */
+ case 77: /* orconf ::= */ yytestcase(yyruleno==77);
+{yymsp[1].minor.yy144 = OE_Default;}
break;
- case 75: /* onconf ::= ON CONFLICT resolvetype */
-{yymsp[-2].minor.yy436 = yymsp[0].minor.yy436;}
+ case 76: /* onconf ::= ON CONFLICT resolvetype */
+{yymsp[-2].minor.yy144 = yymsp[0].minor.yy144;}
break;
- case 78: /* resolvetype ::= IGNORE */
-{yymsp[0].minor.yy436 = OE_Ignore;}
+ case 79: /* resolvetype ::= IGNORE */
+{yymsp[0].minor.yy144 = OE_Ignore;}
break;
- case 79: /* resolvetype ::= REPLACE */
- case 176: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==176);
-{yymsp[0].minor.yy436 = OE_Replace;}
+ case 80: /* resolvetype ::= REPLACE */
+ case 177: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==177);
+{yymsp[0].minor.yy144 = OE_Replace;}
break;
- case 80: /* cmd ::= DROP TABLE ifexists fullname */
+ case 81: /* cmd ::= DROP TABLE ifexists fullname */
{
- sqlite3DropTable(pParse, yymsp[0].minor.yy493, 0, yymsp[-1].minor.yy436);
+ sqlite3DropTable(pParse, yymsp[0].minor.yy203, 0, yymsp[-1].minor.yy144);
}
break;
- case 83: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
+ case 84: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
{
- sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy586, yymsp[0].minor.yy136, yymsp[-7].minor.yy436, yymsp[-5].minor.yy436);
+ sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[0].minor.yy555, yymsp[-7].minor.yy144, yymsp[-5].minor.yy144);
}
break;
- case 84: /* cmd ::= DROP VIEW ifexists fullname */
+ case 85: /* cmd ::= DROP VIEW ifexists fullname */
{
- sqlite3DropTable(pParse, yymsp[0].minor.yy493, 1, yymsp[-1].minor.yy436);
+ sqlite3DropTable(pParse, yymsp[0].minor.yy203, 1, yymsp[-1].minor.yy144);
}
break;
- case 85: /* cmd ::= createkw FUNCTION ifnotexists nm LANGUAGE nm AS STRING */
+ case 86: /* cmd ::= createkw FUNCTION ifnotexists nm LANGUAGE nm AS STRING */
{
- libsql_create_function(pParse, &yymsp[-4].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, 0, yymsp[-5].minor.yy436);
+ libsql_create_function(pParse, &yymsp[-4].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, 0, yymsp[-5].minor.yy144);
}
break;
- case 86: /* cmd ::= createkw FUNCTION ifnotexists nm LANGUAGE nm AS BLOB */
+ case 87: /* cmd ::= createkw FUNCTION ifnotexists nm LANGUAGE nm AS BLOB */
{
- libsql_create_function(pParse, &yymsp[-4].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, 1, yymsp[-5].minor.yy436);
+ libsql_create_function(pParse, &yymsp[-4].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, 1, yymsp[-5].minor.yy144);
}
break;
- case 87: /* cmd ::= DROP FUNCTION ifexists nm */
+ case 88: /* cmd ::= DROP FUNCTION ifexists nm */
{
- libsql_drop_function(pParse, &yymsp[0].minor.yy0, yymsp[-1].minor.yy436);
+ libsql_drop_function(pParse, &yymsp[0].minor.yy0, yymsp[-1].minor.yy144);
}
break;
- case 88: /* cmd ::= select */
+ case 89: /* cmd ::= select */
{
SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0};
- sqlite3Select(pParse, yymsp[0].minor.yy136, &dest);
- sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy136);
+ sqlite3Select(pParse, yymsp[0].minor.yy555, &dest);
+ sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy555);
}
break;
- case 89: /* select ::= WITH wqlist selectnowith */
-{yymsp[-2].minor.yy136 = attachWithToSelect(pParse,yymsp[0].minor.yy136,yymsp[-1].minor.yy19);}
+ case 90: /* select ::= WITH wqlist selectnowith */
+{yymsp[-2].minor.yy555 = attachWithToSelect(pParse,yymsp[0].minor.yy555,yymsp[-1].minor.yy59);}
break;
- case 90: /* select ::= WITH RECURSIVE wqlist selectnowith */
-{yymsp[-3].minor.yy136 = attachWithToSelect(pParse,yymsp[0].minor.yy136,yymsp[-1].minor.yy19);}
+ case 91: /* select ::= WITH RECURSIVE wqlist selectnowith */
+{yymsp[-3].minor.yy555 = attachWithToSelect(pParse,yymsp[0].minor.yy555,yymsp[-1].minor.yy59);}
break;
- case 91: /* select ::= selectnowith */
+ case 92: /* select ::= selectnowith */
{
- Select *p = yymsp[0].minor.yy136;
+ Select *p = yymsp[0].minor.yy555;
if( p ){
parserDoubleLinkSelect(pParse, p);
}
- yymsp[0].minor.yy136 = p; /*A-overwrites-X*/
}
break;
- case 92: /* selectnowith ::= selectnowith multiselect_op oneselect */
+ case 93: /* selectnowith ::= selectnowith multiselect_op oneselect */
{
- Select *pRhs = yymsp[0].minor.yy136;
- Select *pLhs = yymsp[-2].minor.yy136;
+ Select *pRhs = yymsp[0].minor.yy555;
+ Select *pLhs = yymsp[-2].minor.yy555;
if( pRhs && pRhs->pPrior ){
SrcList *pFrom;
Token x;
@@ -172120,145 +175792,148 @@ static YYACTIONTYPE yy_reduce(
pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0);
}
if( pRhs ){
- pRhs->op = (u8)yymsp[-1].minor.yy436;
+ pRhs->op = (u8)yymsp[-1].minor.yy144;
pRhs->pPrior = pLhs;
if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue;
pRhs->selFlags &= ~SF_MultiValue;
- if( yymsp[-1].minor.yy436!=TK_ALL ) pParse->hasCompound = 1;
+ if( yymsp[-1].minor.yy144!=TK_ALL ) pParse->hasCompound = 1;
}else{
sqlite3SelectDelete(pParse->db, pLhs);
}
- yymsp[-2].minor.yy136 = pRhs;
+ yymsp[-2].minor.yy555 = pRhs;
}
break;
- case 93: /* multiselect_op ::= UNION */
- case 95: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==95);
-{yymsp[0].minor.yy436 = yymsp[0].major; /*A-overwrites-OP*/}
+ case 94: /* multiselect_op ::= UNION */
+ case 96: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==96);
+{yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-OP*/}
break;
- case 94: /* multiselect_op ::= UNION ALL */
-{yymsp[-1].minor.yy436 = TK_ALL;}
+ case 95: /* multiselect_op ::= UNION ALL */
+{yymsp[-1].minor.yy144 = TK_ALL;}
break;
- case 96: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
+ case 97: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
{
- yymsp[-8].minor.yy136 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy586,yymsp[-5].minor.yy493,yymsp[-4].minor.yy224,yymsp[-3].minor.yy586,yymsp[-2].minor.yy224,yymsp[-1].minor.yy586,yymsp[-7].minor.yy436,yymsp[0].minor.yy224);
+ yymsp[-8].minor.yy555 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy14,yymsp[-5].minor.yy203,yymsp[-4].minor.yy454,yymsp[-3].minor.yy14,yymsp[-2].minor.yy454,yymsp[-1].minor.yy14,yymsp[-7].minor.yy144,yymsp[0].minor.yy454);
}
break;
- case 97: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
+ case 98: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
{
- yymsp[-9].minor.yy136 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy586,yymsp[-6].minor.yy493,yymsp[-5].minor.yy224,yymsp[-4].minor.yy586,yymsp[-3].minor.yy224,yymsp[-1].minor.yy586,yymsp[-8].minor.yy436,yymsp[0].minor.yy224);
- if( yymsp[-9].minor.yy136 ){
- yymsp[-9].minor.yy136->pWinDefn = yymsp[-2].minor.yy591;
+ yymsp[-9].minor.yy555 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy14,yymsp[-6].minor.yy203,yymsp[-5].minor.yy454,yymsp[-4].minor.yy14,yymsp[-3].minor.yy454,yymsp[-1].minor.yy14,yymsp[-8].minor.yy144,yymsp[0].minor.yy454);
+ if( yymsp[-9].minor.yy555 ){
+ yymsp[-9].minor.yy555->pWinDefn = yymsp[-2].minor.yy211;
}else{
- sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy591);
+ sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy211);
}
}
break;
- case 98: /* values ::= VALUES LP nexprlist RP */
+ case 99: /* values ::= VALUES LP nexprlist RP */
{
- yymsp[-3].minor.yy136 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy586,0,0,0,0,0,SF_Values,0);
+ yymsp[-3].minor.yy555 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy14,0,0,0,0,0,SF_Values,0);
}
break;
- case 99: /* values ::= values COMMA LP nexprlist RP */
+ case 100: /* values ::= values COMMA LP nexprlist RP */
{
- Select *pRight, *pLeft = yymsp[-4].minor.yy136;
- pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy586,0,0,0,0,0,SF_Values|SF_MultiValue,0);
+ Select *pRight, *pLeft = yymsp[-4].minor.yy555;
+ pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy14,0,0,0,0,0,SF_Values|SF_MultiValue,0);
if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
if( pRight ){
pRight->op = TK_ALL;
pRight->pPrior = pLeft;
- yymsp[-4].minor.yy136 = pRight;
+ yymsp[-4].minor.yy555 = pRight;
}else{
- yymsp[-4].minor.yy136 = pLeft;
+ yymsp[-4].minor.yy555 = pLeft;
}
}
break;
- case 100: /* distinct ::= DISTINCT */
-{yymsp[0].minor.yy436 = SF_Distinct;}
+ case 101: /* distinct ::= DISTINCT */
+{yymsp[0].minor.yy144 = SF_Distinct;}
break;
- case 101: /* distinct ::= ALL */
-{yymsp[0].minor.yy436 = SF_All;}
+ case 102: /* distinct ::= ALL */
+{yymsp[0].minor.yy144 = SF_All;}
break;
- case 103: /* sclp ::= */
- case 136: /* orderby_opt ::= */ yytestcase(yyruleno==136);
- case 146: /* groupby_opt ::= */ yytestcase(yyruleno==146);
- case 236: /* exprlist ::= */ yytestcase(yyruleno==236);
- case 239: /* paren_exprlist ::= */ yytestcase(yyruleno==239);
- case 244: /* eidlist_opt ::= */ yytestcase(yyruleno==244);
-{yymsp[1].minor.yy586 = 0;}
+ case 104: /* sclp ::= */
+ case 137: /* orderby_opt ::= */ yytestcase(yyruleno==137);
+ case 147: /* groupby_opt ::= */ yytestcase(yyruleno==147);
+ case 237: /* exprlist ::= */ yytestcase(yyruleno==237);
+ case 240: /* paren_exprlist ::= */ yytestcase(yyruleno==240);
+ case 245: /* eidlist_opt ::= */ yytestcase(yyruleno==245);
+{yymsp[1].minor.yy14 = 0;}
break;
- case 104: /* selcollist ::= sclp scanpt expr scanpt as */
+ case 105: /* selcollist ::= sclp scanpt expr scanpt as */
{
- yymsp[-4].minor.yy586 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy586, yymsp[-2].minor.yy224);
- if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy586, &yymsp[0].minor.yy0, 1);
- sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy586,yymsp[-3].minor.yy594,yymsp[-1].minor.yy594);
+ yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy14, yymsp[-2].minor.yy454);
+ if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy14, &yymsp[0].minor.yy0, 1);
+ sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy14,yymsp[-3].minor.yy168,yymsp[-1].minor.yy168);
}
break;
- case 105: /* selcollist ::= sclp scanpt STAR */
+ case 106: /* selcollist ::= sclp scanpt STAR */
{
Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
- yymsp[-2].minor.yy586 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy586, p);
+ sqlite3ExprSetErrorOffset(p, (int)(yymsp[0].minor.yy0.z - pParse->zTail));
+ yymsp[-2].minor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy14, p);
}
break;
- case 106: /* selcollist ::= sclp scanpt nm DOT STAR */
+ case 107: /* selcollist ::= sclp scanpt nm DOT STAR */
{
- Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
- Expr *pLeft = tokenExpr(pParse, TK_ID, yymsp[-2].minor.yy0);
- Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
- yymsp[-4].minor.yy586 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy586, pDot);
-}
- break;
- case 107: /* as ::= AS nm */
- case 119: /* dbnm ::= DOT nm */ yytestcase(yyruleno==119);
- case 260: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==260);
- case 261: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==261);
+ Expr *pRight, *pLeft, *pDot;
+ pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
+ sqlite3ExprSetErrorOffset(pRight, (int)(yymsp[0].minor.yy0.z - pParse->zTail));
+ pLeft = tokenExpr(pParse, TK_ID, yymsp[-2].minor.yy0);
+ pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
+ yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, pDot);
+}
+ break;
+ case 108: /* as ::= AS nm */
+ case 120: /* dbnm ::= DOT nm */ yytestcase(yyruleno==120);
+ case 261: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==261);
+ case 262: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==262);
{yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;}
break;
- case 109: /* from ::= */
- case 112: /* stl_prefix ::= */ yytestcase(yyruleno==112);
-{yymsp[1].minor.yy493 = 0;}
+ case 110: /* from ::= */
+ case 113: /* stl_prefix ::= */ yytestcase(yyruleno==113);
+{yymsp[1].minor.yy203 = 0;}
break;
- case 110: /* from ::= FROM seltablist */
+ case 111: /* from ::= FROM seltablist */
{
- yymsp[-1].minor.yy493 = yymsp[0].minor.yy493;
- sqlite3SrcListShiftJoinType(pParse,yymsp[-1].minor.yy493);
+ yymsp[-1].minor.yy203 = yymsp[0].minor.yy203;
+ sqlite3SrcListShiftJoinType(pParse,yymsp[-1].minor.yy203);
}
break;
- case 111: /* stl_prefix ::= seltablist joinop */
+ case 112: /* stl_prefix ::= seltablist joinop */
{
- if( ALWAYS(yymsp[-1].minor.yy493 && yymsp[-1].minor.yy493->nSrc>0) ) yymsp[-1].minor.yy493->a[yymsp[-1].minor.yy493->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy436;
+ if( ALWAYS(yymsp[-1].minor.yy203 && yymsp[-1].minor.yy203->nSrc>0) ) yymsp[-1].minor.yy203->a[yymsp[-1].minor.yy203->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy144;
}
break;
- case 113: /* seltablist ::= stl_prefix nm dbnm as on_using */
+ case 114: /* seltablist ::= stl_prefix nm dbnm as on_using */
{
- yymsp[-4].minor.yy493 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-4].minor.yy493,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy5);
+ yymsp[-4].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-4].minor.yy203,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269);
}
break;
- case 114: /* seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
+ case 115: /* seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
{
- yymsp[-5].minor.yy493 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy493,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy5);
- sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy493, &yymsp[-1].minor.yy0);
+ yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy269);
+ sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy203, &yymsp[-1].minor.yy0);
}
break;
- case 115: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
+ case 116: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
{
- yymsp[-7].minor.yy493 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy493,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy5);
- sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy493, yymsp[-3].minor.yy586);
+ yymsp[-7].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy203,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269);
+ sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy203, yymsp[-3].minor.yy14);
}
break;
- case 116: /* seltablist ::= stl_prefix LP select RP as on_using */
+ case 117: /* seltablist ::= stl_prefix LP select RP as on_using */
{
- yymsp[-5].minor.yy493 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy493,0,0,&yymsp[-1].minor.yy0,yymsp[-3].minor.yy136,&yymsp[0].minor.yy5);
+ yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,yymsp[-3].minor.yy555,&yymsp[0].minor.yy269);
}
break;
- case 117: /* seltablist ::= stl_prefix LP seltablist RP as on_using */
+ case 118: /* seltablist ::= stl_prefix LP seltablist RP as on_using */
{
- if( yymsp[-5].minor.yy493==0 && yymsp[-1].minor.yy0.n==0 && yymsp[0].minor.yy5.pOn==0 && yymsp[0].minor.yy5.pUsing==0 ){
- yymsp[-5].minor.yy493 = yymsp[-3].minor.yy493;
- }else if( yymsp[-3].minor.yy493->nSrc==1 ){
- yymsp[-5].minor.yy493 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy493,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy5);
- if( yymsp[-5].minor.yy493 ){
- SrcItem *pNew = &yymsp[-5].minor.yy493->a[yymsp[-5].minor.yy493->nSrc-1];
- SrcItem *pOld = yymsp[-3].minor.yy493->a;
+ if( yymsp[-5].minor.yy203==0 && yymsp[-1].minor.yy0.n==0 && yymsp[0].minor.yy269.pOn==0 && yymsp[0].minor.yy269.pUsing==0 ){
+ yymsp[-5].minor.yy203 = yymsp[-3].minor.yy203;
+ }else if( ALWAYS(yymsp[-3].minor.yy203!=0) && yymsp[-3].minor.yy203->nSrc==1 ){
+ yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269);
+ if( yymsp[-5].minor.yy203 ){
+ SrcItem *pNew = &yymsp[-5].minor.yy203->a[yymsp[-5].minor.yy203->nSrc-1];
+ SrcItem *pOld = yymsp[-3].minor.yy203->a;
pNew->zName = pOld->zName;
pNew->zDatabase = pOld->zDatabase;
pNew->pSelect = pOld->pSelect;
@@ -172274,153 +175949,153 @@ static YYACTIONTYPE yy_reduce(
pOld->zName = pOld->zDatabase = 0;
pOld->pSelect = 0;
}
- sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy493);
+ sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy203);
}else{
Select *pSubquery;
- sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy493);
- pSubquery = sqlite3SelectNew(pParse,0,yymsp[-3].minor.yy493,0,0,0,0,SF_NestedFrom,0);
- yymsp[-5].minor.yy493 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy493,0,0,&yymsp[-1].minor.yy0,pSubquery,&yymsp[0].minor.yy5);
+ sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy203);
+ pSubquery = sqlite3SelectNew(pParse,0,yymsp[-3].minor.yy203,0,0,0,0,SF_NestedFrom,0);
+ yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,pSubquery,&yymsp[0].minor.yy269);
}
}
break;
- case 118: /* dbnm ::= */
- case 133: /* indexed_opt ::= */ yytestcase(yyruleno==133);
+ case 119: /* dbnm ::= */
+ case 134: /* indexed_opt ::= */ yytestcase(yyruleno==134);
{yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;}
break;
- case 120: /* fullname ::= nm */
+ case 121: /* fullname ::= nm */
{
- yylhsminor.yy493 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0);
- if( IN_RENAME_OBJECT && yylhsminor.yy493 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy493->a[0].zName, &yymsp[0].minor.yy0);
+ yylhsminor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0);
+ if( IN_RENAME_OBJECT && yylhsminor.yy203 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[0].minor.yy0);
}
- yymsp[0].minor.yy493 = yylhsminor.yy493;
+ yymsp[0].minor.yy203 = yylhsminor.yy203;
break;
- case 121: /* fullname ::= nm DOT nm */
+ case 122: /* fullname ::= nm DOT nm */
{
- yylhsminor.yy493 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
- if( IN_RENAME_OBJECT && yylhsminor.yy493 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy493->a[0].zName, &yymsp[0].minor.yy0);
+ yylhsminor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
+ if( IN_RENAME_OBJECT && yylhsminor.yy203 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[0].minor.yy0);
}
- yymsp[-2].minor.yy493 = yylhsminor.yy493;
+ yymsp[-2].minor.yy203 = yylhsminor.yy203;
break;
- case 122: /* xfullname ::= nm */
-{yymsp[0].minor.yy493 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/}
+ case 123: /* xfullname ::= nm */
+{yymsp[0].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/}
break;
- case 123: /* xfullname ::= nm DOT nm */
-{yymsp[-2].minor.yy493 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
+ case 124: /* xfullname ::= nm DOT nm */
+{yymsp[-2].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
break;
- case 124: /* xfullname ::= nm DOT nm AS nm */
+ case 125: /* xfullname ::= nm DOT nm AS nm */
{
- yymsp[-4].minor.yy493 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/
- if( yymsp[-4].minor.yy493 ) yymsp[-4].minor.yy493->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
+ yymsp[-4].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/
+ if( yymsp[-4].minor.yy203 ) yymsp[-4].minor.yy203->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
}
break;
- case 125: /* xfullname ::= nm AS nm */
+ case 126: /* xfullname ::= nm AS nm */
{
- yymsp[-2].minor.yy493 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/
- if( yymsp[-2].minor.yy493 ) yymsp[-2].minor.yy493->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
+ yymsp[-2].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/
+ if( yymsp[-2].minor.yy203 ) yymsp[-2].minor.yy203->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
}
break;
- case 126: /* joinop ::= COMMA|JOIN */
-{ yymsp[0].minor.yy436 = JT_INNER; }
+ case 127: /* joinop ::= COMMA|JOIN */
+{ yymsp[0].minor.yy144 = JT_INNER; }
break;
- case 127: /* joinop ::= JOIN_KW JOIN */
-{yymsp[-1].minor.yy436 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/}
+ case 128: /* joinop ::= JOIN_KW JOIN */
+{yymsp[-1].minor.yy144 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/}
break;
- case 128: /* joinop ::= JOIN_KW nm JOIN */
-{yymsp[-2].minor.yy436 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
+ case 129: /* joinop ::= JOIN_KW nm JOIN */
+{yymsp[-2].minor.yy144 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
break;
- case 129: /* joinop ::= JOIN_KW nm nm JOIN */
-{yymsp[-3].minor.yy436 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
+ case 130: /* joinop ::= JOIN_KW nm nm JOIN */
+{yymsp[-3].minor.yy144 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
break;
- case 130: /* on_using ::= ON expr */
-{yymsp[-1].minor.yy5.pOn = yymsp[0].minor.yy224; yymsp[-1].minor.yy5.pUsing = 0;}
+ case 131: /* on_using ::= ON expr */
+{yymsp[-1].minor.yy269.pOn = yymsp[0].minor.yy454; yymsp[-1].minor.yy269.pUsing = 0;}
break;
- case 131: /* on_using ::= USING LP idlist RP */
-{yymsp[-3].minor.yy5.pOn = 0; yymsp[-3].minor.yy5.pUsing = yymsp[-1].minor.yy600;}
+ case 132: /* on_using ::= USING LP idlist RP */
+{yymsp[-3].minor.yy269.pOn = 0; yymsp[-3].minor.yy269.pUsing = yymsp[-1].minor.yy132;}
break;
- case 132: /* on_using ::= */
-{yymsp[1].minor.yy5.pOn = 0; yymsp[1].minor.yy5.pUsing = 0;}
+ case 133: /* on_using ::= */
+{yymsp[1].minor.yy269.pOn = 0; yymsp[1].minor.yy269.pUsing = 0;}
break;
- case 134: /* indexed_by ::= INDEXED BY nm */
+ case 135: /* indexed_by ::= INDEXED BY nm */
{yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;}
break;
- case 135: /* indexed_by ::= NOT INDEXED */
+ case 136: /* indexed_by ::= NOT INDEXED */
{yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;}
break;
- case 137: /* orderby_opt ::= ORDER BY sortlist */
- case 147: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==147);
-{yymsp[-2].minor.yy586 = yymsp[0].minor.yy586;}
+ case 138: /* orderby_opt ::= ORDER BY sortlist */
+ case 148: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==148);
+{yymsp[-2].minor.yy14 = yymsp[0].minor.yy14;}
break;
- case 138: /* sortlist ::= sortlist COMMA expr sortorder nulls */
+ case 139: /* sortlist ::= sortlist COMMA expr sortorder nulls */
{
- yymsp[-4].minor.yy586 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy586,yymsp[-2].minor.yy224);
- sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy586,yymsp[-1].minor.yy436,yymsp[0].minor.yy436);
+ yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14,yymsp[-2].minor.yy454);
+ sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy14,yymsp[-1].minor.yy144,yymsp[0].minor.yy144);
}
break;
- case 139: /* sortlist ::= expr sortorder nulls */
+ case 140: /* sortlist ::= expr sortorder nulls */
{
- yymsp[-2].minor.yy586 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy224); /*A-overwrites-Y*/
- sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy586,yymsp[-1].minor.yy436,yymsp[0].minor.yy436);
+ yymsp[-2].minor.yy14 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy454); /*A-overwrites-Y*/
+ sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy14,yymsp[-1].minor.yy144,yymsp[0].minor.yy144);
}
break;
- case 140: /* sortorder ::= ASC */
-{yymsp[0].minor.yy436 = SQLITE_SO_ASC;}
+ case 141: /* sortorder ::= ASC */
+{yymsp[0].minor.yy144 = SQLITE_SO_ASC;}
break;
- case 141: /* sortorder ::= DESC */
-{yymsp[0].minor.yy436 = SQLITE_SO_DESC;}
+ case 142: /* sortorder ::= DESC */
+{yymsp[0].minor.yy144 = SQLITE_SO_DESC;}
break;
- case 142: /* sortorder ::= */
- case 145: /* nulls ::= */ yytestcase(yyruleno==145);
-{yymsp[1].minor.yy436 = SQLITE_SO_UNDEFINED;}
+ case 143: /* sortorder ::= */
+ case 146: /* nulls ::= */ yytestcase(yyruleno==146);
+{yymsp[1].minor.yy144 = SQLITE_SO_UNDEFINED;}
break;
- case 143: /* nulls ::= NULLS FIRST */
-{yymsp[-1].minor.yy436 = SQLITE_SO_ASC;}
+ case 144: /* nulls ::= NULLS FIRST */
+{yymsp[-1].minor.yy144 = SQLITE_SO_ASC;}
break;
- case 144: /* nulls ::= NULLS LAST */
-{yymsp[-1].minor.yy436 = SQLITE_SO_DESC;}
+ case 145: /* nulls ::= NULLS LAST */
+{yymsp[-1].minor.yy144 = SQLITE_SO_DESC;}
break;
- case 148: /* having_opt ::= */
- case 150: /* limit_opt ::= */ yytestcase(yyruleno==150);
- case 155: /* where_opt ::= */ yytestcase(yyruleno==155);
- case 157: /* where_opt_ret ::= */ yytestcase(yyruleno==157);
- case 233: /* case_else ::= */ yytestcase(yyruleno==233);
- case 235: /* case_operand ::= */ yytestcase(yyruleno==235);
- case 254: /* vinto ::= */ yytestcase(yyruleno==254);
-{yymsp[1].minor.yy224 = 0;}
+ case 149: /* having_opt ::= */
+ case 151: /* limit_opt ::= */ yytestcase(yyruleno==151);
+ case 156: /* where_opt ::= */ yytestcase(yyruleno==156);
+ case 158: /* where_opt_ret ::= */ yytestcase(yyruleno==158);
+ case 235: /* case_else ::= */ yytestcase(yyruleno==235);
+ case 236: /* case_operand ::= */ yytestcase(yyruleno==236);
+ case 255: /* vinto ::= */ yytestcase(yyruleno==255);
+{yymsp[1].minor.yy454 = 0;}
break;
- case 149: /* having_opt ::= HAVING expr */
- case 156: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==156);
- case 158: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==158);
- case 232: /* case_else ::= ELSE expr */ yytestcase(yyruleno==232);
- case 253: /* vinto ::= INTO expr */ yytestcase(yyruleno==253);
-{yymsp[-1].minor.yy224 = yymsp[0].minor.yy224;}
+ case 150: /* having_opt ::= HAVING expr */
+ case 157: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==157);
+ case 159: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==159);
+ case 234: /* case_else ::= ELSE expr */ yytestcase(yyruleno==234);
+ case 254: /* vinto ::= INTO expr */ yytestcase(yyruleno==254);
+{yymsp[-1].minor.yy454 = yymsp[0].minor.yy454;}
break;
- case 151: /* limit_opt ::= LIMIT expr */
-{yymsp[-1].minor.yy224 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy224,0);}
+ case 152: /* limit_opt ::= LIMIT expr */
+{yymsp[-1].minor.yy454 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy454,0);}
break;
- case 152: /* limit_opt ::= LIMIT expr OFFSET expr */
-{yymsp[-3].minor.yy224 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy224,yymsp[0].minor.yy224);}
+ case 153: /* limit_opt ::= LIMIT expr OFFSET expr */
+{yymsp[-3].minor.yy454 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);}
break;
- case 153: /* limit_opt ::= LIMIT expr COMMA expr */
-{yymsp[-3].minor.yy224 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy224,yymsp[-2].minor.yy224);}
+ case 154: /* limit_opt ::= LIMIT expr COMMA expr */
+{yymsp[-3].minor.yy454 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy454,yymsp[-2].minor.yy454);}
break;
- case 154: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
+ case 155: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
{
- sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy493, &yymsp[-1].minor.yy0);
- sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy493,yymsp[0].minor.yy224,0,0);
+ sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy203, &yymsp[-1].minor.yy0);
+ sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy203,yymsp[0].minor.yy454,0,0);
}
break;
- case 159: /* where_opt_ret ::= RETURNING selcollist */
-{sqlite3AddReturning(pParse,yymsp[0].minor.yy586); yymsp[-1].minor.yy224 = 0;}
+ case 160: /* where_opt_ret ::= RETURNING selcollist */
+{sqlite3AddReturning(pParse,yymsp[0].minor.yy14); yymsp[-1].minor.yy454 = 0;}
break;
- case 160: /* where_opt_ret ::= WHERE expr RETURNING selcollist */
-{sqlite3AddReturning(pParse,yymsp[0].minor.yy586); yymsp[-3].minor.yy224 = yymsp[-2].minor.yy224;}
+ case 161: /* where_opt_ret ::= WHERE expr RETURNING selcollist */
+{sqlite3AddReturning(pParse,yymsp[0].minor.yy14); yymsp[-3].minor.yy454 = yymsp[-2].minor.yy454;}
break;
- case 161: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
+ case 162: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
{
- sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy493, &yymsp[-4].minor.yy0);
- sqlite3ExprListCheckLength(pParse,yymsp[-2].minor.yy586,"set list");
- if( yymsp[-1].minor.yy493 ){
- SrcList *pFromClause = yymsp[-1].minor.yy493;
+ sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy203, &yymsp[-4].minor.yy0);
+ sqlite3ExprListCheckLength(pParse,yymsp[-2].minor.yy14,"set list");
+ if( yymsp[-1].minor.yy203 ){
+ SrcList *pFromClause = yymsp[-1].minor.yy203;
if( pFromClause->nSrc>1 ){
Select *pSubquery;
Token as;
@@ -172429,91 +176104,90 @@ static YYACTIONTYPE yy_reduce(
as.z = 0;
pFromClause = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0);
}
- yymsp[-5].minor.yy493 = sqlite3SrcListAppendList(pParse, yymsp[-5].minor.yy493, pFromClause);
+ yymsp[-5].minor.yy203 = sqlite3SrcListAppendList(pParse, yymsp[-5].minor.yy203, pFromClause);
}
- sqlite3Update(pParse,yymsp[-5].minor.yy493,yymsp[-2].minor.yy586,yymsp[0].minor.yy224,yymsp[-6].minor.yy436,0,0,0);
+ sqlite3Update(pParse,yymsp[-5].minor.yy203,yymsp[-2].minor.yy14,yymsp[0].minor.yy454,yymsp[-6].minor.yy144,0,0,0);
}
break;
- case 162: /* setlist ::= setlist COMMA nm EQ expr */
+ case 163: /* setlist ::= setlist COMMA nm EQ expr */
{
- yymsp[-4].minor.yy586 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy586, yymsp[0].minor.yy224);
- sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy586, &yymsp[-2].minor.yy0, 1);
+ yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy14, yymsp[0].minor.yy454);
+ sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy14, &yymsp[-2].minor.yy0, 1);
}
break;
- case 163: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
+ case 164: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
{
- yymsp[-6].minor.yy586 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy586, yymsp[-3].minor.yy600, yymsp[0].minor.yy224);
+ yymsp[-6].minor.yy14 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy14, yymsp[-3].minor.yy132, yymsp[0].minor.yy454);
}
break;
- case 164: /* setlist ::= nm EQ expr */
+ case 165: /* setlist ::= nm EQ expr */
{
- yylhsminor.yy586 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy224);
- sqlite3ExprListSetName(pParse, yylhsminor.yy586, &yymsp[-2].minor.yy0, 1);
+ yylhsminor.yy14 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy454);
+ sqlite3ExprListSetName(pParse, yylhsminor.yy14, &yymsp[-2].minor.yy0, 1);
}
- yymsp[-2].minor.yy586 = yylhsminor.yy586;
+ yymsp[-2].minor.yy14 = yylhsminor.yy14;
break;
- case 165: /* setlist ::= LP idlist RP EQ expr */
+ case 166: /* setlist ::= LP idlist RP EQ expr */
{
- yymsp[-4].minor.yy586 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy600, yymsp[0].minor.yy224);
+ yymsp[-4].minor.yy14 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy132, yymsp[0].minor.yy454);
}
break;
- case 166: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
+ case 167: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
{
- sqlite3Insert(pParse, yymsp[-3].minor.yy493, yymsp[-1].minor.yy136, yymsp[-2].minor.yy600, yymsp[-5].minor.yy436, yymsp[0].minor.yy6);
+ sqlite3Insert(pParse, yymsp[-3].minor.yy203, yymsp[-1].minor.yy555, yymsp[-2].minor.yy132, yymsp[-5].minor.yy144, yymsp[0].minor.yy122);
}
break;
- case 167: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
+ case 168: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
{
- sqlite3Insert(pParse, yymsp[-4].minor.yy493, 0, yymsp[-3].minor.yy600, yymsp[-6].minor.yy436, 0);
+ sqlite3Insert(pParse, yymsp[-4].minor.yy203, 0, yymsp[-3].minor.yy132, yymsp[-6].minor.yy144, 0);
}
break;
- case 168: /* upsert ::= */
-{ yymsp[1].minor.yy6 = 0; }
+ case 169: /* upsert ::= */
+{ yymsp[1].minor.yy122 = 0; }
break;
- case 169: /* upsert ::= RETURNING selcollist */
-{ yymsp[-1].minor.yy6 = 0; sqlite3AddReturning(pParse,yymsp[0].minor.yy586); }
+ case 170: /* upsert ::= RETURNING selcollist */
+{ yymsp[-1].minor.yy122 = 0; sqlite3AddReturning(pParse,yymsp[0].minor.yy14); }
break;
- case 170: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
-{ yymsp[-11].minor.yy6 = sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy586,yymsp[-6].minor.yy224,yymsp[-2].minor.yy586,yymsp[-1].minor.yy224,yymsp[0].minor.yy6);}
+ case 171: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
+{ yymsp[-11].minor.yy122 = sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy14,yymsp[-6].minor.yy454,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454,yymsp[0].minor.yy122);}
break;
- case 171: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
-{ yymsp[-8].minor.yy6 = sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy586,yymsp[-3].minor.yy224,0,0,yymsp[0].minor.yy6); }
+ case 172: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
+{ yymsp[-8].minor.yy122 = sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy14,yymsp[-3].minor.yy454,0,0,yymsp[0].minor.yy122); }
break;
- case 172: /* upsert ::= ON CONFLICT DO NOTHING returning */
-{ yymsp[-4].minor.yy6 = sqlite3UpsertNew(pParse->db,0,0,0,0,0); }
+ case 173: /* upsert ::= ON CONFLICT DO NOTHING returning */
+{ yymsp[-4].minor.yy122 = sqlite3UpsertNew(pParse->db,0,0,0,0,0); }
break;
- case 173: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
-{ yymsp[-7].minor.yy6 = sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy586,yymsp[-1].minor.yy224,0);}
+ case 174: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
+{ yymsp[-7].minor.yy122 = sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454,0);}
break;
- case 174: /* returning ::= RETURNING selcollist */
-{sqlite3AddReturning(pParse,yymsp[0].minor.yy586);}
+ case 175: /* returning ::= RETURNING selcollist */
+{sqlite3AddReturning(pParse,yymsp[0].minor.yy14);}
break;
- case 177: /* idlist_opt ::= */
-{yymsp[1].minor.yy600 = 0;}
+ case 178: /* idlist_opt ::= */
+{yymsp[1].minor.yy132 = 0;}
break;
- case 178: /* idlist_opt ::= LP idlist RP */
-{yymsp[-2].minor.yy600 = yymsp[-1].minor.yy600;}
+ case 179: /* idlist_opt ::= LP idlist RP */
+{yymsp[-2].minor.yy132 = yymsp[-1].minor.yy132;}
break;
- case 179: /* idlist ::= idlist COMMA nm */
-{yymsp[-2].minor.yy600 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy600,&yymsp[0].minor.yy0);}
+ case 180: /* idlist ::= idlist COMMA nm */
+{yymsp[-2].minor.yy132 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy132,&yymsp[0].minor.yy0);}
break;
- case 180: /* idlist ::= nm */
-{yymsp[0].minor.yy600 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
+ case 181: /* idlist ::= nm */
+{yymsp[0].minor.yy132 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
break;
- case 181: /* expr ::= LP expr RP */
-{yymsp[-2].minor.yy224 = yymsp[-1].minor.yy224;}
+ case 182: /* expr ::= LP expr RP */
+{yymsp[-2].minor.yy454 = yymsp[-1].minor.yy454;}
break;
- case 182: /* expr ::= ID|INDEXED */
- case 183: /* expr ::= JOIN_KW */ yytestcase(yyruleno==183);
-{yymsp[0].minor.yy224=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
+ case 183: /* expr ::= ID|INDEXED|JOIN_KW */
+{yymsp[0].minor.yy454=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
break;
case 184: /* expr ::= nm DOT nm */
{
Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0);
Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0);
- yylhsminor.yy224 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
+ yylhsminor.yy454 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
}
- yymsp[-2].minor.yy224 = yylhsminor.yy224;
+ yymsp[-2].minor.yy454 = yylhsminor.yy454;
break;
case 185: /* expr ::= nm DOT nm DOT nm */
{
@@ -172524,27 +176198,27 @@ static YYACTIONTYPE yy_reduce(
if( IN_RENAME_OBJECT ){
sqlite3RenameTokenRemap(pParse, 0, temp1);
}
- yylhsminor.yy224 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
+ yylhsminor.yy454 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
}
- yymsp[-4].minor.yy224 = yylhsminor.yy224;
+ yymsp[-4].minor.yy454 = yylhsminor.yy454;
break;
case 186: /* term ::= NULL|FLOAT|BLOB */
case 187: /* term ::= STRING */ yytestcase(yyruleno==187);
-{yymsp[0].minor.yy224=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
+{yymsp[0].minor.yy454=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
break;
case 188: /* term ::= INTEGER */
{
- yylhsminor.yy224 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
- if( yylhsminor.yy224 ) yylhsminor.yy224->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail);
+ yylhsminor.yy454 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
+ if( yylhsminor.yy454 ) yylhsminor.yy454->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail);
}
- yymsp[0].minor.yy224 = yylhsminor.yy224;
+ yymsp[0].minor.yy454 = yylhsminor.yy454;
break;
case 189: /* expr ::= VARIABLE */
{
if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){
u32 n = yymsp[0].minor.yy0.n;
- yymsp[0].minor.yy224 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0);
- sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy224, n);
+ yymsp[0].minor.yy454 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0);
+ sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy454, n);
}else{
/* When doing a nested parse, one can include terms in an expression
** that look like this: #1 #2 ... These terms refer to registers
@@ -172553,179 +176227,194 @@ static YYACTIONTYPE yy_reduce(
assert( t.n>=2 );
if( pParse->nested==0 ){
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
- yymsp[0].minor.yy224 = 0;
+ yymsp[0].minor.yy454 = 0;
}else{
- yymsp[0].minor.yy224 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
- if( yymsp[0].minor.yy224 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy224->iTable);
+ yymsp[0].minor.yy454 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
+ if( yymsp[0].minor.yy454 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy454->iTable);
}
}
}
break;
case 190: /* expr ::= expr COLLATE ID|STRING */
{
- yymsp[-2].minor.yy224 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy224, &yymsp[0].minor.yy0, 1);
+ yymsp[-2].minor.yy454 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy454, &yymsp[0].minor.yy0, 1);
}
break;
case 191: /* expr ::= CAST LP expr AS typetoken RP */
{
- yymsp[-5].minor.yy224 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
- sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy224, yymsp[-3].minor.yy224, 0);
+ yymsp[-5].minor.yy454 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
+ sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy454, yymsp[-3].minor.yy454, 0);
+}
+ break;
+ case 192: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */
+{
+ yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy14, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy144);
}
+ yymsp[-4].minor.yy454 = yylhsminor.yy454;
break;
- case 192: /* expr ::= ID|INDEXED LP distinct exprlist RP */
+ case 193: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */
{
- yylhsminor.yy224 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy586, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy436);
+ yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-4].minor.yy14, &yymsp[-7].minor.yy0, yymsp[-5].minor.yy144);
+ sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy454, yymsp[-1].minor.yy14);
}
- yymsp[-4].minor.yy224 = yylhsminor.yy224;
+ yymsp[-7].minor.yy454 = yylhsminor.yy454;
break;
- case 193: /* expr ::= ID|INDEXED LP STAR RP */
+ case 194: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP */
{
- yylhsminor.yy224 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0);
+ yylhsminor.yy454 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0);
}
- yymsp[-3].minor.yy224 = yylhsminor.yy224;
+ yymsp[-3].minor.yy454 = yylhsminor.yy454;
break;
- case 194: /* expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
+ case 195: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */
{
- yylhsminor.yy224 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy586, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy436);
- sqlite3WindowAttach(pParse, yylhsminor.yy224, yymsp[0].minor.yy591);
+ yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy14, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy144);
+ sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211);
}
- yymsp[-5].minor.yy224 = yylhsminor.yy224;
+ yymsp[-5].minor.yy454 = yylhsminor.yy454;
break;
- case 195: /* expr ::= ID|INDEXED LP STAR RP filter_over */
+ case 196: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */
{
- yylhsminor.yy224 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0);
- sqlite3WindowAttach(pParse, yylhsminor.yy224, yymsp[0].minor.yy591);
+ yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-5].minor.yy14, &yymsp[-8].minor.yy0, yymsp[-6].minor.yy144);
+ sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211);
+ sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy454, yymsp[-2].minor.yy14);
}
- yymsp[-4].minor.yy224 = yylhsminor.yy224;
+ yymsp[-8].minor.yy454 = yylhsminor.yy454;
break;
- case 196: /* term ::= CTIME_KW */
+ case 197: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */
{
- yylhsminor.yy224 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0);
+ yylhsminor.yy454 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0);
+ sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211);
}
- yymsp[0].minor.yy224 = yylhsminor.yy224;
+ yymsp[-4].minor.yy454 = yylhsminor.yy454;
break;
- case 197: /* expr ::= LP nexprlist COMMA expr RP */
+ case 198: /* term ::= CTIME_KW */
{
- ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy586, yymsp[-1].minor.yy224);
- yymsp[-4].minor.yy224 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
- if( yymsp[-4].minor.yy224 ){
- yymsp[-4].minor.yy224->x.pList = pList;
+ yylhsminor.yy454 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0);
+}
+ yymsp[0].minor.yy454 = yylhsminor.yy454;
+ break;
+ case 199: /* expr ::= LP nexprlist COMMA expr RP */
+{
+ ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy14, yymsp[-1].minor.yy454);
+ yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
+ if( yymsp[-4].minor.yy454 ){
+ yymsp[-4].minor.yy454->x.pList = pList;
if( ALWAYS(pList->nExpr) ){
- yymsp[-4].minor.yy224->flags |= pList->a[0].pExpr->flags & EP_Propagate;
+ yymsp[-4].minor.yy454->flags |= pList->a[0].pExpr->flags & EP_Propagate;
}
}else{
sqlite3ExprListDelete(pParse->db, pList);
}
}
break;
- case 198: /* expr ::= expr AND expr */
-{yymsp[-2].minor.yy224=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy224,yymsp[0].minor.yy224);}
+ case 200: /* expr ::= expr AND expr */
+{yymsp[-2].minor.yy454=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);}
break;
- case 199: /* expr ::= expr OR expr */
- case 200: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==200);
- case 201: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==201);
- case 202: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==202);
- case 203: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==203);
- case 204: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==204);
- case 205: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==205);
-{yymsp[-2].minor.yy224=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy224,yymsp[0].minor.yy224);}
+ case 201: /* expr ::= expr OR expr */
+ case 202: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==202);
+ case 203: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==203);
+ case 204: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==204);
+ case 205: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==205);
+ case 206: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==206);
+ case 207: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==207);
+{yymsp[-2].minor.yy454=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);}
break;
- case 206: /* likeop ::= NOT LIKE_KW|MATCH */
+ case 208: /* likeop ::= NOT LIKE_KW|MATCH */
{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/}
break;
- case 207: /* expr ::= expr likeop expr */
+ case 209: /* expr ::= expr likeop expr */
{
ExprList *pList;
int bNot = yymsp[-1].minor.yy0.n & 0x80000000;
yymsp[-1].minor.yy0.n &= 0x7fffffff;
- pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy224);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy224);
- yymsp[-2].minor.yy224 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
- if( bNot ) yymsp[-2].minor.yy224 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy224, 0);
- if( yymsp[-2].minor.yy224 ) yymsp[-2].minor.yy224->flags |= EP_InfixFunc;
+ pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy454);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy454);
+ yymsp[-2].minor.yy454 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
+ if( bNot ) yymsp[-2].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy454, 0);
+ if( yymsp[-2].minor.yy454 ) yymsp[-2].minor.yy454->flags |= EP_InfixFunc;
}
break;
- case 208: /* expr ::= expr likeop expr ESCAPE expr */
+ case 210: /* expr ::= expr likeop expr ESCAPE expr */
{
ExprList *pList;
int bNot = yymsp[-3].minor.yy0.n & 0x80000000;
yymsp[-3].minor.yy0.n &= 0x7fffffff;
- pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy224);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy224);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy224);
- yymsp[-4].minor.yy224 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0);
- if( bNot ) yymsp[-4].minor.yy224 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy224, 0);
- if( yymsp[-4].minor.yy224 ) yymsp[-4].minor.yy224->flags |= EP_InfixFunc;
+ pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy454);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy454);
+ yymsp[-4].minor.yy454 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0);
+ if( bNot ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
+ if( yymsp[-4].minor.yy454 ) yymsp[-4].minor.yy454->flags |= EP_InfixFunc;
}
break;
- case 209: /* expr ::= expr ISNULL|NOTNULL */
-{yymsp[-1].minor.yy224 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy224,0);}
+ case 211: /* expr ::= expr ISNULL|NOTNULL */
+{yymsp[-1].minor.yy454 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy454,0);}
break;
- case 210: /* expr ::= expr NOT NULL */
-{yymsp[-2].minor.yy224 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy224,0);}
+ case 212: /* expr ::= expr NOT NULL */
+{yymsp[-2].minor.yy454 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy454,0);}
break;
- case 211: /* expr ::= expr IS expr */
+ case 213: /* expr ::= expr IS expr */
{
- yymsp[-2].minor.yy224 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy224,yymsp[0].minor.yy224);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy224, yymsp[-2].minor.yy224, TK_ISNULL);
+ yymsp[-2].minor.yy454 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-2].minor.yy454, TK_ISNULL);
}
break;
- case 212: /* expr ::= expr IS NOT expr */
+ case 214: /* expr ::= expr IS NOT expr */
{
- yymsp[-3].minor.yy224 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy224,yymsp[0].minor.yy224);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy224, yymsp[-3].minor.yy224, TK_NOTNULL);
+ yymsp[-3].minor.yy454 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy454,yymsp[0].minor.yy454);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-3].minor.yy454, TK_NOTNULL);
}
break;
- case 213: /* expr ::= expr IS NOT DISTINCT FROM expr */
+ case 215: /* expr ::= expr IS NOT DISTINCT FROM expr */
{
- yymsp[-5].minor.yy224 = sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy224,yymsp[0].minor.yy224);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy224, yymsp[-5].minor.yy224, TK_ISNULL);
+ yymsp[-5].minor.yy454 = sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy454,yymsp[0].minor.yy454);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-5].minor.yy454, TK_ISNULL);
}
break;
- case 214: /* expr ::= expr IS DISTINCT FROM expr */
+ case 216: /* expr ::= expr IS DISTINCT FROM expr */
{
- yymsp[-4].minor.yy224 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy224,yymsp[0].minor.yy224);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy224, yymsp[-4].minor.yy224, TK_NOTNULL);
+ yymsp[-4].minor.yy454 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy454,yymsp[0].minor.yy454);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-4].minor.yy454, TK_NOTNULL);
}
break;
- case 215: /* expr ::= NOT expr */
- case 216: /* expr ::= BITNOT expr */ yytestcase(yyruleno==216);
-{yymsp[-1].minor.yy224 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy224, 0);/*A-overwrites-B*/}
+ case 217: /* expr ::= NOT expr */
+ case 218: /* expr ::= BITNOT expr */ yytestcase(yyruleno==218);
+{yymsp[-1].minor.yy454 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy454, 0);/*A-overwrites-B*/}
break;
- case 217: /* expr ::= PLUS|MINUS expr */
+ case 219: /* expr ::= PLUS|MINUS expr */
{
- yymsp[-1].minor.yy224 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy224, 0);
+ yymsp[-1].minor.yy454 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy454, 0);
/*A-overwrites-B*/
}
break;
- case 218: /* expr ::= expr PTR expr */
+ case 220: /* expr ::= expr PTR expr */
{
- ExprList *pList = sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy224);
- pList = sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy224);
- yylhsminor.yy224 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
+ ExprList *pList = sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy454);
+ pList = sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy454);
+ yylhsminor.yy454 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
}
- yymsp[-2].minor.yy224 = yylhsminor.yy224;
+ yymsp[-2].minor.yy454 = yylhsminor.yy454;
break;
- case 219: /* between_op ::= BETWEEN */
- case 222: /* in_op ::= IN */ yytestcase(yyruleno==222);
-{yymsp[0].minor.yy436 = 0;}
+ case 221: /* between_op ::= BETWEEN */
+ case 224: /* in_op ::= IN */ yytestcase(yyruleno==224);
+{yymsp[0].minor.yy144 = 0;}
break;
- case 221: /* expr ::= expr between_op expr AND expr */
+ case 223: /* expr ::= expr between_op expr AND expr */
{
- ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy224);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy224);
- yymsp[-4].minor.yy224 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy224, 0);
- if( yymsp[-4].minor.yy224 ){
- yymsp[-4].minor.yy224->x.pList = pList;
+ ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy454);
+ yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy454, 0);
+ if( yymsp[-4].minor.yy454 ){
+ yymsp[-4].minor.yy454->x.pList = pList;
}else{
sqlite3ExprListDelete(pParse->db, pList);
}
- if( yymsp[-3].minor.yy436 ) yymsp[-4].minor.yy224 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy224, 0);
+ if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
}
break;
- case 224: /* expr ::= expr in_op LP exprlist RP */
+ case 226: /* expr ::= expr in_op LP exprlist RP */
{
- if( yymsp[-1].minor.yy586==0 ){
+ if( yymsp[-1].minor.yy14==0 ){
/* Expressions of the form
**
** expr1 IN ()
@@ -172734,211 +176423,208 @@ static YYACTIONTYPE yy_reduce(
** simplify to constants 0 (false) and 1 (true), respectively,
** regardless of the value of expr1.
*/
- sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy224);
- yymsp[-4].minor.yy224 = sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy436 ? "true" : "false");
- if( yymsp[-4].minor.yy224 ) sqlite3ExprIdToTrueFalse(yymsp[-4].minor.yy224);
- }else{
- Expr *pRHS = yymsp[-1].minor.yy586->a[0].pExpr;
- if( yymsp[-1].minor.yy586->nExpr==1 && sqlite3ExprIsConstant(pRHS) && yymsp[-4].minor.yy224->op!=TK_VECTOR ){
- yymsp[-1].minor.yy586->a[0].pExpr = 0;
- sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy586);
+ sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy454);
+ yymsp[-4].minor.yy454 = sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy144 ? "true" : "false");
+ if( yymsp[-4].minor.yy454 ) sqlite3ExprIdToTrueFalse(yymsp[-4].minor.yy454);
+ }else{
+ Expr *pRHS = yymsp[-1].minor.yy14->a[0].pExpr;
+ if( yymsp[-1].minor.yy14->nExpr==1 && sqlite3ExprIsConstant(pRHS) && yymsp[-4].minor.yy454->op!=TK_VECTOR ){
+ yymsp[-1].minor.yy14->a[0].pExpr = 0;
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0);
- yymsp[-4].minor.yy224 = sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy224, pRHS);
- }else if( yymsp[-1].minor.yy586->nExpr==1 && pRHS->op==TK_SELECT ){
- yymsp[-4].minor.yy224 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy224, 0);
- sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy224, pRHS->x.pSelect);
+ yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy454, pRHS);
+ }else if( yymsp[-1].minor.yy14->nExpr==1 && pRHS->op==TK_SELECT ){
+ yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0);
+ sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pRHS->x.pSelect);
pRHS->x.pSelect = 0;
- sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy586);
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
}else{
- yymsp[-4].minor.yy224 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy224, 0);
- if( yymsp[-4].minor.yy224==0 ){
- sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy586);
- }else if( yymsp[-4].minor.yy224->pLeft->op==TK_VECTOR ){
- int nExpr = yymsp[-4].minor.yy224->pLeft->x.pList->nExpr;
- Select *pSelectRHS = sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy586);
+ yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0);
+ if( yymsp[-4].minor.yy454==0 ){
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
+ }else if( yymsp[-4].minor.yy454->pLeft->op==TK_VECTOR ){
+ int nExpr = yymsp[-4].minor.yy454->pLeft->x.pList->nExpr;
+ Select *pSelectRHS = sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy14);
if( pSelectRHS ){
parserDoubleLinkSelect(pParse, pSelectRHS);
- sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy224, pSelectRHS);
+ sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pSelectRHS);
}
}else{
- yymsp[-4].minor.yy224->x.pList = yymsp[-1].minor.yy586;
- sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy224);
+ yymsp[-4].minor.yy454->x.pList = yymsp[-1].minor.yy14;
+ sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy454);
}
}
- if( yymsp[-3].minor.yy436 ) yymsp[-4].minor.yy224 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy224, 0);
+ if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
}
}
break;
- case 225: /* expr ::= LP select RP */
+ case 227: /* expr ::= LP select RP */
{
- yymsp[-2].minor.yy224 = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
- sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy224, yymsp[-1].minor.yy136);
+ yymsp[-2].minor.yy454 = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
+ sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy454, yymsp[-1].minor.yy555);
}
break;
- case 226: /* expr ::= expr in_op LP select RP */
+ case 228: /* expr ::= expr in_op LP select RP */
{
- yymsp[-4].minor.yy224 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy224, 0);
- sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy224, yymsp[-1].minor.yy136);
- if( yymsp[-3].minor.yy436 ) yymsp[-4].minor.yy224 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy224, 0);
+ yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0);
+ sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, yymsp[-1].minor.yy555);
+ if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
}
break;
- case 227: /* expr ::= expr in_op nm dbnm paren_exprlist */
+ case 229: /* expr ::= expr in_op nm dbnm paren_exprlist */
{
SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);
Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0);
- if( yymsp[0].minor.yy586 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy586);
- yymsp[-4].minor.yy224 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy224, 0);
- sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy224, pSelect);
- if( yymsp[-3].minor.yy436 ) yymsp[-4].minor.yy224 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy224, 0);
+ if( yymsp[0].minor.yy14 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy14);
+ yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0);
+ sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pSelect);
+ if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
}
break;
- case 228: /* expr ::= EXISTS LP select RP */
+ case 230: /* expr ::= EXISTS LP select RP */
{
Expr *p;
- p = yymsp[-3].minor.yy224 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
- sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy136);
+ p = yymsp[-3].minor.yy454 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
+ sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy555);
}
break;
- case 229: /* expr ::= CASE case_operand case_exprlist case_else END */
+ case 231: /* expr ::= CASE case_operand case_exprlist case_else END */
{
- yymsp[-4].minor.yy224 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy224, 0);
- if( yymsp[-4].minor.yy224 ){
- yymsp[-4].minor.yy224->x.pList = yymsp[-1].minor.yy224 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy586,yymsp[-1].minor.yy224) : yymsp[-2].minor.yy586;
- sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy224);
+ yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy454, 0);
+ if( yymsp[-4].minor.yy454 ){
+ yymsp[-4].minor.yy454->x.pList = yymsp[-1].minor.yy454 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454) : yymsp[-2].minor.yy14;
+ sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy454);
}else{
- sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy586);
- sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy224);
+ sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy14);
+ sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy454);
}
}
break;
- case 230: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ case 232: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
{
- yymsp[-4].minor.yy586 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy586, yymsp[-2].minor.yy224);
- yymsp[-4].minor.yy586 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy586, yymsp[0].minor.yy224);
+ yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, yymsp[-2].minor.yy454);
+ yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, yymsp[0].minor.yy454);
}
break;
- case 231: /* case_exprlist ::= WHEN expr THEN expr */
+ case 233: /* case_exprlist ::= WHEN expr THEN expr */
{
- yymsp[-3].minor.yy586 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy224);
- yymsp[-3].minor.yy586 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy586, yymsp[0].minor.yy224);
+ yymsp[-3].minor.yy14 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454);
+ yymsp[-3].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy14, yymsp[0].minor.yy454);
}
break;
- case 234: /* case_operand ::= expr */
-{yymsp[0].minor.yy224 = yymsp[0].minor.yy224; /*A-overwrites-X*/}
+ case 238: /* nexprlist ::= nexprlist COMMA expr */
+{yymsp[-2].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[0].minor.yy454);}
break;
- case 237: /* nexprlist ::= nexprlist COMMA expr */
-{yymsp[-2].minor.yy586 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy586,yymsp[0].minor.yy224);}
+ case 239: /* nexprlist ::= expr */
+{yymsp[0].minor.yy14 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy454); /*A-overwrites-Y*/}
break;
- case 238: /* nexprlist ::= expr */
-{yymsp[0].minor.yy586 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy224); /*A-overwrites-Y*/}
+ case 241: /* paren_exprlist ::= LP exprlist RP */
+ case 246: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==246);
+{yymsp[-2].minor.yy14 = yymsp[-1].minor.yy14;}
break;
- case 240: /* paren_exprlist ::= LP exprlist RP */
- case 245: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==245);
-{yymsp[-2].minor.yy586 = yymsp[-1].minor.yy586;}
- break;
- case 241: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+ case 242: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
{
sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0,
- sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy586, yymsp[-10].minor.yy436,
- &yymsp[-11].minor.yy0, yymsp[0].minor.yy224, SQLITE_SO_ASC, yymsp[-8].minor.yy436, SQLITE_IDXTYPE_APPDEF);
+ sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy14, yymsp[-10].minor.yy144,
+ &yymsp[-11].minor.yy0, yymsp[0].minor.yy454, SQLITE_SO_ASC, yymsp[-8].minor.yy144, SQLITE_IDXTYPE_APPDEF);
if( IN_RENAME_OBJECT && pParse->pNewIndex ){
sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &yymsp[-4].minor.yy0);
}
}
break;
- case 242: /* uniqueflag ::= UNIQUE */
- case 284: /* raisetype ::= ABORT */ yytestcase(yyruleno==284);
-{yymsp[0].minor.yy436 = OE_Abort;}
+ case 243: /* uniqueflag ::= UNIQUE */
+ case 285: /* raisetype ::= ABORT */ yytestcase(yyruleno==285);
+{yymsp[0].minor.yy144 = OE_Abort;}
break;
- case 243: /* uniqueflag ::= */
-{yymsp[1].minor.yy436 = OE_None;}
+ case 244: /* uniqueflag ::= */
+{yymsp[1].minor.yy144 = OE_None;}
break;
- case 246: /* eidlist ::= eidlist COMMA nm collate sortorder */
+ case 247: /* eidlist ::= eidlist COMMA nm collate sortorder */
{
- yymsp[-4].minor.yy586 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy586, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy436, yymsp[0].minor.yy436);
+ yymsp[-4].minor.yy14 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy14, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy144, yymsp[0].minor.yy144);
}
break;
- case 247: /* eidlist ::= nm collate sortorder */
+ case 248: /* eidlist ::= nm collate sortorder */
{
- yymsp[-2].minor.yy586 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy436, yymsp[0].minor.yy436); /*A-overwrites-Y*/
+ yymsp[-2].minor.yy14 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy144, yymsp[0].minor.yy144); /*A-overwrites-Y*/
}
break;
- case 250: /* cmd ::= DROP INDEX ifexists fullname */
-{sqlite3DropIndex(pParse, yymsp[0].minor.yy493, yymsp[-1].minor.yy436);}
+ case 251: /* cmd ::= DROP INDEX ifexists fullname */
+{sqlite3DropIndex(pParse, yymsp[0].minor.yy203, yymsp[-1].minor.yy144);}
break;
- case 251: /* cmd ::= VACUUM vinto */
-{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy224);}
+ case 252: /* cmd ::= VACUUM vinto */
+{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy454);}
break;
- case 252: /* cmd ::= VACUUM nm vinto */
-{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy224);}
+ case 253: /* cmd ::= VACUUM nm vinto */
+{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy454);}
break;
- case 255: /* cmd ::= PRAGMA nm dbnm */
+ case 256: /* cmd ::= PRAGMA nm dbnm */
{sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);}
break;
- case 256: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
+ case 257: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);}
break;
- case 257: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ case 258: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);}
break;
- case 258: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
+ case 259: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);}
break;
- case 259: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ case 260: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);}
break;
- case 262: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ case 263: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
{
Token all;
all.z = yymsp[-3].minor.yy0.z;
all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n;
- sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy137, &all);
+ sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy427, &all);
}
break;
- case 263: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ case 264: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
{
- sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy436, yymsp[-4].minor.yy510.a, yymsp[-4].minor.yy510.b, yymsp[-2].minor.yy493, yymsp[0].minor.yy224, yymsp[-10].minor.yy436, yymsp[-8].minor.yy436);
+ sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy144, yymsp[-4].minor.yy286.a, yymsp[-4].minor.yy286.b, yymsp[-2].minor.yy203, yymsp[0].minor.yy454, yymsp[-10].minor.yy144, yymsp[-8].minor.yy144);
yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/
}
break;
- case 264: /* trigger_time ::= BEFORE|AFTER */
-{ yymsp[0].minor.yy436 = yymsp[0].major; /*A-overwrites-X*/ }
+ case 265: /* trigger_time ::= BEFORE|AFTER */
+{ yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-X*/ }
break;
- case 265: /* trigger_time ::= INSTEAD OF */
-{ yymsp[-1].minor.yy436 = TK_INSTEAD;}
+ case 266: /* trigger_time ::= INSTEAD OF */
+{ yymsp[-1].minor.yy144 = TK_INSTEAD;}
break;
- case 266: /* trigger_time ::= */
-{ yymsp[1].minor.yy436 = TK_BEFORE; }
+ case 267: /* trigger_time ::= */
+{ yymsp[1].minor.yy144 = TK_BEFORE; }
break;
- case 267: /* trigger_event ::= DELETE|INSERT */
- case 268: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==268);
-{yymsp[0].minor.yy510.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy510.b = 0;}
+ case 268: /* trigger_event ::= DELETE|INSERT */
+ case 269: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==269);
+{yymsp[0].minor.yy286.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy286.b = 0;}
break;
- case 269: /* trigger_event ::= UPDATE OF idlist */
-{yymsp[-2].minor.yy510.a = TK_UPDATE; yymsp[-2].minor.yy510.b = yymsp[0].minor.yy600;}
+ case 270: /* trigger_event ::= UPDATE OF idlist */
+{yymsp[-2].minor.yy286.a = TK_UPDATE; yymsp[-2].minor.yy286.b = yymsp[0].minor.yy132;}
break;
- case 270: /* when_clause ::= */
- case 289: /* key_opt ::= */ yytestcase(yyruleno==289);
-{ yymsp[1].minor.yy224 = 0; }
+ case 271: /* when_clause ::= */
+ case 290: /* key_opt ::= */ yytestcase(yyruleno==290);
+{ yymsp[1].minor.yy454 = 0; }
break;
- case 271: /* when_clause ::= WHEN expr */
- case 290: /* key_opt ::= KEY expr */ yytestcase(yyruleno==290);
-{ yymsp[-1].minor.yy224 = yymsp[0].minor.yy224; }
+ case 272: /* when_clause ::= WHEN expr */
+ case 291: /* key_opt ::= KEY expr */ yytestcase(yyruleno==291);
+{ yymsp[-1].minor.yy454 = yymsp[0].minor.yy454; }
break;
- case 272: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ case 273: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
{
- assert( yymsp[-2].minor.yy137!=0 );
- yymsp[-2].minor.yy137->pLast->pNext = yymsp[-1].minor.yy137;
- yymsp[-2].minor.yy137->pLast = yymsp[-1].minor.yy137;
+ assert( yymsp[-2].minor.yy427!=0 );
+ yymsp[-2].minor.yy427->pLast->pNext = yymsp[-1].minor.yy427;
+ yymsp[-2].minor.yy427->pLast = yymsp[-1].minor.yy427;
}
break;
- case 273: /* trigger_cmd_list ::= trigger_cmd SEMI */
+ case 274: /* trigger_cmd_list ::= trigger_cmd SEMI */
{
- assert( yymsp[-1].minor.yy137!=0 );
- yymsp[-1].minor.yy137->pLast = yymsp[-1].minor.yy137;
+ assert( yymsp[-1].minor.yy427!=0 );
+ yymsp[-1].minor.yy427->pLast = yymsp[-1].minor.yy427;
}
break;
- case 274: /* trnm ::= nm DOT nm */
+ case 275: /* trnm ::= nm DOT nm */
{
yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;
sqlite3ErrorMsg(pParse,
@@ -172946,305 +176632,305 @@ static YYACTIONTYPE yy_reduce(
"statements within triggers");
}
break;
- case 275: /* tridxby ::= INDEXED BY nm */
+ case 276: /* tridxby ::= INDEXED BY nm */
{
sqlite3ErrorMsg(pParse,
"the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
- case 276: /* tridxby ::= NOT INDEXED */
+ case 277: /* tridxby ::= NOT INDEXED */
{
sqlite3ErrorMsg(pParse,
"the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
- case 277: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
-{yylhsminor.yy137 = sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy493, yymsp[-3].minor.yy586, yymsp[-1].minor.yy224, yymsp[-7].minor.yy436, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy594);}
- yymsp[-8].minor.yy137 = yylhsminor.yy137;
+ case 278: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
+{yylhsminor.yy427 = sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy203, yymsp[-3].minor.yy14, yymsp[-1].minor.yy454, yymsp[-7].minor.yy144, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy168);}
+ yymsp[-8].minor.yy427 = yylhsminor.yy427;
break;
- case 278: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
+ case 279: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
{
- yylhsminor.yy137 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy600,yymsp[-2].minor.yy136,yymsp[-6].minor.yy436,yymsp[-1].minor.yy6,yymsp[-7].minor.yy594,yymsp[0].minor.yy594);/*yylhsminor.yy137-overwrites-yymsp[-6].minor.yy436*/
+ yylhsminor.yy427 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy132,yymsp[-2].minor.yy555,yymsp[-6].minor.yy144,yymsp[-1].minor.yy122,yymsp[-7].minor.yy168,yymsp[0].minor.yy168);/*yylhsminor.yy427-overwrites-yymsp[-6].minor.yy144*/
}
- yymsp[-7].minor.yy137 = yylhsminor.yy137;
+ yymsp[-7].minor.yy427 = yylhsminor.yy427;
break;
- case 279: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
-{yylhsminor.yy137 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy224, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy594);}
- yymsp[-5].minor.yy137 = yylhsminor.yy137;
+ case 280: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
+{yylhsminor.yy427 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy454, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy168);}
+ yymsp[-5].minor.yy427 = yylhsminor.yy427;
break;
- case 280: /* trigger_cmd ::= scanpt select scanpt */
-{yylhsminor.yy137 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy136, yymsp[-2].minor.yy594, yymsp[0].minor.yy594); /*yylhsminor.yy137-overwrites-yymsp[-1].minor.yy136*/}
- yymsp[-2].minor.yy137 = yylhsminor.yy137;
+ case 281: /* trigger_cmd ::= scanpt select scanpt */
+{yylhsminor.yy427 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy555, yymsp[-2].minor.yy168, yymsp[0].minor.yy168); /*yylhsminor.yy427-overwrites-yymsp[-1].minor.yy555*/}
+ yymsp[-2].minor.yy427 = yylhsminor.yy427;
break;
- case 281: /* expr ::= RAISE LP IGNORE RP */
+ case 282: /* expr ::= RAISE LP IGNORE RP */
{
- yymsp[-3].minor.yy224 = sqlite3PExpr(pParse, TK_RAISE, 0, 0);
- if( yymsp[-3].minor.yy224 ){
- yymsp[-3].minor.yy224->affExpr = OE_Ignore;
+ yymsp[-3].minor.yy454 = sqlite3PExpr(pParse, TK_RAISE, 0, 0);
+ if( yymsp[-3].minor.yy454 ){
+ yymsp[-3].minor.yy454->affExpr = OE_Ignore;
}
}
break;
- case 282: /* expr ::= RAISE LP raisetype COMMA nm RP */
+ case 283: /* expr ::= RAISE LP raisetype COMMA nm RP */
{
- yymsp[-5].minor.yy224 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1);
- if( yymsp[-5].minor.yy224 ) {
- yymsp[-5].minor.yy224->affExpr = (char)yymsp[-3].minor.yy436;
+ yymsp[-5].minor.yy454 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1);
+ if( yymsp[-5].minor.yy454 ) {
+ yymsp[-5].minor.yy454->affExpr = (char)yymsp[-3].minor.yy144;
}
}
break;
- case 283: /* raisetype ::= ROLLBACK */
-{yymsp[0].minor.yy436 = OE_Rollback;}
+ case 284: /* raisetype ::= ROLLBACK */
+{yymsp[0].minor.yy144 = OE_Rollback;}
break;
- case 285: /* raisetype ::= FAIL */
-{yymsp[0].minor.yy436 = OE_Fail;}
+ case 286: /* raisetype ::= FAIL */
+{yymsp[0].minor.yy144 = OE_Fail;}
break;
- case 286: /* cmd ::= DROP TRIGGER ifexists fullname */
+ case 287: /* cmd ::= DROP TRIGGER ifexists fullname */
{
- sqlite3DropTrigger(pParse,yymsp[0].minor.yy493,yymsp[-1].minor.yy436);
+ sqlite3DropTrigger(pParse,yymsp[0].minor.yy203,yymsp[-1].minor.yy144);
}
break;
- case 287: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ case 288: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
{
- sqlite3Attach(pParse, yymsp[-3].minor.yy224, yymsp[-1].minor.yy224, yymsp[0].minor.yy224);
+ sqlite3Attach(pParse, yymsp[-3].minor.yy454, yymsp[-1].minor.yy454, yymsp[0].minor.yy454);
}
break;
- case 288: /* cmd ::= DETACH database_kw_opt expr */
+ case 289: /* cmd ::= DETACH database_kw_opt expr */
{
- sqlite3Detach(pParse, yymsp[0].minor.yy224);
+ sqlite3Detach(pParse, yymsp[0].minor.yy454);
}
break;
- case 291: /* cmd ::= REINDEX */
+ case 292: /* cmd ::= REINDEX */
{sqlite3Reindex(pParse, 0, 0);}
break;
- case 292: /* cmd ::= REINDEX nm dbnm */
+ case 293: /* cmd ::= REINDEX nm dbnm */
{sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
- case 293: /* cmd ::= ANALYZE */
+ case 294: /* cmd ::= ANALYZE */
{sqlite3Analyze(pParse, 0, 0);}
break;
- case 294: /* cmd ::= ANALYZE nm dbnm */
+ case 295: /* cmd ::= ANALYZE nm dbnm */
{sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
- case 295: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
+ case 296: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
{
- sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy493,&yymsp[0].minor.yy0);
+ sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy203,&yymsp[0].minor.yy0);
}
break;
- case 296: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+ case 297: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
{
yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n;
sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0);
}
break;
- case 297: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
+ case 298: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
{
- sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy493, &yymsp[0].minor.yy0);
+ sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy203, &yymsp[0].minor.yy0);
}
break;
- case 298: /* add_column_fullname ::= fullname */
+ case 299: /* add_column_fullname ::= fullname */
{
disableLookaside(pParse);
- sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy493);
+ sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy203);
}
break;
- case 299: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
+ case 300: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
{
- sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy493, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);
+ sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy203, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);
}
break;
- case 300: /* cmd ::= create_vtab */
+ case 301: /* cmd ::= ALTER TABLE fullname ALTER COLUMNKW columnname TO columnname carglist */
+{
+ libsqlAlterAlterColumn(pParse, yymsp[-6].minor.yy203, &yymsp[-3].minor.yy0, &yymsp[-1].minor.yy0);
+}
+ break;
+ case 302: /* cmd ::= create_vtab */
{sqlite3VtabFinishParse(pParse,0);}
break;
- case 301: /* cmd ::= create_vtab LP vtabarglist RP */
+ case 303: /* cmd ::= create_vtab LP vtabarglist RP */
{sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
break;
- case 302: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+ case 304: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
{
- sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy436);
+ sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy144);
}
break;
- case 303: /* vtabarg ::= */
+ case 305: /* vtabarg ::= */
{sqlite3VtabArgInit(pParse);}
break;
- case 304: /* vtabargtoken ::= ANY */
- case 305: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==305);
- case 306: /* lp ::= LP */ yytestcase(yyruleno==306);
+ case 306: /* vtabargtoken ::= ANY */
+ case 307: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==307);
+ case 308: /* lp ::= LP */ yytestcase(yyruleno==308);
{sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
break;
- case 307: /* with ::= WITH wqlist */
- case 308: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==308);
-{ sqlite3WithPush(pParse, yymsp[0].minor.yy19, 1); }
+ case 309: /* with ::= WITH wqlist */
+ case 310: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==310);
+{ sqlite3WithPush(pParse, yymsp[0].minor.yy59, 1); }
break;
- case 309: /* wqas ::= AS */
-{yymsp[0].minor.yy480 = M10d_Any;}
+ case 311: /* wqas ::= AS */
+{yymsp[0].minor.yy462 = M10d_Any;}
break;
- case 310: /* wqas ::= AS MATERIALIZED */
-{yymsp[-1].minor.yy480 = M10d_Yes;}
+ case 312: /* wqas ::= AS MATERIALIZED */
+{yymsp[-1].minor.yy462 = M10d_Yes;}
break;
- case 311: /* wqas ::= AS NOT MATERIALIZED */
-{yymsp[-2].minor.yy480 = M10d_No;}
+ case 313: /* wqas ::= AS NOT MATERIALIZED */
+{yymsp[-2].minor.yy462 = M10d_No;}
break;
- case 312: /* wqitem ::= nm eidlist_opt wqas LP select RP */
+ case 314: /* wqitem ::= nm eidlist_opt wqas LP select RP */
{
- yymsp[-5].minor.yy615 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy586, yymsp[-1].minor.yy136, yymsp[-3].minor.yy480); /*A-overwrites-X*/
+ yymsp[-5].minor.yy67 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy14, yymsp[-1].minor.yy555, yymsp[-3].minor.yy462); /*A-overwrites-X*/
}
break;
- case 313: /* wqlist ::= wqitem */
+ case 315: /* wqlist ::= wqitem */
{
- yymsp[0].minor.yy19 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy615); /*A-overwrites-X*/
+ yymsp[0].minor.yy59 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy67); /*A-overwrites-X*/
}
break;
- case 314: /* wqlist ::= wqlist COMMA wqitem */
+ case 316: /* wqlist ::= wqlist COMMA wqitem */
{
- yymsp[-2].minor.yy19 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy19, yymsp[0].minor.yy615);
+ yymsp[-2].minor.yy59 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy59, yymsp[0].minor.yy67);
}
break;
- case 315: /* windowdefn_list ::= windowdefn */
-{ yylhsminor.yy591 = yymsp[0].minor.yy591; }
- yymsp[0].minor.yy591 = yylhsminor.yy591;
- break;
- case 316: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */
+ case 317: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */
{
- assert( yymsp[0].minor.yy591!=0 );
- sqlite3WindowChain(pParse, yymsp[0].minor.yy591, yymsp[-2].minor.yy591);
- yymsp[0].minor.yy591->pNextWin = yymsp[-2].minor.yy591;
- yylhsminor.yy591 = yymsp[0].minor.yy591;
+ assert( yymsp[0].minor.yy211!=0 );
+ sqlite3WindowChain(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy211);
+ yymsp[0].minor.yy211->pNextWin = yymsp[-2].minor.yy211;
+ yylhsminor.yy211 = yymsp[0].minor.yy211;
}
- yymsp[-2].minor.yy591 = yylhsminor.yy591;
+ yymsp[-2].minor.yy211 = yylhsminor.yy211;
break;
- case 317: /* windowdefn ::= nm AS LP window RP */
+ case 318: /* windowdefn ::= nm AS LP window RP */
{
- if( ALWAYS(yymsp[-1].minor.yy591) ){
- yymsp[-1].minor.yy591->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n);
+ if( ALWAYS(yymsp[-1].minor.yy211) ){
+ yymsp[-1].minor.yy211->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n);
}
- yylhsminor.yy591 = yymsp[-1].minor.yy591;
+ yylhsminor.yy211 = yymsp[-1].minor.yy211;
}
- yymsp[-4].minor.yy591 = yylhsminor.yy591;
+ yymsp[-4].minor.yy211 = yylhsminor.yy211;
break;
- case 318: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+ case 319: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */
{
- yymsp[-4].minor.yy591 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy591, yymsp[-2].minor.yy586, yymsp[-1].minor.yy586, 0);
+ yymsp[-4].minor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy14, yymsp[-1].minor.yy14, 0);
}
break;
- case 319: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+ case 320: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
{
- yylhsminor.yy591 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy591, yymsp[-2].minor.yy586, yymsp[-1].minor.yy586, &yymsp[-5].minor.yy0);
+ yylhsminor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy14, yymsp[-1].minor.yy14, &yymsp[-5].minor.yy0);
}
- yymsp[-5].minor.yy591 = yylhsminor.yy591;
+ yymsp[-5].minor.yy211 = yylhsminor.yy211;
break;
- case 320: /* window ::= ORDER BY sortlist frame_opt */
+ case 321: /* window ::= ORDER BY sortlist frame_opt */
{
- yymsp[-3].minor.yy591 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy591, 0, yymsp[-1].minor.yy586, 0);
+ yymsp[-3].minor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, yymsp[-1].minor.yy14, 0);
}
break;
- case 321: /* window ::= nm ORDER BY sortlist frame_opt */
+ case 322: /* window ::= nm ORDER BY sortlist frame_opt */
{
- yylhsminor.yy591 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy591, 0, yymsp[-1].minor.yy586, &yymsp[-4].minor.yy0);
+ yylhsminor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, yymsp[-1].minor.yy14, &yymsp[-4].minor.yy0);
}
- yymsp[-4].minor.yy591 = yylhsminor.yy591;
- break;
- case 322: /* window ::= frame_opt */
- case 341: /* filter_over ::= over_clause */ yytestcase(yyruleno==341);
-{
- yylhsminor.yy591 = yymsp[0].minor.yy591;
-}
- yymsp[0].minor.yy591 = yylhsminor.yy591;
+ yymsp[-4].minor.yy211 = yylhsminor.yy211;
break;
case 323: /* window ::= nm frame_opt */
{
- yylhsminor.yy591 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy591, 0, 0, &yymsp[-1].minor.yy0);
+ yylhsminor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, 0, &yymsp[-1].minor.yy0);
}
- yymsp[-1].minor.yy591 = yylhsminor.yy591;
+ yymsp[-1].minor.yy211 = yylhsminor.yy211;
break;
case 324: /* frame_opt ::= */
{
- yymsp[1].minor.yy591 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0);
+ yymsp[1].minor.yy211 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0);
}
break;
case 325: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
{
- yylhsminor.yy591 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy436, yymsp[-1].minor.yy537.eType, yymsp[-1].minor.yy537.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy480);
+ yylhsminor.yy211 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy144, yymsp[-1].minor.yy509.eType, yymsp[-1].minor.yy509.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy462);
}
- yymsp[-2].minor.yy591 = yylhsminor.yy591;
+ yymsp[-2].minor.yy211 = yylhsminor.yy211;
break;
case 326: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
{
- yylhsminor.yy591 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy436, yymsp[-3].minor.yy537.eType, yymsp[-3].minor.yy537.pExpr, yymsp[-1].minor.yy537.eType, yymsp[-1].minor.yy537.pExpr, yymsp[0].minor.yy480);
+ yylhsminor.yy211 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy144, yymsp[-3].minor.yy509.eType, yymsp[-3].minor.yy509.pExpr, yymsp[-1].minor.yy509.eType, yymsp[-1].minor.yy509.pExpr, yymsp[0].minor.yy462);
}
- yymsp[-5].minor.yy591 = yylhsminor.yy591;
+ yymsp[-5].minor.yy211 = yylhsminor.yy211;
break;
case 328: /* frame_bound_s ::= frame_bound */
case 330: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==330);
-{yylhsminor.yy537 = yymsp[0].minor.yy537;}
- yymsp[0].minor.yy537 = yylhsminor.yy537;
+{yylhsminor.yy509 = yymsp[0].minor.yy509;}
+ yymsp[0].minor.yy509 = yylhsminor.yy509;
break;
case 329: /* frame_bound_s ::= UNBOUNDED PRECEDING */
case 331: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==331);
case 333: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==333);
-{yylhsminor.yy537.eType = yymsp[-1].major; yylhsminor.yy537.pExpr = 0;}
- yymsp[-1].minor.yy537 = yylhsminor.yy537;
+{yylhsminor.yy509.eType = yymsp[-1].major; yylhsminor.yy509.pExpr = 0;}
+ yymsp[-1].minor.yy509 = yylhsminor.yy509;
break;
case 332: /* frame_bound ::= expr PRECEDING|FOLLOWING */
-{yylhsminor.yy537.eType = yymsp[0].major; yylhsminor.yy537.pExpr = yymsp[-1].minor.yy224;}
- yymsp[-1].minor.yy537 = yylhsminor.yy537;
+{yylhsminor.yy509.eType = yymsp[0].major; yylhsminor.yy509.pExpr = yymsp[-1].minor.yy454;}
+ yymsp[-1].minor.yy509 = yylhsminor.yy509;
break;
case 334: /* frame_exclude_opt ::= */
-{yymsp[1].minor.yy480 = 0;}
+{yymsp[1].minor.yy462 = 0;}
break;
case 335: /* frame_exclude_opt ::= EXCLUDE frame_exclude */
-{yymsp[-1].minor.yy480 = yymsp[0].minor.yy480;}
+{yymsp[-1].minor.yy462 = yymsp[0].minor.yy462;}
break;
case 336: /* frame_exclude ::= NO OTHERS */
case 337: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==337);
-{yymsp[-1].minor.yy480 = yymsp[-1].major; /*A-overwrites-X*/}
+{yymsp[-1].minor.yy462 = yymsp[-1].major; /*A-overwrites-X*/}
break;
case 338: /* frame_exclude ::= GROUP|TIES */
-{yymsp[0].minor.yy480 = yymsp[0].major; /*A-overwrites-X*/}
+{yymsp[0].minor.yy462 = yymsp[0].major; /*A-overwrites-X*/}
break;
case 339: /* window_clause ::= WINDOW windowdefn_list */
-{ yymsp[-1].minor.yy591 = yymsp[0].minor.yy591; }
+{ yymsp[-1].minor.yy211 = yymsp[0].minor.yy211; }
break;
case 340: /* filter_over ::= filter_clause over_clause */
{
- if( yymsp[0].minor.yy591 ){
- yymsp[0].minor.yy591->pFilter = yymsp[-1].minor.yy224;
+ if( yymsp[0].minor.yy211 ){
+ yymsp[0].minor.yy211->pFilter = yymsp[-1].minor.yy454;
}else{
- sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy224);
+ sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy454);
}
- yylhsminor.yy591 = yymsp[0].minor.yy591;
+ yylhsminor.yy211 = yymsp[0].minor.yy211;
+}
+ yymsp[-1].minor.yy211 = yylhsminor.yy211;
+ break;
+ case 341: /* filter_over ::= over_clause */
+{
+ yylhsminor.yy211 = yymsp[0].minor.yy211;
}
- yymsp[-1].minor.yy591 = yylhsminor.yy591;
+ yymsp[0].minor.yy211 = yylhsminor.yy211;
break;
case 342: /* filter_over ::= filter_clause */
{
- yylhsminor.yy591 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
- if( yylhsminor.yy591 ){
- yylhsminor.yy591->eFrmType = TK_FILTER;
- yylhsminor.yy591->pFilter = yymsp[0].minor.yy224;
+ yylhsminor.yy211 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
+ if( yylhsminor.yy211 ){
+ yylhsminor.yy211->eFrmType = TK_FILTER;
+ yylhsminor.yy211->pFilter = yymsp[0].minor.yy454;
}else{
- sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy224);
+ sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy454);
}
}
- yymsp[0].minor.yy591 = yylhsminor.yy591;
+ yymsp[0].minor.yy211 = yylhsminor.yy211;
break;
case 343: /* over_clause ::= OVER LP window RP */
{
- yymsp[-3].minor.yy591 = yymsp[-1].minor.yy591;
- assert( yymsp[-3].minor.yy591!=0 );
+ yymsp[-3].minor.yy211 = yymsp[-1].minor.yy211;
+ assert( yymsp[-3].minor.yy211!=0 );
}
break;
case 344: /* over_clause ::= OVER nm */
{
- yymsp[-1].minor.yy591 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
- if( yymsp[-1].minor.yy591 ){
- yymsp[-1].minor.yy591->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n);
+ yymsp[-1].minor.yy211 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
+ if( yymsp[-1].minor.yy211 ){
+ yymsp[-1].minor.yy211->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n);
}
}
break;
case 345: /* filter_clause ::= FILTER LP WHERE expr RP */
-{ yymsp[-4].minor.yy224 = yymsp[-1].minor.yy224; }
+{ yymsp[-4].minor.yy454 = yymsp[-1].minor.yy454; }
break;
default:
/* (346) input ::= cmdlist */ yytestcase(yyruleno==346);
@@ -173262,32 +176948,32 @@ static YYACTIONTYPE yy_reduce(
/* (358) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=358);
/* (359) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==359);
/* (360) columnlist ::= columnname carglist */ yytestcase(yyruleno==360);
- /* (361) nm ::= ID|INDEXED */ yytestcase(yyruleno==361);
+ /* (361) nm ::= ID|INDEXED|JOIN_KW */ yytestcase(yyruleno==361);
/* (362) nm ::= STRING */ yytestcase(yyruleno==362);
- /* (363) nm ::= JOIN_KW */ yytestcase(yyruleno==363);
- /* (364) typetoken ::= typename */ yytestcase(yyruleno==364);
- /* (365) typename ::= ID|STRING */ yytestcase(yyruleno==365);
- /* (366) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=366);
- /* (367) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=367);
- /* (368) carglist ::= carglist ccons */ yytestcase(yyruleno==368);
- /* (369) carglist ::= */ yytestcase(yyruleno==369);
- /* (370) ccons ::= NULL onconf */ yytestcase(yyruleno==370);
- /* (371) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==371);
- /* (372) ccons ::= AS generated */ yytestcase(yyruleno==372);
- /* (373) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==373);
- /* (374) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==374);
- /* (375) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=375);
- /* (376) tconscomma ::= */ yytestcase(yyruleno==376);
- /* (377) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=377);
- /* (378) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=378);
- /* (379) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=379);
- /* (380) oneselect ::= values */ yytestcase(yyruleno==380);
- /* (381) sclp ::= selcollist COMMA */ yytestcase(yyruleno==381);
- /* (382) as ::= ID|STRING */ yytestcase(yyruleno==382);
- /* (383) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=383);
- /* (384) returning ::= */ yytestcase(yyruleno==384);
- /* (385) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=385);
- /* (386) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==386);
+ /* (363) typetoken ::= typename */ yytestcase(yyruleno==363);
+ /* (364) typename ::= ID|STRING */ yytestcase(yyruleno==364);
+ /* (365) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=365);
+ /* (366) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=366);
+ /* (367) carglist ::= carglist ccons */ yytestcase(yyruleno==367);
+ /* (368) carglist ::= */ yytestcase(yyruleno==368);
+ /* (369) ccons ::= NULL onconf */ yytestcase(yyruleno==369);
+ /* (370) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==370);
+ /* (371) ccons ::= AS generated */ yytestcase(yyruleno==371);
+ /* (372) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==372);
+ /* (373) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==373);
+ /* (374) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=374);
+ /* (375) tconscomma ::= */ yytestcase(yyruleno==375);
+ /* (376) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=376);
+ /* (377) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=377);
+ /* (378) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=378);
+ /* (379) oneselect ::= values */ yytestcase(yyruleno==379);
+ /* (380) sclp ::= selcollist COMMA */ yytestcase(yyruleno==380);
+ /* (381) as ::= ID|STRING */ yytestcase(yyruleno==381);
+ /* (382) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=382);
+ /* (383) returning ::= */ yytestcase(yyruleno==383);
+ /* (384) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=384);
+ /* (385) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==385);
+ /* (386) case_operand ::= expr */ yytestcase(yyruleno==386);
/* (387) exprlist ::= nexprlist */ yytestcase(yyruleno==387);
/* (388) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=388);
/* (389) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=389);
@@ -173310,6 +176996,8 @@ static YYACTIONTYPE yy_reduce(
/* (406) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==406);
/* (407) anylist ::= anylist ANY */ yytestcase(yyruleno==407);
/* (408) with ::= */ yytestcase(yyruleno==408);
+ /* (409) windowdefn_list ::= windowdefn (OPTIMIZED OUT) */ assert(yyruleno!=409);
+ /* (410) window ::= frame_opt (OPTIMIZED OUT) */ assert(yyruleno!=410);
break;
/********** End reduce actions ************************************************/
};
@@ -173816,8 +177504,8 @@ const unsigned char ebcdicToAscii[] = {
** is substantially reduced. This is important for embedded applications
** on platforms with limited memory.
*/
-/* Hash score: 236 */
-/* zKWText[] encodes 1032 bytes of keyword text in 687 bytes */
+/* Hash score: 240 */
+/* zKWText[] encodes 1041 bytes of keyword text in 695 bytes */
/* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */
/* ABLEFTHENDEFERRABLELSEXCLUDELETEMPORARYISNULLSAVEPOINTERSECT */
/* IESNOTNULLANGUAGENERATEDETACHAVINGLOBEGINNERAISEXCEPT */
@@ -173829,8 +177517,8 @@ const unsigned char ebcdicToAscii[] = {
/* COMMITCONFLICTCROSSCURRENT_TIMESTAMPARTITIONDROPRECEDINGFAIL */
/* ASTFILTERENAMEFIRSTFOLLOWINGFROMFULLIMITFUNCTIONIFORDEREPLACE */
/* OTHERSOVERESTRICTRETURNINGRIGHTROLLBACKROWSUNBOUNDEDUNIONUSING */
-/* VACUUMVIEWINDOWBYINITIALLYPRIMARY */
-static const char zKWText[686] = {
+/* VACUUMVIEWINDOWBYINITIALLYPRIMARYREADONLY */
+static const char zKWText[694] = {
'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H',
'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G',
'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A',
@@ -173869,40 +177557,40 @@ static const char zKWText[686] = {
'R','O','W','S','U','N','B','O','U','N','D','E','D','U','N','I','O','N',
'U','S','I','N','G','V','A','C','U','U','M','V','I','E','W','I','N','D',
'O','W','B','Y','I','N','I','T','I','A','L','L','Y','P','R','I','M','A',
- 'R','Y',
+ 'R','Y','R','E','A','D','O','N','L','Y',
};
/* aKWHash[i] is the hash value for the i-th keyword */
static const unsigned char aKWHash[127] = {
86, 93, 137, 84, 116, 29, 0, 0, 95, 0, 88, 74, 0,
60, 35, 64, 15, 0, 49, 98, 61, 90, 138, 19, 40, 0,
143, 0, 87, 134, 0, 22, 106, 0, 9, 0, 0, 124, 82,
- 0, 80, 6, 0, 67, 104, 150, 0, 139, 114, 0, 0, 55,
+ 0, 80, 6, 0, 67, 104, 149, 0, 139, 114, 0, 0, 55,
0, 91, 24, 0, 17, 0, 27, 72, 23, 26, 5, 44, 145,
- 109, 123, 0, 75, 92, 73, 148, 45, 121, 76, 0, 56, 0,
+ 109, 123, 0, 75, 92, 73, 147, 45, 121, 76, 0, 56, 0,
11, 48, 0, 112, 0, 0, 0, 108, 10, 110, 115, 126, 14,
- 128, 125, 0, 101, 0, 18, 131, 147, 54, 132, 142, 89, 85,
+ 128, 125, 0, 101, 0, 18, 131, 146, 54, 132, 142, 89, 85,
37, 30, 127, 0, 0, 107, 58, 133, 130, 0, 34, 0, 0,
135, 0, 99, 38, 39, 0, 20, 52, 118, 94,
};
/* aKWNext[] forms the hash collision chain. If aKWHash[i]==0
** then the i-th keyword has no more hash collisions. Otherwise,
** the next keyword with the same hash is aKWHash[i]-1. */
-static const unsigned char aKWNext[150] = {
+static const unsigned char aKWNext[152] = {0,
0, 0, 0, 0, 4, 0, 50, 0, 0, 105, 113, 0, 0,
- 0, 2, 0, 0, 146, 0, 0, 0, 13, 0, 0, 0, 0,
+ 0, 2, 0, 0, 151, 0, 0, 0, 13, 0, 0, 0, 0,
144, 0, 0, 120, 59, 0, 0, 140, 12, 0, 0, 46, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 0, 0, 36,
0, 47, 28, 79, 0, 0, 0, 0, 43, 0, 0, 0, 0,
- 0, 0, 0, 71, 0, 0, 0, 0, 0, 149, 3, 0, 42,
+ 0, 0, 0, 71, 0, 0, 0, 0, 0, 148, 3, 0, 42,
0, 1, 77, 0, 0, 0, 31, 0, 141, 103, 0, 129, 0,
- 117, 0, 66, 68, 63, 0, 0, 0, 0, 0, 53, 0, 16,
+ 117, 0, 66, 68, 63, 0, 0, 0, 0, 0, 53, 0, 150,
0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 102, 0, 8,
0, 111, 21, 7, 0, 0, 81, 97, 119, 0, 57, 0, 70,
69, 0, 100, 0, 51, 0, 62, 0, 78, 0, 96, 32, 33,
- 41, 25, 0, 122, 0, 0, 65,
+ 41, 25, 122, 0, 0, 65, 16, 0,
};
/* aKWLen[i] is the length (in bytes) of the i-th keyword */
-static const unsigned char aKWLen[150] = {
+static const unsigned char aKWLen[152] = {0,
7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6,
7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 7,
6, 9, 4, 2, 6, 5, 9, 9, 4, 7, 3, 2, 4,
@@ -173914,11 +177602,11 @@ static const unsigned char aKWLen[150] = {
13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 9, 4,
9, 4, 4, 6, 6, 5, 9, 4, 4, 5, 8, 2, 5,
7, 6, 4, 8, 9, 5, 8, 4, 3, 9, 5, 5, 6,
- 4, 6, 2, 2, 9, 3, 7,
+ 4, 6, 2, 9, 3, 7, 8, 2,
};
/* aKWOffset[i] is the index into zKWText[] of the start of
** the text for the i-th keyword. */
-static const unsigned short int aKWOffset[150] = {
+static const unsigned short int aKWOffset[152] = {0,
0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33,
36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81,
86, 90, 90, 94, 99, 101, 105, 111, 119, 123, 123, 123, 126,
@@ -173930,10 +177618,10 @@ static const unsigned short int aKWOffset[150] = {
447, 449, 451, 460, 464, 470, 476, 484, 489, 489, 489, 505, 514,
517, 526, 529, 533, 538, 544, 549, 558, 562, 565, 570, 578, 580,
584, 591, 597, 600, 608, 617, 622, 630, 630, 634, 643, 648, 653,
- 659, 662, 665, 668, 670, 675, 679,
+ 659, 662, 668, 670, 675, 679, 686, 689,
};
/* aKWCode[i] is the parser symbol code for the i-th keyword */
-static const unsigned char aKWCode[150] = {
+static const unsigned char aKWCode[152] = {0,
TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE,
TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN,
TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD,
@@ -173963,7 +177651,8 @@ static const unsigned char aKWCode[150] = {
TK_REPLACE, TK_OTHERS, TK_OVER, TK_RESTRICT, TK_RETURNING,
TK_JOIN_KW, TK_ROLLBACK, TK_ROWS, TK_ROW, TK_UNBOUNDED,
TK_UNION, TK_USING, TK_VACUUM, TK_VIEW, TK_WINDOW,
- TK_DO, TK_BY, TK_INITIALLY, TK_ALL, TK_PRIMARY,
+ TK_BY, TK_INITIALLY, TK_ALL, TK_PRIMARY, TK_READONLY,
+ TK_DO,
};
/* Hash table decoded:
** 0: INSERT
@@ -174010,7 +177699,7 @@ static const unsigned char aKWCode[150] = {
** 41: EACH
** 42:
** 43: QUERY
-** 44: AND ADD
+** 44: AND READONLY ADD
** 45: PRIMARY ANALYZE
** 46:
** 47: ROW ASC DETACH
@@ -174100,188 +177789,189 @@ static const unsigned char aKWCode[150] = {
static int keywordCode(const char *z, int n, int *pType){
int i, j;
const char *zKW;
- if( n>=2 ){
- i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n*1) % 127;
- for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){
- if( aKWLen[i]!=n ) continue;
- zKW = &zKWText[aKWOffset[i]];
+ assert( n>=2 );
+ i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n*1) % 127;
+ for(i=(int)aKWHash[i]; i>0; i=aKWNext[i]){
+ if( aKWLen[i]!=n ) continue;
+ zKW = &zKWText[aKWOffset[i]];
#ifdef SQLITE_ASCII
- if( (z[0]&~0x20)!=zKW[0] ) continue;
- if( (z[1]&~0x20)!=zKW[1] ) continue;
- j = 2;
- while( j=2 ) keywordCode((char*)z, n, &id);
return id;
}
-#define SQLITE_N_KEYWORD 150
+#define SQLITE_N_KEYWORD 151
SQLITE_API int sqlite3_keyword_name(int i,const char **pzName,int *pnName){
if( i<0 || i>=SQLITE_N_KEYWORD ) return SQLITE_ERROR;
+ i++;
*pzName = zKWText + aKWOffset[i];
*pnName = aKWLen[i];
return SQLITE_OK;
@@ -174580,7 +178270,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' );
testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' );
testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' );
- testcase( z[0]=='9' );
+ testcase( z[0]=='9' ); testcase( z[0]=='.' );
*tokenType = TK_INTEGER;
#ifndef SQLITE_OMIT_HEX_INTEGER
if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){
@@ -174652,7 +178342,8 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
return i;
}
case CC_KYWD0: {
- for(i=1; aiClass[z[i]]<=CC_KYWD; i++){}
+ if( aiClass[z[1]]>CC_KYWD ){ i = 1; break; }
+ for(i=2; aiClass[z[i]]<=CC_KYWD; i++){}
if( IdChar(z[i]) ){
/* This token started out using characters that can appear in keywords,
** but z[i] is a character not allowed within keywords, so this must
@@ -175431,30 +179122,20 @@ static int sqlite3TestExtInit(sqlite3 *db){
** Forward declarations of external module initializer functions
** for modules that need them.
*/
-#ifdef SQLITE_ENABLE_FTS1
-SQLITE_PRIVATE int sqlite3Fts1Init(sqlite3*);
-#endif
-#ifdef SQLITE_ENABLE_FTS2
-SQLITE_PRIVATE int sqlite3Fts2Init(sqlite3*);
-#endif
#ifdef SQLITE_ENABLE_FTS5
SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3*);
#endif
#ifdef SQLITE_ENABLE_STMTVTAB
SQLITE_PRIVATE int sqlite3StmtVtabInit(sqlite3*);
#endif
-
+#ifdef SQLITE_EXTRA_AUTOEXT
+int SQLITE_EXTRA_AUTOEXT(sqlite3*);
+#endif
/*
** An array of pointers to extension initializer functions for
** built-in extensions.
*/
static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = {
-#ifdef SQLITE_ENABLE_FTS1
- sqlite3Fts1Init,
-#endif
-#ifdef SQLITE_ENABLE_FTS2
- sqlite3Fts2Init,
-#endif
#ifdef SQLITE_ENABLE_FTS3
sqlite3Fts3Init,
#endif
@@ -175483,6 +179164,9 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = {
#ifdef SQLITE_ENABLE_BYTECODE_VTAB
sqlite3VdbeBytecodeVtabInit,
#endif
+#ifdef SQLITE_EXTRA_AUTOEXT
+ SQLITE_EXTRA_AUTOEXT,
+#endif
};
#ifndef SQLITE_AMALGAMATION
@@ -175559,6 +179243,32 @@ SQLITE_API char *sqlite3_temp_directory = 0;
*/
SQLITE_API char *sqlite3_data_directory = 0;
+/*
+** Determine whether or not high-precision (long double) floating point
+** math works correctly on CPU currently running.
+*/
+static SQLITE_NOINLINE int hasHighPrecisionDouble(int rc){
+ if( sizeof(LONGDOUBLE_TYPE)<=8 ){
+ /* If the size of "long double" is not more than 8, then
+ ** high-precision math is not possible. */
+ return 0;
+ }else{
+ /* Just because sizeof(long double)>8 does not mean that the underlying
+ ** hardware actually supports high-precision floating point. For example,
+ ** clearing the 0x100 bit in the floating-point control word on Intel
+ ** processors will make long double work like double, even though long
+ ** double takes up more space. The only way to determine if long double
+ ** actually works is to run an experiment. */
+ LONGDOUBLE_TYPE a, b, c;
+ rc++;
+ a = 1.0+rc*0.1;
+ b = 1.0e+18+rc*25.0;
+ c = a+b;
+ return b!=c;
+ }
+}
+
+
/*
** Initialize SQLite.
**
@@ -175754,6 +179464,12 @@ SQLITE_API int sqlite3_initialize(void){
}
#endif
+ /* Experimentally determine if high-precision floating point is
+ ** available. */
+#ifndef SQLITE_OMIT_WSD
+ sqlite3Config.bUseLongDouble = hasHighPrecisionDouble(rc);
+#endif
+
return rc;
}
@@ -176324,6 +180040,10 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3 *db){
SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
va_list ap;
int rc;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
va_start(ap, op);
switch( op ){
@@ -176624,6 +180344,10 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
db->trace.xV2(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
}
+ if (db->xCloseCallback) {
+ db->xCloseCallback(db->pCloseArg, db);
+ }
+
/* Force xDisconnect calls on all virtual tables */
disconnectAllVtab(db);
@@ -176653,9 +180377,22 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
}
#endif
+ while( db->pDbData ){
+ DbClientData *p = db->pDbData;
+ db->pDbData = p->pNext;
+ assert( p->pData!=0 );
+ if( p->xDestructor ) p->xDestructor(p->pData);
+ sqlite3_free(p);
+ }
+
/* Convert the connection into a zombie and then close it.
*/
db->eOpenState = SQLITE_STATE_ZOMBIE;
+#ifdef LIBSQL_ENABLE_WASM_RUNTIME
+ if (db->wasm.engine) {
+ libsql_wasm_engine_free(db->wasm.engine);
+ }
+#endif
sqlite3LeaveMutexAndCloseZombie(db);
return SQLITE_OK;
}
@@ -176824,6 +180561,9 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
if( db->lookaside.bMalloced ){
sqlite3_free(db->lookaside.pStart);
}
+
+ destroy_wal_manager(db->wal_manager);
+
sqlite3_free(db);
}
@@ -177070,9 +180810,9 @@ static int sqliteDefaultBusyCallback(
void *ptr, /* Database connection */
int count /* Number of times table has been busy */
){
-#if SQLITE_OS_WIN || HAVE_USLEEP
+#if SQLITE_OS_WIN || !defined(HAVE_NANOSLEEP) || HAVE_NANOSLEEP
/* This case is for systems that have support for sleeping for fractions of
- ** a second. Examples: All windows systems, unix systems with usleep() */
+ ** a second. Examples: All windows systems, unix systems with nanosleep() */
static const u8 delays[] =
{ 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 };
static const u8 totals[] =
@@ -177727,6 +181467,12 @@ SQLITE_API void *sqlite3_preupdate_hook(
void *pArg /* First callback argument */
){
void *pRet;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( db==0 ){
+ return 0;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
pRet = db->pPreUpdateArg;
db->xPreUpdateCallback = xCallback;
@@ -177736,6 +181482,24 @@ SQLITE_API void *sqlite3_preupdate_hook(
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
+/*
+** Register a callback to be invoked when the connection is closed.
+*/
+void *libsql_close_hook(
+ sqlite3 *db, /* Attach the hook to this connection */
+ void(*xCallback)( /* Callback function */
+ void*,sqlite3*),
+ void *pArg /* First callback argument */
+){
+ void *pRet;
+ sqlite3_mutex_enter(db->mutex);
+ pRet = db->pCloseArg;
+ db->xCloseCallback = xCallback;
+ db->pCloseArg = pArg;
+ sqlite3_mutex_leave(db->mutex);
+ return pRet;
+}
+
/*
** Register a function to be invoked prior to each autovacuum that
** determines the number of pages to vacuum.
@@ -177873,7 +181637,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
if( eModeSQLITE_CHECKPOINT_TRUNCATE ){
/* EVIDENCE-OF: R-03996-12088 The M parameter must be a valid checkpoint
** mode: */
- return SQLITE_MISUSE;
+ return SQLITE_MISUSE_BKPT;
}
sqlite3_mutex_enter(db->mutex);
@@ -178307,10 +182071,8 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
return oldLimit; /* IMP: R-53341-35419 */
}
-#ifdef SQLITE_OMIT_WAL
-libsql_wal_methods* libsql_wal_methods_find(const char *zName) {
- return NULL;
-}
+#ifdef LIBSQL_PRE_VFS_HOOK
+void libsql_pre_vfs_hook(const char *zVfs);
#endif
/*
@@ -178343,18 +182105,15 @@ libsql_wal_methods* libsql_wal_methods_find(const char *zName) {
*/
SQLITE_PRIVATE int sqlite3ParseUri(
const char *zDefaultVfs, /* VFS to use if no "vfs=xxx" query option */
- const char *zDefaultWal, /* WAL module to use if no "wal=xxx" query option */
const char *zUri, /* Nul-terminated URI to parse */
unsigned int *pFlags, /* IN/OUT: SQLITE_OPEN_XXX flags */
sqlite3_vfs **ppVfs, /* OUT: VFS to use */
- libsql_wal_methods **ppWal, /* OUT: WAL module to use */
char **pzFile, /* OUT: Filename component of URI */
char **pzErrMsg /* OUT: Error message (if rc!=SQLITE_OK) */
){
int rc = SQLITE_OK;
unsigned int flags = *pFlags;
const char *zVfs = zDefaultVfs;
- const char *zWal = zDefaultWal;
char *zFile;
char c;
int nUri = sqlite3Strlen30(zUri);
@@ -178485,9 +182244,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
if( nOpt==3 && memcmp("vfs", zOpt, 3)==0 ){
zVfs = zVal;
- }else if( nOpt==3 && memcmp("wal", zOpt, 3)==0 ){
- zWal = zVal;
- }else{
+ } else {
struct OpenMode {
const char *z;
int mode;
@@ -178564,16 +182321,15 @@ SQLITE_PRIVATE int sqlite3ParseUri(
flags &= ~SQLITE_OPEN_URI;
}
+#ifdef LIBSQL_PRE_VFS_HOOK
+ libsql_pre_vfs_hook(zVfs);
+#endif
+
*ppVfs = sqlite3_vfs_find(zVfs);
if( *ppVfs==0 ){
*pzErrMsg = sqlite3_mprintf("no such vfs: %s", zVfs);
rc = SQLITE_ERROR;
}
- *ppWal = libsql_wal_methods_find(zWal);
- if( *ppWal==NULL ){
- *pzErrMsg = sqlite3_mprintf("no such WAL module: %s", zWal);
- rc = SQLITE_ERROR;
- }
parse_uri_out:
if( rc!=SQLITE_OK ){
sqlite3_free_filename(zFile);
@@ -178599,7 +182355,9 @@ static const char *uriParameter(const char *zFilename, const char *zParam){
return 0;
}
-
+#ifdef LIBSQL_EXTRA_URI_PARAMS
+int libsql_handle_extra_uri_params(sqlite3 *db, const char *zOpen);
+#endif
/*
** This routine does the work of opening a database on behalf of
@@ -178607,11 +182365,11 @@ static const char *uriParameter(const char *zFilename, const char *zParam){
** is UTF-8 encoded.
*/
static int openDatabase(
- const char *zFilename, /* Database filename UTF-8 encoded */
- sqlite3 **ppDb, /* OUT: Returned database handle */
- unsigned int flags, /* Operational flags */
- const char *zVfs, /* Name of the VFS to use */
- const char *zWal /* Name of WAL module to use */
+ const char *zFilename, /* Database filename UTF-8 encoded */
+ sqlite3 **ppDb, /* OUT: Returned database handle */
+ unsigned int flags, /* Operational flags */
+ const char *zVfs, /* Name of the VFS to use */
+ RefCountedWalManager *wal_manager /* wal manager implementation */
){
sqlite3 *db; /* Store allocated handle here */
int rc; /* Return code */
@@ -178671,6 +182429,7 @@ static int openDatabase(
/* Allocate the sqlite data structure */
db = sqlite3MallocZero( sizeof(sqlite3) );
if( db==0 ) goto opendb_out;
+ db->wal_manager = wal_manager;
if( isThreadsafe
#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
|| sqlite3GlobalConfig.bCoreMutex
@@ -178678,6 +182437,8 @@ static int openDatabase(
){
db->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
if( db->mutex==0 ){
+ wal_manager->ref.xDestroy(wal_manager->ref.pData);
+ sqlite3_free(db->wal_manager);
sqlite3_free(db);
db = 0;
goto opendb_out;
@@ -178729,7 +182490,7 @@ static int openDatabase(
** 0 off off
**
** Legacy behavior is 3 (double-quoted string literals are allowed anywhere)
-** and so that is the default. But developers are encouranged to use
+** and so that is the default. But developers are encouraged to use
** -DSQLITE_DQS=0 (best) or -DSQLITE_DQS=1 (second choice) if possible.
*/
#if !defined(SQLITE_DQS)
@@ -178838,7 +182599,7 @@ static int openDatabase(
if( ((1<<(flags&7)) & 0x46)==0 ){
rc = SQLITE_MISUSE_BKPT; /* IMP: R-18321-05872 */
}else{
- rc = sqlite3ParseUri(zVfs, zWal, zFilename, &flags, &db->pVfs, &db->pWalMethods, &zOpen, &zErrMsg);
+ rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
}
if( rc!=SQLITE_OK ){
if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
@@ -178854,7 +182615,7 @@ static int openDatabase(
#endif
/* Open the backend database driver */
- rc = sqlite3BtreeOpen(db->pVfs, db->pWalMethods, zOpen, db, &db->aDb[0].pBt, 0,
+ rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0,
flags | SQLITE_OPEN_MAIN_DB);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_IOERR_NOMEM ){
@@ -178932,10 +182693,6 @@ static int openDatabase(
setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside,
sqlite3GlobalConfig.nLookaside);
- if (strcmp("default", libsql_wal_methods_name(db->pWalMethods)) != 0) {
- sqlite3_exec(db, "pragma journal_mode=wal", NULL, NULL, NULL);
- }
-
sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT);
opendb_out:
@@ -178959,6 +182716,11 @@ static int openDatabase(
void *pArg = sqlite3GlobalConfig.pSqllogArg;
sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);
}
+#endif
+#ifdef LIBSQL_EXTRA_URI_PARAMS
+ if (rc == SQLITE_OK) {
+ rc = libsql_handle_extra_uri_params(db, zOpen);
+ }
#endif
sqlite3_free_filename(zOpen);
return rc;
@@ -178973,7 +182735,7 @@ SQLITE_API int sqlite3_open(
sqlite3 **ppDb
){
return openDatabase(zFilename, ppDb,
- SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL, NULL);
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL, make_sqlite3_wal_manager_rc());
}
SQLITE_API int sqlite3_open_v2(
const char *filename, /* Database filename (UTF-8) */
@@ -178981,9 +182743,10 @@ SQLITE_API int sqlite3_open_v2(
int flags, /* Flags */
const char *zVfs /* Name of VFS module to use */
){
- return openDatabase(filename, ppDb, (unsigned int)flags, zVfs, NULL);
+ return openDatabase(filename, ppDb, (unsigned int)flags, zVfs, make_sqlite3_wal_manager_rc());
}
+/* deprecated, only works with zWal == NULL */
int libsql_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
@@ -178991,7 +182754,37 @@ int libsql_open(
const char *zVfs, /* Name of VFS module to use, NULL for default */
const char *zWal /* Name of WAL module to use */
) {
- return openDatabase(filename, ppDb, (unsigned int)flags, zVfs, zWal);
+ assert( zWal == NULL );
+ return openDatabase(filename, ppDb, (unsigned int)flags, zVfs, make_sqlite3_wal_manager_rc());
+}
+
+/* deprecated, only works with zWal == NULL */
+int libsql_open_v2(
+ const char *filename, /* Database filename (UTF-8) */
+ sqlite3 **ppDb, /* OUT: SQLite db handle */
+ int flags, /* Flags */
+ const char *zVfs, /* Name of VFS module to use, NULL for default */
+ const char *zWal, /* Name of WAL module to use */
+ void* pWalMethodsData /* User data, passed to the libsql_wal struct*/
+) {
+ assert( zWal == NULL );
+ return openDatabase(filename, ppDb, (unsigned int)flags, zVfs, make_sqlite3_wal_manager_rc());
+}
+
+int libsql_open_v3(
+ const char *filename, /* Database filename (UTF-8) */
+ sqlite3 **ppDb, /* OUT: SQLite db handle */
+ int flags, /* Flags */
+ const char *zVfs, /* Name of VFS module to use, NULL for default */
+ libsql_wal_manager wal_manager /* wal_manager implemetation */
+ ) {
+ RefCountedWalManager *wal_manager_rc;
+ int rc = make_ref_counted_wal_manager(wal_manager, &wal_manager_rc);
+ if (rc) {
+ wal_manager.xDestroy(wal_manager.pData);
+ return rc;
+ }
+ return openDatabase(filename, ppDb, (unsigned int)flags, zVfs, wal_manager_rc);
}
#ifndef SQLITE_OMIT_UTF16
@@ -179020,7 +182813,7 @@ SQLITE_API int sqlite3_open16(
zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8);
if( zFilename8 ){
rc = openDatabase(zFilename8, ppDb,
- SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL, NULL);
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL, make_sqlite3_wal_manager_rc());
assert( *ppDb || rc==SQLITE_NOMEM );
if( rc==SQLITE_OK && !DbHasProperty(*ppDb, 0, DB_SchemaLoaded) ){
SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE;
@@ -179143,6 +182936,69 @@ SQLITE_API int sqlite3_collation_needed16(
}
#endif /* SQLITE_OMIT_UTF16 */
+/*
+** Find existing client data.
+*/
+SQLITE_API void *sqlite3_get_clientdata(sqlite3 *db, const char *zName){
+ DbClientData *p;
+ sqlite3_mutex_enter(db->mutex);
+ for(p=db->pDbData; p; p=p->pNext){
+ if( strcmp(p->zName, zName)==0 ){
+ void *pResult = p->pData;
+ sqlite3_mutex_leave(db->mutex);
+ return pResult;
+ }
+ }
+ sqlite3_mutex_leave(db->mutex);
+ return 0;
+}
+
+/*
+** Add new client data to a database connection.
+*/
+SQLITE_API int sqlite3_set_clientdata(
+ sqlite3 *db, /* Attach client data to this connection */
+ const char *zName, /* Name of the client data */
+ void *pData, /* The client data itself */
+ void (*xDestructor)(void*) /* Destructor */
+){
+ DbClientData *p, **pp;
+ sqlite3_mutex_enter(db->mutex);
+ pp = &db->pDbData;
+ for(p=db->pDbData; p && strcmp(p->zName,zName); p=p->pNext){
+ pp = &p->pNext;
+ }
+ if( p ){
+ assert( p->pData!=0 );
+ if( p->xDestructor ) p->xDestructor(p->pData);
+ if( pData==0 ){
+ *pp = p->pNext;
+ sqlite3_free(p);
+ sqlite3_mutex_leave(db->mutex);
+ return SQLITE_OK;
+ }
+ }else if( pData==0 ){
+ sqlite3_mutex_leave(db->mutex);
+ return SQLITE_OK;
+ }else{
+ size_t n = strlen(zName);
+ p = sqlite3_malloc64( sizeof(DbClientData)+n+1 );
+ if( p==0 ){
+ if( xDestructor ) xDestructor(pData);
+ sqlite3_mutex_leave(db->mutex);
+ return SQLITE_NOMEM;
+ }
+ memcpy(p->zName, zName, n+1);
+ p->pNext = db->pDbData;
+ db->pDbData = p;
+ }
+ p->pData = pData;
+ p->xDestructor = xDestructor;
+ sqlite3_mutex_leave(db->mutex);
+ return SQLITE_OK;
+}
+
+
#ifndef SQLITE_OMIT_DEPRECATED
/*
** This function is now an anachronism. It used to be used to recover from a
@@ -179278,7 +183134,7 @@ SQLITE_API int sqlite3_table_column_metadata(
/* Find the column for which info is requested */
if( zColumnName==0 ){
- /* Query for existance of table only */
+ /* Query for existence of table only */
}else{
for(iCol=0; iColnCol; iCol++){
pCol = &pTab->aCol[iCol];
@@ -179359,7 +183215,7 @@ SQLITE_API int sqlite3_sleep(int ms){
/* This function works in milliseconds, but the underlying OsSleep()
** API uses microseconds. Hence the 1000's.
*/
- rc = (sqlite3OsSleep(pVfs, 1000*ms)/1000);
+ rc = (sqlite3OsSleep(pVfs, ms<0 ? 0 : 1000*ms)/1000);
return rc;
}
@@ -179497,6 +183353,28 @@ SQLITE_API int sqlite3_test_control(int op, ...){
}
#endif
+ /* sqlite3_test_control(SQLITE_TESTCTRL_FK_NO_ACTION, sqlite3 *db, int b);
+ **
+ ** If b is true, then activate the SQLITE_FkNoAction setting. If b is
+ ** false then clearn that setting. If the SQLITE_FkNoAction setting is
+ ** abled, all foreign key ON DELETE and ON UPDATE actions behave as if
+ ** they were NO ACTION, regardless of how they are defined.
+ **
+ ** NB: One must usually run "PRAGMA writable_schema=RESET" after
+ ** using this test-control, before it will take full effect. failing
+ ** to reset the schema can result in some unexpected behavior.
+ */
+ case SQLITE_TESTCTRL_FK_NO_ACTION: {
+ sqlite3 *db = va_arg(ap, sqlite3*);
+ int b = va_arg(ap, int);
+ if( b ){
+ db->flags |= SQLITE_FkNoAction;
+ }else{
+ db->flags &= ~SQLITE_FkNoAction;
+ }
+ break;
+ }
+
/*
** sqlite3_test_control(BITVEC_TEST, size, program)
**
@@ -179603,10 +183481,12 @@ SQLITE_API int sqlite3_test_control(int op, ...){
sqlite3ShowSrcList(0);
sqlite3ShowWith(0);
sqlite3ShowUpsert(0);
+#ifndef SQLITE_OMIT_TRIGGER
sqlite3ShowTriggerStep(0);
sqlite3ShowTriggerStepList(0);
sqlite3ShowTrigger(0);
sqlite3ShowTriggerList(0);
+#endif
#ifndef SQLITE_OMIT_WINDOWFUNC
sqlite3ShowWindow(0);
sqlite3ShowWinFunc(0);
@@ -179723,7 +183603,7 @@ SQLITE_API int sqlite3_test_control(int op, ...){
** formed and never corrupt. This flag is clear by default, indicating that
** database files might have arbitrary corruption. Setting the flag during
** testing causes certain assert() statements in the code to be activated
- ** that demonstrat invariants on well-formed database files.
+ ** that demonstrate invariants on well-formed database files.
*/
case SQLITE_TESTCTRL_NEVER_CORRUPT: {
sqlite3GlobalConfig.neverCorrupt = va_arg(ap, int);
@@ -179877,7 +183757,7 @@ SQLITE_API int sqlite3_test_control(int op, ...){
**
** op==0 Store the current sqlite3TreeTrace in *ptr
** op==1 Set sqlite3TreeTrace to the value *ptr
- ** op==3 Store the current sqlite3WhereTrace in *ptr
+ ** op==2 Store the current sqlite3WhereTrace in *ptr
** op==3 Set sqlite3WhereTrace to the value *ptr
*/
case SQLITE_TESTCTRL_TRACEFLAGS: {
@@ -179913,6 +183793,23 @@ SQLITE_API int sqlite3_test_control(int op, ...){
break;
}
+#if !defined(SQLITE_OMIT_WSD)
+ /* sqlite3_test_control(SQLITE_TESTCTRL_USELONGDOUBLE, int X);
+ **
+ ** X<0 Make no changes to the bUseLongDouble. Just report value.
+ ** X==0 Disable bUseLongDouble
+ ** X==1 Enable bUseLongDouble
+ ** X>=2 Set bUseLongDouble to its default value for this platform
+ */
+ case SQLITE_TESTCTRL_USELONGDOUBLE: {
+ int b = va_arg(ap, int);
+ if( b>=2 ) b = hasHighPrecisionDouble(b);
+ if( b>=0 ) sqlite3Config.bUseLongDouble = b>0;
+ rc = sqlite3Config.bUseLongDouble!=0;
+ break;
+ }
+#endif
+
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
/* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue)
@@ -180213,7 +184110,7 @@ SQLITE_API int sqlite3_snapshot_get(
}
/*
-** Open a read-transaction on the snapshot idendified by pSnapshot.
+** Open a read-transaction on the snapshot identified by pSnapshot.
*/
SQLITE_API int sqlite3_snapshot_open(
sqlite3 *db,
@@ -180320,7 +184217,7 @@ SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
int nOpt;
const char **azCompileOpt;
-#if SQLITE_ENABLE_API_ARMOR
+#ifdef SQLITE_ENABLE_API_ARMOR
if( zOptName==0 ){
(void)SQLITE_MISUSE_BKPT;
return 0;
@@ -180515,6 +184412,9 @@ SQLITE_API int sqlite3_unlock_notify(
){
int rc = SQLITE_OK;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
enterMutex();
@@ -181536,6 +185436,7 @@ struct Fts3Table {
int nPgsz; /* Page size for host database */
char *zSegmentsTbl; /* Name of %_segments table */
sqlite3_blob *pSegments; /* Blob handle open on %_segments table */
+ int iSavepoint;
/*
** The following array of hash tables is used to buffer pending index
@@ -182279,6 +186180,7 @@ static void fts3DeclareVtab(int *pRc, Fts3Table *p){
zLanguageid = (p->zLanguageid ? p->zLanguageid : "__langid");
sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
+ sqlite3_vtab_config(p->db, SQLITE_VTAB_INNOCUOUS);
/* Create a list of user columns for the virtual table */
zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]);
@@ -185528,6 +189430,8 @@ static int fts3RenameMethod(
rc = sqlite3Fts3PendingTermsFlush(p);
}
+ p->bIgnoreSavepoint = 1;
+
if( p->zContentTbl==0 ){
fts3DbExec(&rc, db,
"ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
@@ -185555,6 +189459,8 @@ static int fts3RenameMethod(
"ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';",
p->zDb, p->zName, zName
);
+
+ p->bIgnoreSavepoint = 0;
return rc;
}
@@ -185565,12 +189471,28 @@ static int fts3RenameMethod(
*/
static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
int rc = SQLITE_OK;
- UNUSED_PARAMETER(iSavepoint);
- assert( ((Fts3Table *)pVtab)->inTransaction );
- assert( ((Fts3Table *)pVtab)->mxSavepoint <= iSavepoint );
- TESTONLY( ((Fts3Table *)pVtab)->mxSavepoint = iSavepoint );
- if( ((Fts3Table *)pVtab)->bIgnoreSavepoint==0 ){
- rc = fts3SyncMethod(pVtab);
+ Fts3Table *pTab = (Fts3Table*)pVtab;
+ assert( pTab->inTransaction );
+ assert( pTab->mxSavepoint<=iSavepoint );
+ TESTONLY( pTab->mxSavepoint = iSavepoint );
+
+ if( pTab->bIgnoreSavepoint==0 ){
+ if( fts3HashCount(&pTab->aIndex[0].hPending)>0 ){
+ char *zSql = sqlite3_mprintf("INSERT INTO %Q.%Q(%Q) VALUES('flush')",
+ pTab->zDb, pTab->zName, pTab->zName
+ );
+ if( zSql ){
+ pTab->bIgnoreSavepoint = 1;
+ rc = sqlite3_exec(pTab->db, zSql, 0, 0, 0);
+ pTab->bIgnoreSavepoint = 0;
+ sqlite3_free(zSql);
+ }else{
+ rc = SQLITE_NOMEM;
+ }
+ }
+ if( rc==SQLITE_OK ){
+ pTab->iSavepoint = iSavepoint+1;
+ }
}
return rc;
}
@@ -185581,12 +189503,11 @@ static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
** This is a no-op.
*/
static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
- TESTONLY( Fts3Table *p = (Fts3Table*)pVtab );
- UNUSED_PARAMETER(iSavepoint);
- UNUSED_PARAMETER(pVtab);
- assert( p->inTransaction );
- assert( p->mxSavepoint >= iSavepoint );
- TESTONLY( p->mxSavepoint = iSavepoint-1 );
+ Fts3Table *pTab = (Fts3Table*)pVtab;
+ assert( pTab->inTransaction );
+ assert( pTab->mxSavepoint >= iSavepoint );
+ TESTONLY( pTab->mxSavepoint = iSavepoint-1 );
+ pTab->iSavepoint = iSavepoint;
return SQLITE_OK;
}
@@ -185596,11 +189517,13 @@ static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
** Discard the contents of the pending terms table.
*/
static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
- Fts3Table *p = (Fts3Table*)pVtab;
+ Fts3Table *pTab = (Fts3Table*)pVtab;
UNUSED_PARAMETER(iSavepoint);
- assert( p->inTransaction );
- TESTONLY( p->mxSavepoint = iSavepoint );
- sqlite3Fts3PendingTermsClear(p);
+ assert( pTab->inTransaction );
+ TESTONLY( pTab->mxSavepoint = iSavepoint );
+ if( (iSavepoint+1)<=pTab->iSavepoint ){
+ sqlite3Fts3PendingTermsClear(pTab);
+ }
return SQLITE_OK;
}
@@ -185619,8 +189542,49 @@ static int fts3ShadowName(const char *zName){
return 0;
}
+/*
+** Implementation of the xIntegrity() method on the FTS3/FTS4 virtual
+** table.
+*/
+static int fts3Integrity(
+ sqlite3_vtab *pVtab, /* The virtual table to be checked */
+ const char *zSchema, /* Name of schema in which pVtab lives */
+ const char *zTabname, /* Name of the pVTab table */
+ int isQuick, /* True if this is a quick_check */
+ char **pzErr /* Write error message here */
+){
+ Fts3Table *p = (Fts3Table*)pVtab;
+ char *zSql;
+ int rc;
+ char *zErr = 0;
+
+ assert( pzErr!=0 );
+ assert( *pzErr==0 );
+ UNUSED_PARAMETER(isQuick);
+ zSql = sqlite3_mprintf(
+ "INSERT INTO \"%w\".\"%w\"(\"%w\") VALUES('integrity-check');",
+ zSchema, zTabname, zTabname);
+ if( zSql==0 ){
+ return SQLITE_NOMEM;
+ }
+ rc = sqlite3_exec(p->db, zSql, 0, 0, &zErr);
+ sqlite3_free(zSql);
+ if( (rc&0xff)==SQLITE_CORRUPT ){
+ *pzErr = sqlite3_mprintf("malformed inverted index for FTS%d table %s.%s",
+ p->bFts4 ? 4 : 3, zSchema, zTabname);
+ }else if( rc!=SQLITE_OK ){
+ *pzErr = sqlite3_mprintf("unable to validate the inverted index for"
+ " FTS%d table %s.%s: %s",
+ p->bFts4 ? 4 : 3, zSchema, zTabname, zErr);
+ }
+ sqlite3_free(zErr);
+ return SQLITE_OK;
+}
+
+
+
static const sqlite3_module fts3Module = {
- /* iVersion */ 3,
+ /* iVersion */ 4,
/* xCreate */ fts3CreateMethod,
/* xConnect */ fts3ConnectMethod,
/* xBestIndex */ fts3BestIndexMethod,
@@ -185644,6 +189608,7 @@ static const sqlite3_module fts3Module = {
/* xRelease */ fts3ReleaseMethod,
/* xRollbackTo */ fts3RollbackToMethod,
/* xShadowName */ fts3ShadowName,
+ /* xIntegrity */ fts3Integrity,
};
/*
@@ -188319,7 +192284,8 @@ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
int rc; /* Return code */
@@ -191885,7 +195851,8 @@ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash, void(*xDestr
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
int rc; /* Return code */
@@ -194568,16 +198535,18 @@ static int fts3MsrBufferData(
char *pList,
i64 nList
){
- if( nList>pMsr->nBuffer ){
+ if( (nList+FTS3_NODE_PADDING)>pMsr->nBuffer ){
char *pNew;
- pMsr->nBuffer = nList*2;
- pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, pMsr->nBuffer);
+ int nNew = nList*2 + FTS3_NODE_PADDING;
+ pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, nNew);
if( !pNew ) return SQLITE_NOMEM;
pMsr->aBuffer = pNew;
+ pMsr->nBuffer = nNew;
}
assert( nList>0 );
memcpy(pMsr->aBuffer, pList, nList);
+ memset(&pMsr->aBuffer[nList], 0, FTS3_NODE_PADDING);
return SQLITE_OK;
}
@@ -195224,7 +199193,6 @@ SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
rc = fts3SegmentMerge(p, p->iPrevLangid, i, FTS3_SEGCURSOR_PENDING);
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
}
- sqlite3Fts3PendingTermsClear(p);
/* Determine the auto-incr-merge setting if unknown. If enabled,
** estimate the number of leaf blocks of content to be written
@@ -195246,6 +199214,10 @@ SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
rc = sqlite3_reset(pStmt);
}
}
+
+ if( rc==SQLITE_OK ){
+ sqlite3Fts3PendingTermsClear(p);
+ }
return rc;
}
@@ -195877,6 +199849,8 @@ static int fts3AppendToNode(
blobGrowBuffer(pPrev, nTerm, &rc);
if( rc!=SQLITE_OK ) return rc;
+ assert( pPrev!=0 );
+ assert( pPrev->a!=0 );
nPrefix = fts3PrefixCompress(pPrev->a, pPrev->n, zTerm, nTerm);
nSuffix = nTerm - nPrefix;
@@ -195933,9 +199907,13 @@ static int fts3IncrmergeAppend(
nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist;
/* If the current block is not empty, and if adding this term/doclist
- ** to the current block would make it larger than Fts3Table.nNodeSize
- ** bytes, write this block out to the database. */
- if( pLeaf->block.n>0 && (pLeaf->block.n + nSpace)>p->nNodeSize ){
+ ** to the current block would make it larger than Fts3Table.nNodeSize bytes,
+ ** and if there is still room for another leaf page, write this block out to
+ ** the database. */
+ if( pLeaf->block.n>0
+ && (pLeaf->block.n + nSpace)>p->nNodeSize
+ && pLeaf->iBlock < (pWriter->iStart + pWriter->nLeafEst)
+ ){
rc = fts3WriteSegment(p, pLeaf->iBlock, pLeaf->block.a, pLeaf->block.n);
pWriter->nWork++;
@@ -196246,6 +200224,7 @@ static int fts3IncrmergeLoad(
for(i=nHeight; i>=0 && rc==SQLITE_OK; i--){
NodeReader reader;
+ memset(&reader, 0, sizeof(reader));
pNode = &pWriter->aNodeWriter[i];
if( pNode->block.a){
@@ -196266,7 +200245,7 @@ static int fts3IncrmergeLoad(
rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock,0);
blobGrowBuffer(&pNode->block,
MAX(nBlock, p->nNodeSize)+FTS3_NODE_PADDING, &rc
- );
+ );
if( rc==SQLITE_OK ){
memcpy(pNode->block.a, aBlock, nBlock);
pNode->block.n = nBlock;
@@ -197116,7 +201095,7 @@ static u64 fts3ChecksumIndex(
int rc;
u64 cksum = 0;
- assert( *pRc==SQLITE_OK );
+ if( *pRc ) return 0;
memset(&filter, 0, sizeof(filter));
memset(&csr, 0, sizeof(csr));
@@ -197331,8 +201310,11 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
rc = fts3DoIncrmerge(p, &zVal[6]);
}else if( nVal>10 && 0==sqlite3_strnicmp(zVal, "automerge=", 10) ){
rc = fts3DoAutoincrmerge(p, &zVal[10]);
+ }else if( nVal==5 && 0==sqlite3_strnicmp(zVal, "flush", 5) ){
+ rc = sqlite3Fts3PendingTermsFlush(p);
+ }
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
- }else{
+ else{
int v;
if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
v = atoi(&zVal[9]);
@@ -197350,8 +201332,8 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
if( v>=4 && v<=FTS3_MERGE_COUNT && (v&1)==0 ) p->nMergeCount = v;
rc = SQLITE_OK;
}
-#endif
}
+#endif
return rc;
}
@@ -200292,25 +204274,51 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){
** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
*/
static const char jsonIsSpace[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
#define fast_isspace(x) (jsonIsSpace[(unsigned char)x])
+/*
+** Characters that are special to JSON. Control charaters,
+** '"' and '\\'.
+*/
+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
+};
+
+
#if !defined(SQLITE_DEBUG) && !defined(SQLITE_COVERAGE_TEST)
# define VVA(X)
#else
@@ -200321,6 +204329,7 @@ static const char jsonIsSpace[] = {
typedef struct JsonString JsonString;
typedef struct JsonNode JsonNode;
typedef struct JsonParse JsonParse;
+typedef struct JsonCleanup JsonCleanup;
/* An instance of this object represents a JSON string
** under construction. Really, this is a generic string accumulator
@@ -200336,16 +204345,26 @@ struct JsonString {
char zSpace[100]; /* Initial static space */
};
+/* A deferred cleanup task. A list of JsonCleanup objects might be
+** run when the JsonParse object is destroyed.
+*/
+struct JsonCleanup {
+ JsonCleanup *pJCNext; /* Next in a list */
+ void (*xOp)(void*); /* Routine to run */
+ void *pArg; /* Argument to xOp() */
+};
+
/* JSON type values
*/
-#define JSON_NULL 0
-#define JSON_TRUE 1
-#define JSON_FALSE 2
-#define JSON_INT 3
-#define JSON_REAL 4
-#define JSON_STRING 5
-#define JSON_ARRAY 6
-#define JSON_OBJECT 7
+#define JSON_SUBST 0 /* Special edit node. Uses u.iPrev */
+#define JSON_NULL 1
+#define JSON_TRUE 2
+#define JSON_FALSE 3
+#define JSON_INT 4
+#define JSON_REAL 5
+#define JSON_STRING 6
+#define JSON_ARRAY 7
+#define JSON_OBJECT 8
/* The "subtype" set for JSON values */
#define JSON_SUBTYPE 74 /* Ascii for "J" */
@@ -200354,59 +204373,97 @@ struct JsonString {
** Names of the various JSON types:
*/
static const char * const jsonType[] = {
+ "subst",
"null", "true", "false", "integer", "real", "text", "array", "object"
};
/* Bit values for the JsonNode.jnFlag field
*/
-#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */
-#define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */
-#define JNODE_REMOVE 0x04 /* Do not output */
-#define JNODE_REPLACE 0x08 /* Replace with JsonNode.u.iReplace */
-#define JNODE_PATCH 0x10 /* Patch with JsonNode.u.pPatch */
-#define JNODE_APPEND 0x20 /* More ARRAY/OBJECT entries at u.iAppend */
-#define JNODE_LABEL 0x40 /* Is a label of an object */
+#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */
+#define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */
+#define JNODE_REMOVE 0x04 /* Do not output */
+#define JNODE_REPLACE 0x08 /* Target of a JSON_SUBST node */
+#define JNODE_APPEND 0x10 /* More ARRAY/OBJECT entries at u.iAppend */
+#define JNODE_LABEL 0x20 /* Is a label of an object */
+#define JNODE_JSON5 0x40 /* Node contains JSON5 enhancements */
-/* A single node of parsed JSON
+/* A single node of parsed JSON. An array of these nodes describes
+** a parse of JSON + edits.
+**
+** Use the json_parse() SQL function (available when compiled with
+** -DSQLITE_DEBUG) to see a dump of complete JsonParse objects, including
+** a complete listing and decoding of the array of JsonNodes.
*/
struct JsonNode {
u8 eType; /* One of the JSON_ type values */
u8 jnFlags; /* JNODE flags */
u8 eU; /* Which union element to use */
- u32 n; /* Bytes of content, or number of sub-nodes */
+ u32 n; /* Bytes of content for INT, REAL or STRING
+ ** Number of sub-nodes for ARRAY and OBJECT
+ ** Node that SUBST applies to */
union {
const char *zJContent; /* 1: Content for INT, REAL, and STRING */
u32 iAppend; /* 2: More terms for ARRAY and OBJECT */
u32 iKey; /* 3: Key for ARRAY objects in json_tree() */
- u32 iReplace; /* 4: Replacement content for JNODE_REPLACE */
- JsonNode *pPatch; /* 5: Node chain of patch for JNODE_PATCH */
+ u32 iPrev; /* 4: Previous SUBST node, or 0 */
} u;
};
-/* A completely parsed JSON string
+
+/* A parsed and possibly edited JSON string. Lifecycle:
+**
+** 1. JSON comes in and is parsed into an array aNode[]. The original
+** JSON text is stored in zJson.
+**
+** 2. Zero or more changes are made (via json_remove() or json_replace()
+** or similar) to the aNode[] array.
+**
+** 3. A new, edited and mimified JSON string is generated from aNode
+** and stored in zAlt. The JsonParse object always owns zAlt.
+**
+** Step 1 always happens. Step 2 and 3 may or may not happen, depending
+** on the operation.
+**
+** aNode[].u.zJContent entries typically point into zJson. Hence zJson
+** must remain valid for the lifespan of the parse. For edits,
+** aNode[].u.zJContent might point to malloced space other than zJson.
+** Entries in pClup are responsible for freeing that extra malloced space.
+**
+** When walking the parse tree in aNode[], edits are ignored if useMod is
+** false.
*/
struct JsonParse {
u32 nNode; /* Number of slots of aNode[] used */
u32 nAlloc; /* Number of slots of aNode[] allocated */
JsonNode *aNode; /* Array of nodes containing the parse */
- const char *zJson; /* Original JSON string */
+ char *zJson; /* Original JSON string (before edits) */
+ char *zAlt; /* Revised and/or mimified JSON */
u32 *aUp; /* Index of parent of each node */
- u8 oom; /* Set to true if out of memory */
- u8 nErr; /* Number of errors seen */
+ JsonCleanup *pClup;/* Cleanup operations prior to freeing this object */
u16 iDepth; /* Nesting depth */
+ u8 nErr; /* Number of errors seen */
+ u8 oom; /* Set to true if out of memory */
+ u8 bJsonIsRCStr; /* True if zJson is an RCStr */
+ u8 hasNonstd; /* True if input uses non-standard features like JSON5 */
+ u8 useMod; /* Actually use the edits contain inside aNode */
+ u8 hasMod; /* aNode contains edits from the original zJson */
+ u32 nJPRef; /* Number of references to this object */
int nJson; /* Length of the zJson string in bytes */
- u32 iHold; /* Replace cache line with the lowest iHold value */
+ int nAlt; /* Length of alternative JSON string zAlt, in bytes */
+ u32 iErr; /* Error location in zJson[] */
+ u32 iSubst; /* Last JSON_SUBST entry in aNode[] */
+ u32 iHold; /* Age of this entry in the cache for LRU replacement */
};
/*
** Maximum nesting depth of JSON for this implementation.
**
** This limit is needed to avoid a stack overflow in the recursive
-** descent parser. A depth of 2000 is far deeper than any sane JSON
-** should go.
+** descent parser. A depth of 1000 is far deeper than any sane JSON
+** should go. Historical note: This limit was 2000 prior to version 3.42.0
*/
-#define JSON_MAX_DEPTH 2000
+#define JSON_MAX_DEPTH 1000
/**************************************************************************
** Utility routines for dealing with JsonString objects
@@ -200429,16 +204486,14 @@ static void jsonInit(JsonString *p, sqlite3_context *pCtx){
jsonZero(p);
}
-
/* Free all allocated memory and reset the JsonString object back to its
** initial state.
*/
static void jsonReset(JsonString *p){
- if( !p->bStatic ) sqlite3_free(p->zBuf);
+ if( !p->bStatic ) sqlite3RCStrUnref(p->zBuf);
jsonZero(p);
}
-
/* Report an out-of-memory (OOM) condition
*/
static void jsonOom(JsonString *p){
@@ -200455,7 +204510,7 @@ static int jsonGrow(JsonString *p, u32 N){
char *zNew;
if( p->bStatic ){
if( p->bErr ) return 1;
- zNew = sqlite3_malloc64(nTotal);
+ zNew = sqlite3RCStrNew(nTotal);
if( zNew==0 ){
jsonOom(p);
return SQLITE_NOMEM;
@@ -200464,12 +204519,12 @@ static int jsonGrow(JsonString *p, u32 N){
p->zBuf = zNew;
p->bStatic = 0;
}else{
- zNew = sqlite3_realloc64(p->zBuf, nTotal);
- if( zNew==0 ){
- jsonOom(p);
+ p->zBuf = sqlite3RCStrResize(p->zBuf, nTotal);
+ if( p->zBuf==0 ){
+ p->bErr = 1;
+ jsonZero(p);
return SQLITE_NOMEM;
}
- p->zBuf = zNew;
}
p->nAlloc = nTotal;
return SQLITE_OK;
@@ -200477,12 +204532,35 @@ static int jsonGrow(JsonString *p, u32 N){
/* Append N bytes from zIn onto the end of the JsonString string.
*/
-static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
- if( N==0 ) return;
- if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
+static SQLITE_NOINLINE void jsonAppendExpand(
+ JsonString *p,
+ const char *zIn,
+ u32 N
+){
+ assert( N>0 );
+ if( jsonGrow(p,N) ) return;
memcpy(p->zBuf+p->nUsed, zIn, N);
p->nUsed += N;
}
+static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
+ if( N==0 ) return;
+ if( N+p->nUsed >= p->nAlloc ){
+ jsonAppendExpand(p,zIn,N);
+ }else{
+ memcpy(p->zBuf+p->nUsed, zIn, N);
+ p->nUsed += N;
+ }
+}
+static void jsonAppendRawNZ(JsonString *p, const char *zIn, u32 N){
+ assert( N>0 );
+ if( N+p->nUsed >= p->nAlloc ){
+ jsonAppendExpand(p,zIn,N);
+ }else{
+ memcpy(p->zBuf+p->nUsed, zIn, N);
+ p->nUsed += N;
+ }
+}
+
/* Append formatted text (not to exceed N bytes) to the JsonString.
*/
@@ -200497,10 +204575,35 @@ static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
/* Append a single character
*/
-static void jsonAppendChar(JsonString *p, char c){
- if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return;
+static SQLITE_NOINLINE void jsonAppendCharExpand(JsonString *p, char c){
+ if( jsonGrow(p,1) ) return;
p->zBuf[p->nUsed++] = c;
}
+static void jsonAppendChar(JsonString *p, char c){
+ if( p->nUsed>=p->nAlloc ){
+ jsonAppendCharExpand(p,c);
+ }else{
+ p->zBuf[p->nUsed++] = c;
+ }
+}
+
+/* Try to force the string to be a zero-terminated RCStr string.
+**
+** Return true on success. Return false if an OOM prevents this
+** from happening.
+*/
+static int jsonForceRCStr(JsonString *p){
+ jsonAppendChar(p, 0);
+ if( p->bErr ) return 0;
+ p->nUsed--;
+ if( p->bStatic==0 ) return 1;
+ p->nAlloc = 0;
+ p->nUsed++;
+ jsonGrow(p, p->nUsed);
+ p->nUsed--;
+ return p->bStatic==0;
+}
+
/* Append a comma separator to the output buffer, if the previous
** character is not '[' or '{'.
@@ -200509,7 +204612,8 @@ static void jsonAppendSeparator(JsonString *p){
char c;
if( p->nUsed==0 ) return;
c = p->zBuf[p->nUsed-1];
- if( c!='[' && c!='{' ) jsonAppendChar(p, ',');
+ if( c=='[' || c=='{' ) return;
+ jsonAppendChar(p, ',');
}
/* Append the N-byte string in zIn to the end of the JsonString string
@@ -200523,11 +204627,16 @@ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
p->zBuf[p->nUsed++] = '"';
for(i=0; izBuf[p->nUsed++] = c;
+ }else if( c=='"' || c=='\\' ){
json_simple_escape:
if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return;
p->zBuf[p->nUsed++] = '\\';
- }else if( c<=0x1f ){
+ p->zBuf[p->nUsed++] = c;
+ }else if( c=='\'' ){
+ p->zBuf[p->nUsed++] = c;
+ }else{
static const char aSpecial[] = {
0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
@@ -200538,6 +204647,7 @@ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
assert( aSpecial['\n']=='n' );
assert( aSpecial['\r']=='r' );
assert( aSpecial['\t']=='t' );
+ assert( c>=0 && czBuf[p->nUsed++] = 'u';
p->zBuf[p->nUsed++] = '0';
p->zBuf[p->nUsed++] = '0';
- p->zBuf[p->nUsed++] = '0' + (c>>4);
- c = "0123456789abcdef"[c&0xf];
+ p->zBuf[p->nUsed++] = "0123456789abcdef"[c>>4];
+ p->zBuf[p->nUsed++] = "0123456789abcdef"[c&0xf];
}
- p->zBuf[p->nUsed++] = c;
}
p->zBuf[p->nUsed++] = '"';
assert( p->nUsednAlloc );
}
+/*
+** The zIn[0..N] string is a JSON5 string literal. Append to p a translation
+** of the string literal that standard JSON and that omits all JSON5
+** features.
+*/
+static void jsonAppendNormalizedString(JsonString *p, const char *zIn, u32 N){
+ u32 i;
+ jsonAppendChar(p, '"');
+ zIn++;
+ N -= 2;
+ while( N>0 ){
+ for(i=0; i0 ){
+ jsonAppendRawNZ(p, zIn, i);
+ zIn += i;
+ N -= i;
+ if( N==0 ) break;
+ }
+ assert( zIn[0]=='\\' );
+ switch( (u8)zIn[1] ){
+ case '\'':
+ jsonAppendChar(p, '\'');
+ break;
+ case 'v':
+ jsonAppendRawNZ(p, "\\u0009", 6);
+ break;
+ case 'x':
+ jsonAppendRawNZ(p, "\\u00", 4);
+ jsonAppendRawNZ(p, &zIn[2], 2);
+ zIn += 2;
+ N -= 2;
+ break;
+ case '0':
+ jsonAppendRawNZ(p, "\\u0000", 6);
+ break;
+ case '\r':
+ if( zIn[2]=='\n' ){
+ zIn++;
+ N--;
+ }
+ break;
+ case '\n':
+ break;
+ case 0xe2:
+ assert( N>=4 );
+ assert( 0x80==(u8)zIn[2] );
+ assert( 0xa8==(u8)zIn[3] || 0xa9==(u8)zIn[3] );
+ zIn += 2;
+ N -= 2;
+ break;
+ default:
+ jsonAppendRawNZ(p, zIn, 2);
+ break;
+ }
+ zIn += 2;
+ N -= 2;
+ }
+ jsonAppendChar(p, '"');
+}
+
+/*
+** The zIn[0..N] string is a JSON5 integer literal. Append to p a translation
+** of the string literal that standard JSON and that omits all JSON5
+** features.
+*/
+static void jsonAppendNormalizedInt(JsonString *p, const char *zIn, u32 N){
+ if( zIn[0]=='+' ){
+ zIn++;
+ N--;
+ }else if( zIn[0]=='-' ){
+ jsonAppendChar(p, '-');
+ zIn++;
+ N--;
+ }
+ if( zIn[0]=='0' && (zIn[1]=='x' || zIn[1]=='X') ){
+ sqlite3_int64 i = 0;
+ int rc = sqlite3DecOrHexToI64(zIn, &i);
+ if( rc<=1 ){
+ jsonPrintf(100,p,"%lld",i);
+ }else{
+ assert( rc==2 );
+ jsonAppendRawNZ(p, "9.0e999", 7);
+ }
+ return;
+ }
+ assert( N>0 );
+ jsonAppendRawNZ(p, zIn, N);
+}
+
+/*
+** The zIn[0..N] string is a JSON5 real literal. Append to p a translation
+** of the string literal that standard JSON and that omits all JSON5
+** features.
+*/
+static void jsonAppendNormalizedReal(JsonString *p, const char *zIn, u32 N){
+ u32 i;
+ if( zIn[0]=='+' ){
+ zIn++;
+ N--;
+ }else if( zIn[0]=='-' ){
+ jsonAppendChar(p, '-');
+ zIn++;
+ N--;
+ }
+ if( zIn[0]=='.' ){
+ jsonAppendChar(p, '0');
+ }
+ for(i=0; i0 ){
+ jsonAppendRawNZ(p, zIn, N);
+ }
+}
+
+
+
/*
** Append a function parameter value to the JSON string under
** construction.
@@ -200566,11 +204799,14 @@ static void jsonAppendValue(
){
switch( sqlite3_value_type(pValue) ){
case SQLITE_NULL: {
- jsonAppendRaw(p, "null", 4);
+ jsonAppendRawNZ(p, "null", 4);
break;
}
- case SQLITE_INTEGER:
case SQLITE_FLOAT: {
+ jsonPrintf(100, p, "%!0.15g", sqlite3_value_double(pValue));
+ break;
+ }
+ case SQLITE_INTEGER: {
const char *z = (const char*)sqlite3_value_text(pValue);
u32 n = (u32)sqlite3_value_bytes(pValue);
jsonAppendRaw(p, z, n);
@@ -200599,15 +204835,25 @@ static void jsonAppendValue(
/* Make the JSON in p the result of the SQL function.
+**
+** The JSON string is reset.
*/
static void jsonResult(JsonString *p){
if( p->bErr==0 ){
- sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
- p->bStatic ? SQLITE_TRANSIENT : sqlite3_free,
- SQLITE_UTF8);
- jsonZero(p);
+ if( p->bStatic ){
+ sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
+ SQLITE_TRANSIENT, SQLITE_UTF8);
+ }else if( jsonForceRCStr(p) ){
+ sqlite3RCStrRef(p->zBuf);
+ sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
+ sqlite3RCStrUnref,
+ SQLITE_UTF8);
+ }
+ }
+ if( p->bErr==1 ){
+ sqlite3_result_error_nomem(p->pCtx);
}
- assert( p->bStatic );
+ jsonReset(p);
}
/**************************************************************************
@@ -200632,20 +204878,73 @@ static u32 jsonNodeSize(JsonNode *pNode){
** delete the JsonParse object itself.
*/
static void jsonParseReset(JsonParse *pParse){
- sqlite3_free(pParse->aNode);
- pParse->aNode = 0;
+ while( pParse->pClup ){
+ JsonCleanup *pTask = pParse->pClup;
+ pParse->pClup = pTask->pJCNext;
+ pTask->xOp(pTask->pArg);
+ sqlite3_free(pTask);
+ }
+ assert( pParse->nJPRef<=1 );
+ if( pParse->aNode ){
+ sqlite3_free(pParse->aNode);
+ pParse->aNode = 0;
+ }
pParse->nNode = 0;
pParse->nAlloc = 0;
- sqlite3_free(pParse->aUp);
- pParse->aUp = 0;
+ if( pParse->aUp ){
+ sqlite3_free(pParse->aUp);
+ pParse->aUp = 0;
+ }
+ if( pParse->bJsonIsRCStr ){
+ sqlite3RCStrUnref(pParse->zJson);
+ pParse->zJson = 0;
+ pParse->bJsonIsRCStr = 0;
+ }
+ if( pParse->zAlt ){
+ sqlite3RCStrUnref(pParse->zAlt);
+ pParse->zAlt = 0;
+ }
}
/*
** Free a JsonParse object that was obtained from sqlite3_malloc().
+**
+** Note that destroying JsonParse might call sqlite3RCStrUnref() to
+** destroy the zJson value. The RCStr object might recursively invoke
+** JsonParse to destroy this pParse object again. Take care to ensure
+** that this recursive destructor sequence terminates harmlessly.
*/
static void jsonParseFree(JsonParse *pParse){
- jsonParseReset(pParse);
- sqlite3_free(pParse);
+ if( pParse->nJPRef>1 ){
+ pParse->nJPRef--;
+ }else{
+ jsonParseReset(pParse);
+ sqlite3_free(pParse);
+ }
+}
+
+/*
+** Add a cleanup task to the JsonParse object.
+**
+** If an OOM occurs, the cleanup operation happens immediately
+** and this function returns SQLITE_NOMEM.
+*/
+static int jsonParseAddCleanup(
+ JsonParse *pParse, /* Add the cleanup task to this parser */
+ void(*xOp)(void*), /* The cleanup task */
+ void *pArg /* Argument to the cleanup */
+){
+ JsonCleanup *pTask = sqlite3_malloc64( sizeof(*pTask) );
+ if( pTask==0 ){
+ pParse->oom = 1;
+ xOp(pArg);
+ return SQLITE_ERROR;
+ }
+ pTask->pJCNext = pParse->pClup;
+ pParse->pClup = pTask;
+ pTask->xOp = xOp;
+ pTask->pArg = pArg;
+ return SQLITE_OK;
}
/*
@@ -200654,46 +204953,76 @@ static void jsonParseFree(JsonParse *pParse){
** the number of JsonNode objects that are encoded.
*/
static void jsonRenderNode(
+ JsonParse *pParse, /* the complete parse of the JSON */
JsonNode *pNode, /* The node to render */
- JsonString *pOut, /* Write JSON here */
- sqlite3_value **aReplace /* Replacement values */
+ JsonString *pOut /* Write JSON here */
){
assert( pNode!=0 );
- if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){
- if( (pNode->jnFlags & JNODE_REPLACE)!=0 && ALWAYS(aReplace!=0) ){
- assert( pNode->eU==4 );
- jsonAppendValue(pOut, aReplace[pNode->u.iReplace]);
- return;
+ while( (pNode->jnFlags & JNODE_REPLACE)!=0 && pParse->useMod ){
+ u32 idx = (u32)(pNode - pParse->aNode);
+ u32 i = pParse->iSubst;
+ while( 1 /*exit-by-break*/ ){
+ assert( inNode );
+ assert( pParse->aNode[i].eType==JSON_SUBST );
+ assert( pParse->aNode[i].eU==4 );
+ assert( pParse->aNode[i].u.iPrevaNode[i].n==idx ){
+ pNode = &pParse->aNode[i+1];
+ break;
+ }
+ i = pParse->aNode[i].u.iPrev;
}
- assert( pNode->eU==5 );
- pNode = pNode->u.pPatch;
}
switch( pNode->eType ){
default: {
assert( pNode->eType==JSON_NULL );
- jsonAppendRaw(pOut, "null", 4);
+ jsonAppendRawNZ(pOut, "null", 4);
break;
}
case JSON_TRUE: {
- jsonAppendRaw(pOut, "true", 4);
+ jsonAppendRawNZ(pOut, "true", 4);
break;
}
case JSON_FALSE: {
- jsonAppendRaw(pOut, "false", 5);
+ jsonAppendRawNZ(pOut, "false", 5);
break;
}
case JSON_STRING: {
+ assert( pNode->eU==1 );
if( pNode->jnFlags & JNODE_RAW ){
- assert( pNode->eU==1 );
- jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
- break;
+ if( pNode->jnFlags & JNODE_LABEL ){
+ jsonAppendChar(pOut, '"');
+ jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
+ jsonAppendChar(pOut, '"');
+ }else{
+ jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
+ }
+ }else if( pNode->jnFlags & JNODE_JSON5 ){
+ jsonAppendNormalizedString(pOut, pNode->u.zJContent, pNode->n);
+ }else{
+ assert( pNode->n>0 );
+ jsonAppendRawNZ(pOut, pNode->u.zJContent, pNode->n);
}
- /* no break */ deliberate_fall_through
+ break;
+ }
+ case JSON_REAL: {
+ assert( pNode->eU==1 );
+ if( pNode->jnFlags & JNODE_JSON5 ){
+ jsonAppendNormalizedReal(pOut, pNode->u.zJContent, pNode->n);
+ }else{
+ assert( pNode->n>0 );
+ jsonAppendRawNZ(pOut, pNode->u.zJContent, pNode->n);
+ }
+ break;
}
- case JSON_REAL:
case JSON_INT: {
assert( pNode->eU==1 );
- jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
+ if( pNode->jnFlags & JNODE_JSON5 ){
+ jsonAppendNormalizedInt(pOut, pNode->u.zJContent, pNode->n);
+ }else{
+ assert( pNode->n>0 );
+ jsonAppendRawNZ(pOut, pNode->u.zJContent, pNode->n);
+ }
break;
}
case JSON_ARRAY: {
@@ -200701,15 +205030,16 @@ static void jsonRenderNode(
jsonAppendChar(pOut, '[');
for(;;){
while( j<=pNode->n ){
- if( (pNode[j].jnFlags & JNODE_REMOVE)==0 ){
+ if( (pNode[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ){
jsonAppendSeparator(pOut);
- jsonRenderNode(&pNode[j], pOut, aReplace);
+ jsonRenderNode(pParse, &pNode[j], pOut);
}
j += jsonNodeSize(&pNode[j]);
}
if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
+ if( pParse->useMod==0 ) break;
assert( pNode->eU==2 );
- pNode = &pNode[pNode->u.iAppend];
+ pNode = &pParse->aNode[pNode->u.iAppend];
j = 1;
}
jsonAppendChar(pOut, ']');
@@ -200720,17 +205050,18 @@ static void jsonRenderNode(
jsonAppendChar(pOut, '{');
for(;;){
while( j<=pNode->n ){
- if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){
+ if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ){
jsonAppendSeparator(pOut);
- jsonRenderNode(&pNode[j], pOut, aReplace);
+ jsonRenderNode(pParse, &pNode[j], pOut);
jsonAppendChar(pOut, ':');
- jsonRenderNode(&pNode[j+1], pOut, aReplace);
+ jsonRenderNode(pParse, &pNode[j+1], pOut);
}
j += 1 + jsonNodeSize(&pNode[j+1]);
}
if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
+ if( pParse->useMod==0 ) break;
assert( pNode->eU==2 );
- pNode = &pNode[pNode->u.iAppend];
+ pNode = &pParse->aNode[pNode->u.iAppend];
j = 1;
}
jsonAppendChar(pOut, '}');
@@ -200740,18 +205071,29 @@ static void jsonRenderNode(
}
/*
-** Return a JsonNode and all its descendents as a JSON string.
+** Return a JsonNode and all its descendants as a JSON string.
*/
static void jsonReturnJson(
+ JsonParse *pParse, /* The complete JSON */
JsonNode *pNode, /* Node to return */
sqlite3_context *pCtx, /* Return value for this function */
- sqlite3_value **aReplace /* Array of replacement values */
+ int bGenerateAlt /* Also store the rendered text in zAlt */
){
JsonString s;
- jsonInit(&s, pCtx);
- jsonRenderNode(pNode, &s, aReplace);
- jsonResult(&s);
- sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
+ if( pParse->oom ){
+ sqlite3_result_error_nomem(pCtx);
+ return;
+ }
+ if( pParse->nErr==0 ){
+ jsonInit(&s, pCtx);
+ jsonRenderNode(pParse, pNode, &s);
+ if( bGenerateAlt && pParse->zAlt==0 && jsonForceRCStr(&s) ){
+ pParse->zAlt = sqlite3RCStrRef(s.zBuf);
+ pParse->nAlt = s.nUsed;
+ }
+ jsonResult(&s);
+ sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
+ }
}
/*
@@ -200789,9 +205131,9 @@ static u32 jsonHexToInt4(const char *z){
** Make the JsonNode the return value of the function.
*/
static void jsonReturn(
+ JsonParse *pParse, /* Complete JSON parse tree */
JsonNode *pNode, /* Node to return */
- sqlite3_context *pCtx, /* Return value for this function */
- sqlite3_value **aReplace /* Array of replacement values */
+ sqlite3_context *pCtx /* Return value for this function */
){
switch( pNode->eType ){
default: {
@@ -200809,59 +205151,40 @@ static void jsonReturn(
}
case JSON_INT: {
sqlite3_int64 i = 0;
+ int rc;
+ int bNeg = 0;
const char *z;
+
assert( pNode->eU==1 );
z = pNode->u.zJContent;
- if( z[0]=='-' ){ z++; }
- while( z[0]>='0' && z[0]<='9' ){
- unsigned v = *(z++) - '0';
- if( i>=LARGEST_INT64/10 ){
- if( i>LARGEST_INT64/10 ) goto int_as_real;
- if( z[0]>='0' && z[0]<='9' ) goto int_as_real;
- if( v==9 ) goto int_as_real;
- if( v==8 ){
- if( pNode->u.zJContent[0]=='-' ){
- sqlite3_result_int64(pCtx, SMALLEST_INT64);
- goto int_done;
- }else{
- goto int_as_real;
- }
- }
- }
- i = i*10 + v;
+ if( z[0]=='-' ){ z++; bNeg = 1; }
+ else if( z[0]=='+' ){ z++; }
+ rc = sqlite3DecOrHexToI64(z, &i);
+ if( rc<=1 ){
+ sqlite3_result_int64(pCtx, bNeg ? -i : i);
+ }else if( rc==3 && bNeg ){
+ sqlite3_result_int64(pCtx, SMALLEST_INT64);
+ }else{
+ goto to_double;
}
- if( pNode->u.zJContent[0]=='-' ){ i = -i; }
- sqlite3_result_int64(pCtx, i);
- int_done:
break;
- int_as_real: ; /* no break */ deliberate_fall_through
}
case JSON_REAL: {
double r;
-#ifdef SQLITE_AMALGAMATION
const char *z;
assert( pNode->eU==1 );
+ to_double:
z = pNode->u.zJContent;
sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
-#else
- assert( pNode->eU==1 );
- r = strtod(pNode->u.zJContent, 0);
-#endif
sqlite3_result_double(pCtx, r);
break;
}
case JSON_STRING: {
-#if 0 /* Never happens because JNODE_RAW is only set by json_set(),
- ** json_insert() and json_replace() and those routines do not
- ** call jsonReturn() */
if( pNode->jnFlags & JNODE_RAW ){
assert( pNode->eU==1 );
sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n,
SQLITE_TRANSIENT);
- }else
-#endif
- assert( (pNode->jnFlags & JNODE_RAW)==0 );
- if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
+ }else if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
/* JSON formatted without any backslash-escapes */
assert( pNode->eU==1 );
sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2,
@@ -200873,18 +205196,17 @@ static void jsonReturn(
const char *z;
char *zOut;
u32 j;
+ u32 nOut = n;
assert( pNode->eU==1 );
z = pNode->u.zJContent;
- zOut = sqlite3_malloc( n+1 );
+ zOut = sqlite3_malloc( nOut+1 );
if( zOut==0 ){
sqlite3_result_error_nomem(pCtx);
break;
}
for(i=1, j=0; iaNode after first expanding the
+** size of the aNode array. Return the index of the new node.
+**
+** If an OOM error occurs, set pParse->oom and return -1.
+*/
static JSON_NOINLINE int jsonParseAddNodeExpand(
JsonParse *pParse, /* Append the node to this object */
u32 eType, /* Node type */
@@ -200977,7 +205323,7 @@ static JSON_NOINLINE int jsonParseAddNodeExpand(
pParse->oom = 1;
return -1;
}
- pParse->nAlloc = nNew;
+ pParse->nAlloc = sqlite3_msize(pNew)/sizeof(JsonNode);
pParse->aNode = pNew;
assert( pParse->nNodenAlloc );
return jsonParseAddNode(pParse, eType, n, zContent);
@@ -200995,34 +205341,239 @@ static int jsonParseAddNode(
const char *zContent /* Content */
){
JsonNode *p;
- if( pParse->aNode==0 || pParse->nNode>=pParse->nAlloc ){
+ assert( pParse->aNode!=0 || pParse->nNode>=pParse->nAlloc );
+ if( pParse->nNode>=pParse->nAlloc ){
return jsonParseAddNodeExpand(pParse, eType, n, zContent);
}
+ assert( pParse->aNode!=0 );
p = &pParse->aNode[pParse->nNode];
- p->eType = (u8)eType;
- p->jnFlags = 0;
+ assert( p!=0 );
+ p->eType = (u8)(eType & 0xff);
+ p->jnFlags = (u8)(eType >> 8);
VVA( p->eU = zContent ? 1 : 0 );
p->n = n;
p->u.zJContent = zContent;
return pParse->nNode++;
}
+/*
+** Add an array of new nodes to the current pParse->aNode array.
+** Return the index of the first node added.
+**
+** If an OOM error occurs, set pParse->oom.
+*/
+static void jsonParseAddNodeArray(
+ JsonParse *pParse, /* Append the node to this object */
+ JsonNode *aNode, /* Array of nodes to add */
+ u32 nNode /* Number of elements in aNew */
+){
+ assert( aNode!=0 );
+ assert( nNode>=1 );
+ if( pParse->nNode + nNode > pParse->nAlloc ){
+ u32 nNew = pParse->nNode + nNode;
+ JsonNode *aNew = sqlite3_realloc64(pParse->aNode, nNew*sizeof(JsonNode));
+ if( aNew==0 ){
+ pParse->oom = 1;
+ return;
+ }
+ pParse->nAlloc = sqlite3_msize(aNew)/sizeof(JsonNode);
+ pParse->aNode = aNew;
+ }
+ memcpy(&pParse->aNode[pParse->nNode], aNode, nNode*sizeof(JsonNode));
+ pParse->nNode += nNode;
+}
+
+/*
+** Add a new JSON_SUBST node. The node immediately following
+** this new node will be the substitute content for iNode.
+*/
+static int jsonParseAddSubstNode(
+ JsonParse *pParse, /* Add the JSON_SUBST here */
+ u32 iNode /* References this node */
+){
+ int idx = jsonParseAddNode(pParse, JSON_SUBST, iNode, 0);
+ if( pParse->oom ) return -1;
+ pParse->aNode[iNode].jnFlags |= JNODE_REPLACE;
+ pParse->aNode[idx].eU = 4;
+ pParse->aNode[idx].u.iPrev = pParse->iSubst;
+ pParse->iSubst = idx;
+ pParse->hasMod = 1;
+ pParse->useMod = 1;
+ return idx;
+}
+
+/*
+** Return true if z[] begins with 2 (or more) hexadecimal digits
+*/
+static int jsonIs2Hex(const char *z){
+ return sqlite3Isxdigit(z[0]) && sqlite3Isxdigit(z[1]);
+}
+
/*
** Return true if z[] begins with 4 (or more) hexadecimal digits
*/
static int jsonIs4Hex(const char *z){
- int i;
- for(i=0; i<4; i++) if( !sqlite3Isxdigit(z[i]) ) return 0;
- return 1;
+ return jsonIs2Hex(z) && jsonIs2Hex(&z[2]);
+}
+
+/*
+** Return the number of bytes of JSON5 whitespace at the beginning of
+** the input string z[].
+**
+** JSON5 whitespace consists of any of the following characters:
+**
+** Unicode UTF-8 Name
+** U+0009 09 horizontal tab
+** U+000a 0a line feed
+** U+000b 0b vertical tab
+** U+000c 0c form feed
+** U+000d 0d carriage return
+** U+0020 20 space
+** U+00a0 c2 a0 non-breaking space
+** U+1680 e1 9a 80 ogham space mark
+** U+2000 e2 80 80 en quad
+** U+2001 e2 80 81 em quad
+** U+2002 e2 80 82 en space
+** U+2003 e2 80 83 em space
+** U+2004 e2 80 84 three-per-em space
+** U+2005 e2 80 85 four-per-em space
+** U+2006 e2 80 86 six-per-em space
+** U+2007 e2 80 87 figure space
+** U+2008 e2 80 88 punctuation space
+** U+2009 e2 80 89 thin space
+** U+200a e2 80 8a hair space
+** U+2028 e2 80 a8 line separator
+** U+2029 e2 80 a9 paragraph separator
+** U+202f e2 80 af narrow no-break space (NNBSP)
+** U+205f e2 81 9f medium mathematical space (MMSP)
+** U+3000 e3 80 80 ideographical space
+** U+FEFF ef bb bf byte order mark
+**
+** In addition, comments between '/', '*' and '*', '/' and
+** from '/', '/' to end-of-line are also considered to be whitespace.
+*/
+static int json5Whitespace(const char *zIn){
+ int n = 0;
+ const u8 *z = (u8*)zIn;
+ while( 1 /*exit by "goto whitespace_done"*/ ){
+ switch( z[n] ){
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x20: {
+ n++;
+ break;
+ }
+ case '/': {
+ if( z[n+1]=='*' && z[n+2]!=0 ){
+ int j;
+ for(j=n+3; z[j]!='/' || z[j-1]!='*'; j++){
+ if( z[j]==0 ) goto whitespace_done;
+ }
+ n = j+1;
+ break;
+ }else if( z[n+1]=='/' ){
+ int j;
+ char c;
+ for(j=n+2; (c = z[j])!=0; j++){
+ if( c=='\n' || c=='\r' ) break;
+ if( 0xe2==(u8)c && 0x80==(u8)z[j+1]
+ && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2])
+ ){
+ j += 2;
+ break;
+ }
+ }
+ n = j;
+ if( z[n] ) n++;
+ break;
+ }
+ goto whitespace_done;
+ }
+ case 0xc2: {
+ if( z[n+1]==0xa0 ){
+ n += 2;
+ break;
+ }
+ goto whitespace_done;
+ }
+ case 0xe1: {
+ if( z[n+1]==0x9a && z[n+2]==0x80 ){
+ n += 3;
+ break;
+ }
+ goto whitespace_done;
+ }
+ case 0xe2: {
+ if( z[n+1]==0x80 ){
+ u8 c = z[n+2];
+ if( c<0x80 ) goto whitespace_done;
+ if( c<=0x8a || c==0xa8 || c==0xa9 || c==0xaf ){
+ n += 3;
+ break;
+ }
+ }else if( z[n+1]==0x81 && z[n+2]==0x9f ){
+ n += 3;
+ break;
+ }
+ goto whitespace_done;
+ }
+ case 0xe3: {
+ if( z[n+1]==0x80 && z[n+2]==0x80 ){
+ n += 3;
+ break;
+ }
+ goto whitespace_done;
+ }
+ case 0xef: {
+ if( z[n+1]==0xbb && z[n+2]==0xbf ){
+ n += 3;
+ break;
+ }
+ goto whitespace_done;
+ }
+ default: {
+ goto whitespace_done;
+ }
+ }
+ }
+ whitespace_done:
+ return n;
}
+/*
+** Extra floating-point literals to allow in JSON.
+*/
+static const struct NanInfName {
+ char c1;
+ char c2;
+ char n;
+ char eType;
+ char nRepl;
+ char *zMatch;
+ char *zRepl;
+} aNanInfName[] = {
+ { 'i', 'I', 3, JSON_REAL, 7, "inf", "9.0e999" },
+ { 'i', 'I', 8, JSON_REAL, 7, "infinity", "9.0e999" },
+ { 'n', 'N', 3, JSON_NULL, 4, "NaN", "null" },
+ { 'q', 'Q', 4, JSON_NULL, 4, "QNaN", "null" },
+ { 's', 'S', 4, JSON_NULL, 4, "SNaN", "null" },
+};
+
/*
** Parse a single JSON value which begins at pParse->zJson[i]. Return the
** index of the first character past the end of the value parsed.
**
-** Return negative for a syntax error. Special cases: return -2 if the
-** first non-whitespace character is '}' and return -3 if the first
-** non-whitespace character is ']'.
+** Special return values:
+**
+** 0 End of input
+** -1 Syntax error
+** -2 '}' seen
+** -3 ']' seen
+** -4 ',' seen
+** -5 ':' seen
*/
static int jsonParseValue(JsonParse *pParse, u32 i){
char c;
@@ -201031,175 +205582,457 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
int x;
JsonNode *pNode;
const char *z = pParse->zJson;
- while( fast_isspace(z[i]) ){ i++; }
- if( (c = z[i])=='{' ){
+json_parse_restart:
+ switch( (u8)z[i] ){
+ case '{': {
/* Parse object */
iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
if( iThis<0 ) return -1;
+ if( ++pParse->iDepth > JSON_MAX_DEPTH ){
+ pParse->iErr = i;
+ return -1;
+ }
for(j=i+1;;j++){
- while( fast_isspace(z[j]) ){ j++; }
- if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
+ u32 nNode = pParse->nNode;
x = jsonParseValue(pParse, j);
- if( x<0 ){
- pParse->iDepth--;
- if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
- return -1;
+ if( x<=0 ){
+ if( x==(-2) ){
+ j = pParse->iErr;
+ if( pParse->nNode!=(u32)iThis+1 ) pParse->hasNonstd = 1;
+ break;
+ }
+ j += json5Whitespace(&z[j]);
+ if( sqlite3JsonId1(z[j])
+ || (z[j]=='\\' && z[j+1]=='u' && jsonIs4Hex(&z[j+2]))
+ ){
+ int k = j+1;
+ while( (sqlite3JsonId2(z[k]) && json5Whitespace(&z[k])==0)
+ || (z[k]=='\\' && z[k+1]=='u' && jsonIs4Hex(&z[k+2]))
+ ){
+ k++;
+ }
+ jsonParseAddNode(pParse, JSON_STRING | (JNODE_RAW<<8), k-j, &z[j]);
+ pParse->hasNonstd = 1;
+ x = k;
+ }else{
+ if( x!=-1 ) pParse->iErr = j;
+ return -1;
+ }
}
if( pParse->oom ) return -1;
- pNode = &pParse->aNode[pParse->nNode-1];
- if( pNode->eType!=JSON_STRING ) return -1;
+ pNode = &pParse->aNode[nNode];
+ if( pNode->eType!=JSON_STRING ){
+ pParse->iErr = j;
+ return -1;
+ }
pNode->jnFlags |= JNODE_LABEL;
j = x;
- while( fast_isspace(z[j]) ){ j++; }
- if( z[j]!=':' ) return -1;
- j++;
+ if( z[j]==':' ){
+ j++;
+ }else{
+ if( fast_isspace(z[j]) ){
+ do{ j++; }while( fast_isspace(z[j]) );
+ if( z[j]==':' ){
+ j++;
+ goto parse_object_value;
+ }
+ }
+ x = jsonParseValue(pParse, j);
+ if( x!=(-5) ){
+ if( x!=(-1) ) pParse->iErr = j;
+ return -1;
+ }
+ j = pParse->iErr+1;
+ }
+ parse_object_value:
x = jsonParseValue(pParse, j);
- pParse->iDepth--;
- if( x<0 ) return -1;
+ if( x<=0 ){
+ if( x!=(-1) ) pParse->iErr = j;
+ return -1;
+ }
j = x;
- while( fast_isspace(z[j]) ){ j++; }
- c = z[j];
- if( c==',' ) continue;
- if( c!='}' ) return -1;
- break;
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]=='}' ){
+ break;
+ }else{
+ if( fast_isspace(z[j]) ){
+ do{ j++; }while( fast_isspace(z[j]) );
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]=='}' ){
+ break;
+ }
+ }
+ x = jsonParseValue(pParse, j);
+ if( x==(-4) ){
+ j = pParse->iErr;
+ continue;
+ }
+ if( x==(-2) ){
+ j = pParse->iErr;
+ break;
+ }
+ }
+ pParse->iErr = j;
+ return -1;
}
pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
+ pParse->iDepth--;
return j+1;
- }else if( c=='[' ){
+ }
+ case '[': {
/* Parse array */
iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
if( iThis<0 ) return -1;
+ if( ++pParse->iDepth > JSON_MAX_DEPTH ){
+ pParse->iErr = i;
+ return -1;
+ }
memset(&pParse->aNode[iThis].u, 0, sizeof(pParse->aNode[iThis].u));
for(j=i+1;;j++){
- while( fast_isspace(z[j]) ){ j++; }
- if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
x = jsonParseValue(pParse, j);
- pParse->iDepth--;
- if( x<0 ){
- if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
+ if( x<=0 ){
+ if( x==(-3) ){
+ j = pParse->iErr;
+ if( pParse->nNode!=(u32)iThis+1 ) pParse->hasNonstd = 1;
+ break;
+ }
+ if( x!=(-1) ) pParse->iErr = j;
return -1;
}
j = x;
- while( fast_isspace(z[j]) ){ j++; }
- c = z[j];
- if( c==',' ) continue;
- if( c!=']' ) return -1;
- break;
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]==']' ){
+ break;
+ }else{
+ if( fast_isspace(z[j]) ){
+ do{ j++; }while( fast_isspace(z[j]) );
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]==']' ){
+ break;
+ }
+ }
+ x = jsonParseValue(pParse, j);
+ if( x==(-4) ){
+ j = pParse->iErr;
+ continue;
+ }
+ if( x==(-3) ){
+ j = pParse->iErr;
+ break;
+ }
+ }
+ pParse->iErr = j;
+ return -1;
}
pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
+ pParse->iDepth--;
return j+1;
- }else if( c=='"' ){
+ }
+ case '\'': {
+ u8 jnFlags;
+ char cDelim;
+ pParse->hasNonstd = 1;
+ jnFlags = JNODE_JSON5;
+ goto parse_string;
+ case '"':
/* Parse string */
- u8 jnFlags = 0;
- j = i+1;
- for(;;){
+ jnFlags = 0;
+ parse_string:
+ cDelim = z[i];
+ for(j=i+1; 1; j++){
+ if( jsonIsOk[(unsigned char)z[j]] ) continue;
c = z[j];
- if( (c & ~0x1f)==0 ){
- /* Control characters are not allowed in strings */
- return -1;
- }
- if( c=='\\' ){
+ if( c==cDelim ){
+ break;
+ }else if( c=='\\' ){
c = z[++j];
if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
|| c=='n' || c=='r' || c=='t'
- || (c=='u' && jsonIs4Hex(z+j+1)) ){
- jnFlags = JNODE_ESCAPE;
+ || (c=='u' && jsonIs4Hex(&z[j+1])) ){
+ jnFlags |= JNODE_ESCAPE;
+ }else if( c=='\'' || c=='0' || c=='v' || c=='\n'
+ || (0xe2==(u8)c && 0x80==(u8)z[j+1]
+ && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2]))
+ || (c=='x' && jsonIs2Hex(&z[j+1])) ){
+ jnFlags |= (JNODE_ESCAPE|JNODE_JSON5);
+ pParse->hasNonstd = 1;
+ }else if( c=='\r' ){
+ if( z[j+1]=='\n' ) j++;
+ jnFlags |= (JNODE_ESCAPE|JNODE_JSON5);
+ pParse->hasNonstd = 1;
}else{
+ pParse->iErr = j;
return -1;
}
- }else if( c=='"' ){
- break;
+ }else if( c<=0x1f ){
+ /* Control characters are not allowed in strings */
+ pParse->iErr = j;
+ return -1;
}
- j++;
}
- jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]);
- if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags;
+ jsonParseAddNode(pParse, JSON_STRING | (jnFlags<<8), j+1-i, &z[i]);
return j+1;
- }else if( c=='n'
- && strncmp(z+i,"null",4)==0
- && !sqlite3Isalnum(z[i+4]) ){
- jsonParseAddNode(pParse, JSON_NULL, 0, 0);
- return i+4;
- }else if( c=='t'
- && strncmp(z+i,"true",4)==0
- && !sqlite3Isalnum(z[i+4]) ){
- jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
- return i+4;
- }else if( c=='f'
- && strncmp(z+i,"false",5)==0
- && !sqlite3Isalnum(z[i+5]) ){
- jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
- return i+5;
- }else if( c=='-' || (c>='0' && c<='9') ){
+ }
+ case 't': {
+ if( strncmp(z+i,"true",4)==0 && !sqlite3Isalnum(z[i+4]) ){
+ jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
+ return i+4;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ case 'f': {
+ if( strncmp(z+i,"false",5)==0 && !sqlite3Isalnum(z[i+5]) ){
+ jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
+ return i+5;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ case '+': {
+ u8 seenDP, seenE, jnFlags;
+ pParse->hasNonstd = 1;
+ jnFlags = JNODE_JSON5;
+ goto parse_number;
+ case '.':
+ if( sqlite3Isdigit(z[i+1]) ){
+ pParse->hasNonstd = 1;
+ jnFlags = JNODE_JSON5;
+ seenE = 0;
+ seenDP = JSON_REAL;
+ goto parse_number_2;
+ }
+ pParse->iErr = i;
+ return -1;
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
/* Parse number */
- u8 seenDP = 0;
- u8 seenE = 0;
+ jnFlags = 0;
+ parse_number:
+ seenDP = JSON_INT;
+ seenE = 0;
assert( '-' < '0' );
+ assert( '+' < '0' );
+ assert( '.' < '0' );
+ c = z[i];
+
if( c<='0' ){
- j = c=='-' ? i+1 : i;
- if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1;
+ if( c=='0' ){
+ if( (z[i+1]=='x' || z[i+1]=='X') && sqlite3Isxdigit(z[i+2]) ){
+ assert( seenDP==JSON_INT );
+ pParse->hasNonstd = 1;
+ jnFlags |= JNODE_JSON5;
+ for(j=i+3; sqlite3Isxdigit(z[j]); j++){}
+ goto parse_number_finish;
+ }else if( sqlite3Isdigit(z[i+1]) ){
+ pParse->iErr = i+1;
+ return -1;
+ }
+ }else{
+ if( !sqlite3Isdigit(z[i+1]) ){
+ /* JSON5 allows for "+Infinity" and "-Infinity" using exactly
+ ** that case. SQLite also allows these in any case and it allows
+ ** "+inf" and "-inf". */
+ if( (z[i+1]=='I' || z[i+1]=='i')
+ && sqlite3StrNICmp(&z[i+1], "inf",3)==0
+ ){
+ pParse->hasNonstd = 1;
+ if( z[i]=='-' ){
+ jsonParseAddNode(pParse, JSON_REAL, 8, "-9.0e999");
+ }else{
+ jsonParseAddNode(pParse, JSON_REAL, 7, "9.0e999");
+ }
+ return i + (sqlite3StrNICmp(&z[i+4],"inity",5)==0 ? 9 : 4);
+ }
+ if( z[i+1]=='.' ){
+ pParse->hasNonstd = 1;
+ jnFlags |= JNODE_JSON5;
+ goto parse_number_2;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ if( z[i+1]=='0' ){
+ if( sqlite3Isdigit(z[i+2]) ){
+ pParse->iErr = i+1;
+ return -1;
+ }else if( (z[i+2]=='x' || z[i+2]=='X') && sqlite3Isxdigit(z[i+3]) ){
+ pParse->hasNonstd = 1;
+ jnFlags |= JNODE_JSON5;
+ for(j=i+4; sqlite3Isxdigit(z[j]); j++){}
+ goto parse_number_finish;
+ }
+ }
+ }
}
- j = i+1;
- for(;; j++){
+ parse_number_2:
+ for(j=i+1;; j++){
c = z[j];
- if( c>='0' && c<='9' ) continue;
+ if( sqlite3Isdigit(c) ) continue;
if( c=='.' ){
- if( z[j-1]=='-' ) return -1;
- if( seenDP ) return -1;
- seenDP = 1;
+ if( seenDP==JSON_REAL ){
+ pParse->iErr = j;
+ return -1;
+ }
+ seenDP = JSON_REAL;
continue;
}
if( c=='e' || c=='E' ){
- if( z[j-1]<'0' ) return -1;
- if( seenE ) return -1;
- seenDP = seenE = 1;
+ if( z[j-1]<'0' ){
+ if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){
+ pParse->hasNonstd = 1;
+ jnFlags |= JNODE_JSON5;
+ }else{
+ pParse->iErr = j;
+ return -1;
+ }
+ }
+ if( seenE ){
+ pParse->iErr = j;
+ return -1;
+ }
+ seenDP = JSON_REAL;
+ seenE = 1;
c = z[j+1];
if( c=='+' || c=='-' ){
j++;
c = z[j+1];
}
- if( c<'0' || c>'9' ) return -1;
+ if( c<'0' || c>'9' ){
+ pParse->iErr = j;
+ return -1;
+ }
continue;
}
break;
}
- if( z[j-1]<'0' ) return -1;
- jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT,
- j - i, &z[i]);
+ if( z[j-1]<'0' ){
+ if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){
+ pParse->hasNonstd = 1;
+ jnFlags |= JNODE_JSON5;
+ }else{
+ pParse->iErr = j;
+ return -1;
+ }
+ }
+ parse_number_finish:
+ jsonParseAddNode(pParse, seenDP | (jnFlags<<8), j - i, &z[i]);
return j;
- }else if( c=='}' ){
+ }
+ case '}': {
+ pParse->iErr = i;
return -2; /* End of {...} */
- }else if( c==']' ){
+ }
+ case ']': {
+ pParse->iErr = i;
return -3; /* End of [...] */
- }else if( c==0 ){
+ }
+ case ',': {
+ pParse->iErr = i;
+ return -4; /* List separator */
+ }
+ case ':': {
+ pParse->iErr = i;
+ return -5; /* Object label/value separator */
+ }
+ case 0: {
return 0; /* End of file */
- }else{
+ }
+ case 0x09:
+ case 0x0a:
+ case 0x0d:
+ case 0x20: {
+ do{
+ i++;
+ }while( fast_isspace(z[i]) );
+ goto json_parse_restart;
+ }
+ case 0x0b:
+ case 0x0c:
+ case '/':
+ case 0xc2:
+ case 0xe1:
+ case 0xe2:
+ case 0xe3:
+ case 0xef: {
+ j = json5Whitespace(&z[i]);
+ if( j>0 ){
+ i += j;
+ pParse->hasNonstd = 1;
+ goto json_parse_restart;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ case 'n': {
+ if( strncmp(z+i,"null",4)==0 && !sqlite3Isalnum(z[i+4]) ){
+ jsonParseAddNode(pParse, JSON_NULL, 0, 0);
+ return i+4;
+ }
+ /* fall-through into the default case that checks for NaN */
+ }
+ default: {
+ u32 k;
+ int nn;
+ c = z[i];
+ for(k=0; khasNonstd = 1;
+ return i + nn;
+ }
+ pParse->iErr = i;
return -1; /* Syntax error */
}
+ } /* End switch(z[i]) */
}
/*
** Parse a complete JSON string. Return 0 on success or non-zero if there
-** are any errors. If an error occurs, free all memory associated with
-** pParse.
+** are any errors. If an error occurs, free all memory held by pParse,
+** but not pParse itself.
**
-** pParse is uninitialized when this routine is called.
+** pParse must be initialized to an empty parse object prior to calling
+** this routine.
*/
static int jsonParse(
JsonParse *pParse, /* Initialize and fill this JsonParse object */
- sqlite3_context *pCtx, /* Report errors here */
- const char *zJson /* Input JSON text to be parsed */
+ sqlite3_context *pCtx /* Report errors here */
){
int i;
- memset(pParse, 0, sizeof(*pParse));
- if( zJson==0 ) return 1;
- pParse->zJson = zJson;
+ const char *zJson = pParse->zJson;
i = jsonParseValue(pParse, 0);
if( pParse->oom ) i = -1;
if( i>0 ){
assert( pParse->iDepth==0 );
while( fast_isspace(zJson[i]) ) i++;
- if( zJson[i] ) i = -1;
+ if( zJson[i] ){
+ i += json5Whitespace(&zJson[i]);
+ if( zJson[i] ){
+ jsonParseReset(pParse);
+ return 1;
+ }
+ pParse->hasNonstd = 1;
+ }
}
if( i<=0 ){
if( pCtx!=0 ){
@@ -201215,6 +206048,7 @@ static int jsonParse(
return 0;
}
+
/* Mark node i of pParse as being a child of iParent. Call recursively
** to fill in all the descendants of node i.
*/
@@ -201264,26 +206098,49 @@ static int jsonParseFindParents(JsonParse *pParse){
#define JSON_CACHE_SZ 4 /* Max number of cache entries */
/*
-** Obtain a complete parse of the JSON found in the first argument
-** of the argv array. Use the sqlite3_get_auxdata() cache for this
-** parse if it is available. If the cache is not available or if it
-** is no longer valid, parse the JSON again and return the new parse,
-** and also register the new parse so that it will be available for
+** Obtain a complete parse of the JSON found in the pJson argument
+**
+** Use the sqlite3_get_auxdata() cache to find a preexisting parse
+** if it is available. If the cache is not available or if it
+** is no longer valid, parse the JSON again and return the new parse.
+** Also register the new parse so that it will be available for
** future sqlite3_get_auxdata() calls.
+**
+** If an error occurs and pErrCtx!=0 then report the error on pErrCtx
+** and return NULL.
+**
+** The returned pointer (if it is not NULL) is owned by the cache in
+** most cases, not the caller. The caller does NOT need to invoke
+** jsonParseFree(), in most cases.
+**
+** Except, if an error occurs and pErrCtx==0 then return the JsonParse
+** object with JsonParse.nErr non-zero and the caller will own the JsonParse
+** object. In that case, it will be the responsibility of the caller to
+** invoke jsonParseFree(). To summarize:
+**
+** pErrCtx!=0 || p->nErr==0 ==> Return value p is owned by the
+** cache. Call does not need to
+** free it.
+**
+** pErrCtx==0 && p->nErr!=0 ==> Return value is owned by the caller
+** and so the caller must free it.
*/
static JsonParse *jsonParseCached(
- sqlite3_context *pCtx,
- sqlite3_value **argv,
- sqlite3_context *pErrCtx
+ sqlite3_context *pCtx, /* Context to use for cache search */
+ sqlite3_value *pJson, /* Function param containing JSON text */
+ sqlite3_context *pErrCtx, /* Write parse errors here if not NULL */
+ int bUnedited /* No prior edits allowed */
){
- const char *zJson = (const char*)sqlite3_value_text(argv[0]);
- int nJson = sqlite3_value_bytes(argv[0]);
+ char *zJson = (char*)sqlite3_value_text(pJson);
+ int nJson = sqlite3_value_bytes(pJson);
JsonParse *p;
JsonParse *pMatch = 0;
int iKey;
int iMinKey = 0;
u32 iMinHold = 0xffffffff;
u32 iMaxHold = 0;
+ int bJsonRCStr;
+
if( zJson==0 ) return 0;
for(iKey=0; iKeynJson==nJson
- && memcmp(p->zJson,zJson,nJson)==0
+ && (p->hasMod==0 || bUnedited==0)
+ && (p->zJson==zJson || memcmp(p->zJson,zJson,nJson)==0)
+ ){
+ p->nErr = 0;
+ p->useMod = 0;
+ pMatch = p;
+ }else
+ if( pMatch==0
+ && p->zAlt!=0
+ && bUnedited==0
+ && p->nAlt==nJson
+ && memcmp(p->zAlt, zJson, nJson)==0
){
p->nErr = 0;
+ p->useMod = 1;
pMatch = p;
}else if( p->iHoldiHold;
@@ -201306,24 +206175,44 @@ static JsonParse *jsonParseCached(
}
}
if( pMatch ){
+ /* The input JSON text was found in the cache. Use the preexisting
+ ** parse of this JSON */
pMatch->nErr = 0;
pMatch->iHold = iMaxHold+1;
+ assert( pMatch->nJPRef>0 ); /* pMatch is owned by the cache */
return pMatch;
}
- p = sqlite3_malloc64( sizeof(*p) + nJson + 1 );
+
+ /* The input JSON was not found anywhere in the cache. We will need
+ ** to parse it ourselves and generate a new JsonParse object.
+ */
+ bJsonRCStr = sqlite3ValueIsOfClass(pJson,sqlite3RCStrUnref);
+ p = sqlite3_malloc64( sizeof(*p) + (bJsonRCStr ? 0 : nJson+1) );
if( p==0 ){
sqlite3_result_error_nomem(pCtx);
return 0;
}
memset(p, 0, sizeof(*p));
- p->zJson = (char*)&p[1];
- memcpy((char*)p->zJson, zJson, nJson+1);
- if( jsonParse(p, pErrCtx, p->zJson) ){
- sqlite3_free(p);
+ if( bJsonRCStr ){
+ p->zJson = sqlite3RCStrRef(zJson);
+ p->bJsonIsRCStr = 1;
+ }else{
+ p->zJson = (char*)&p[1];
+ memcpy(p->zJson, zJson, nJson+1);
+ }
+ p->nJPRef = 1;
+ if( jsonParse(p, pErrCtx) ){
+ if( pErrCtx==0 ){
+ p->nErr = 1;
+ assert( p->nJPRef==1 ); /* Caller will own the new JsonParse object p */
+ return p;
+ }
+ jsonParseFree(p);
return 0;
}
p->nJson = nJson;
p->iHold = iMaxHold+1;
+ /* Transfer ownership of the new JsonParse to the cache */
sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p,
(void(*)(void*))jsonParseFree);
return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey);
@@ -201333,7 +206222,7 @@ static JsonParse *jsonParseCached(
** Compare the OBJECT label at pNode against zKey,nKey. Return true on
** a match.
*/
-static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){
+static int jsonLabelCompare(const JsonNode *pNode, const char *zKey, u32 nKey){
assert( pNode->eU==1 );
if( pNode->jnFlags & JNODE_RAW ){
if( pNode->n!=nKey ) return 0;
@@ -201343,6 +206232,15 @@ static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){
return strncmp(pNode->u.zJContent+1, zKey, nKey)==0;
}
}
+static int jsonSameLabel(const JsonNode *p1, const JsonNode *p2){
+ if( p1->jnFlags & JNODE_RAW ){
+ return jsonLabelCompare(p2, p1->u.zJContent, p1->n);
+ }else if( p2->jnFlags & JNODE_RAW ){
+ return jsonLabelCompare(p1, p2->u.zJContent, p2->n);
+ }else{
+ return p1->n==p2->n && strncmp(p1->u.zJContent,p2->u.zJContent,p1->n)==0;
+ }
+}
/* forward declaration */
static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**);
@@ -201365,9 +206263,31 @@ static JsonNode *jsonLookupStep(
){
u32 i, j, nKey;
const char *zKey;
- JsonNode *pRoot = &pParse->aNode[iRoot];
+ JsonNode *pRoot;
+ if( pParse->oom ) return 0;
+ pRoot = &pParse->aNode[iRoot];
+ if( pRoot->jnFlags & (JNODE_REPLACE|JNODE_REMOVE) && pParse->useMod ){
+ while( (pRoot->jnFlags & JNODE_REPLACE)!=0 ){
+ u32 idx = (u32)(pRoot - pParse->aNode);
+ i = pParse->iSubst;
+ while( 1 /*exit-by-break*/ ){
+ assert( inNode );
+ assert( pParse->aNode[i].eType==JSON_SUBST );
+ assert( pParse->aNode[i].eU==4 );
+ assert( pParse->aNode[i].u.iPrevaNode[i].n==idx ){
+ pRoot = &pParse->aNode[i+1];
+ iRoot = i+1;
+ break;
+ }
+ i = pParse->aNode[i].u.iPrev;
+ }
+ }
+ if( pRoot->jnFlags & JNODE_REMOVE ){
+ return 0;
+ }
+ }
if( zPath[0]==0 ) return pRoot;
- if( pRoot->jnFlags & JNODE_REPLACE ) return 0;
if( zPath[0]=='.' ){
if( pRoot->eType!=JSON_OBJECT ) return 0;
zPath++;
@@ -201401,14 +206321,16 @@ static JsonNode *jsonLookupStep(
j += jsonNodeSize(&pRoot[j]);
}
if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
+ if( pParse->useMod==0 ) break;
assert( pRoot->eU==2 );
- iRoot += pRoot->u.iAppend;
+ iRoot = pRoot->u.iAppend;
pRoot = &pParse->aNode[iRoot];
j = 1;
}
if( pApnd ){
u32 iStart, iLabel;
JsonNode *pNode;
+ assert( pParse->useMod );
iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
iLabel = jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
zPath += i;
@@ -201417,7 +206339,7 @@ static JsonNode *jsonLookupStep(
if( pNode ){
pRoot = &pParse->aNode[iRoot];
assert( pRoot->eU==0 );
- pRoot->u.iAppend = iStart - iRoot;
+ pRoot->u.iAppend = iStart;
pRoot->jnFlags |= JNODE_APPEND;
VVA( pRoot->eU = 2 );
pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
@@ -201438,12 +206360,13 @@ static JsonNode *jsonLookupStep(
if( pRoot->eType!=JSON_ARRAY ) return 0;
for(;;){
while( j<=pBase->n ){
- if( (pBase[j].jnFlags & JNODE_REMOVE)==0 ) i++;
+ if( (pBase[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ) i++;
j += jsonNodeSize(&pBase[j]);
}
if( (pBase->jnFlags & JNODE_APPEND)==0 ) break;
+ if( pParse->useMod==0 ) break;
assert( pBase->eU==2 );
- iBase += pBase->u.iAppend;
+ iBase = pBase->u.iAppend;
pBase = &pParse->aNode[iBase];
j = 1;
}
@@ -201471,13 +206394,17 @@ static JsonNode *jsonLookupStep(
zPath += j + 1;
j = 1;
for(;;){
- while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){
- if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--;
+ while( j<=pRoot->n
+ && (i>0 || ((pRoot[j].jnFlags & JNODE_REMOVE)!=0 && pParse->useMod))
+ ){
+ if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ) i--;
j += jsonNodeSize(&pRoot[j]);
}
+ if( i==0 && j<=pRoot->n ) break;
if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
+ if( pParse->useMod==0 ) break;
assert( pRoot->eU==2 );
- iRoot += pRoot->u.iAppend;
+ iRoot = pRoot->u.iAppend;
pRoot = &pParse->aNode[iRoot];
j = 1;
}
@@ -201487,13 +206414,14 @@ static JsonNode *jsonLookupStep(
if( i==0 && pApnd ){
u32 iStart;
JsonNode *pNode;
+ assert( pParse->useMod );
iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0);
pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
if( pParse->oom ) return 0;
if( pNode ){
pRoot = &pParse->aNode[iRoot];
assert( pRoot->eU==0 );
- pRoot->u.iAppend = iStart - iRoot;
+ pRoot->u.iAppend = iStart;
pRoot->jnFlags |= JNODE_APPEND;
VVA( pRoot->eU = 2 );
}
@@ -201620,47 +206548,90 @@ static void jsonRemoveAllNulls(JsonNode *pNode){
** SQL functions used for testing and debugging
****************************************************************************/
+#if SQLITE_DEBUG
+/*
+** Print N node entries.
+*/
+static void jsonDebugPrintNodeEntries(
+ JsonNode *aNode, /* First node entry to print */
+ int N /* Number of node entries to print */
+){
+ int i;
+ for(i=0; iaNode, p->nNode);
+}
+static void jsonDebugPrintNode(JsonNode *pNode){
+ jsonDebugPrintNodeEntries(pNode, jsonNodeSize(pNode));
+}
+#else
+ /* The usual case */
+# define jsonDebugPrintNode(X)
+# define jsonDebugPrintParse(X)
+#endif
+
#ifdef SQLITE_DEBUG
/*
-** The json_parse(JSON) function returns a string which describes
-** a parse of the JSON provided. Or it returns NULL if JSON is not
-** well-formed.
+** SQL function: json_parse(JSON)
+**
+** Parse JSON using jsonParseCached(). Then print a dump of that
+** parse on standard output. Return the mimified JSON result, just
+** like the json() function.
*/
static void jsonParseFunc(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
- JsonString s; /* Output string - not real JSON */
- JsonParse x; /* The parse */
- u32 i;
+ JsonParse *p; /* The parse */
assert( argc==1 );
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- jsonParseFindParents(&x);
- jsonInit(&s, ctx);
- for(i=0; inNode);
+ printf("nAlloc = %u\n", p->nAlloc);
+ printf("nJson = %d\n", p->nJson);
+ printf("nAlt = %d\n", p->nAlt);
+ printf("nErr = %u\n", p->nErr);
+ printf("oom = %u\n", p->oom);
+ printf("hasNonstd = %u\n", p->hasNonstd);
+ printf("useMod = %u\n", p->useMod);
+ printf("hasMod = %u\n", p->hasMod);
+ printf("nJPRef = %u\n", p->nJPRef);
+ printf("iSubst = %u\n", p->iSubst);
+ printf("iHold = %u\n", p->iHold);
+ jsonDebugPrintNodeEntries(p->aNode, p->nNode);
+ jsonReturnJson(p, p->aNode, ctx, 1);
}
/*
@@ -201744,7 +206715,7 @@ static void jsonArrayLengthFunc(
u32 i;
JsonNode *pNode;
- p = jsonParseCached(ctx, argv, ctx);
+ p = jsonParseCached(ctx, argv[0], ctx, 0);
if( p==0 ) return;
assert( p->nNode );
if( argc==2 ){
@@ -201757,9 +206728,16 @@ static void jsonArrayLengthFunc(
return;
}
if( pNode->eType==JSON_ARRAY ){
- assert( (pNode->jnFlags & JNODE_APPEND)==0 );
- for(i=1; i<=pNode->n; n++){
- i += jsonNodeSize(&pNode[i]);
+ while( 1 /*exit-by-break*/ ){
+ i = 1;
+ while( i<=pNode->n ){
+ if( (pNode[i].jnFlags & JNODE_REMOVE)==0 ) n++;
+ i += jsonNodeSize(&pNode[i]);
+ }
+ if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
+ if( p->useMod==0 ) break;
+ assert( pNode->eU==2 );
+ pNode = &p->aNode[pNode->u.iAppend];
}
}
sqlite3_result_int64(ctx, n);
@@ -201806,14 +206784,14 @@ static void jsonExtractFunc(
JsonString jx;
if( argc<2 ) return;
- p = jsonParseCached(ctx, argv, ctx);
+ p = jsonParseCached(ctx, argv[0], ctx, 0);
if( p==0 ) return;
if( argc==2 ){
/* With a single PATH argument */
zPath = (const char*)sqlite3_value_text(argv[1]);
if( zPath==0 ) return;
if( flags & JSON_ABPATH ){
- if( zPath[0]!='$' ){
+ if( zPath[0]!='$' || (zPath[1]!='.' && zPath[1]!='[' && zPath[1]!=0) ){
/* The -> and ->> operators accept abbreviated PATH arguments. This
** is mostly for compatibility with PostgreSQL, but also for
** convenience.
@@ -201824,11 +206802,11 @@ static void jsonExtractFunc(
*/
jsonInit(&jx, ctx);
if( sqlite3Isdigit(zPath[0]) ){
- jsonAppendRaw(&jx, "$[", 2);
+ jsonAppendRawNZ(&jx, "$[", 2);
jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
- jsonAppendRaw(&jx, "]", 2);
+ jsonAppendRawNZ(&jx, "]", 2);
}else{
- jsonAppendRaw(&jx, "$.", 1 + (zPath[0]!='['));
+ jsonAppendRawNZ(&jx, "$.", 1 + (zPath[0]!='['));
jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
jsonAppendChar(&jx, 0);
}
@@ -201839,15 +206817,15 @@ static void jsonExtractFunc(
}
if( pNode ){
if( flags & JSON_JSON ){
- jsonReturnJson(pNode, ctx, 0);
+ jsonReturnJson(p, pNode, ctx, 0);
}else{
- jsonReturn(pNode, ctx, 0);
+ jsonReturn(p, pNode, ctx);
sqlite3_result_subtype(ctx, 0);
}
}
}else{
pNode = jsonLookup(p, zPath, 0, ctx);
- if( p->nErr==0 && pNode ) jsonReturn(pNode, ctx, 0);
+ if( p->nErr==0 && pNode ) jsonReturn(p, pNode, ctx);
}
}else{
/* Two or more PATH arguments results in a JSON array with each
@@ -201861,9 +206839,9 @@ static void jsonExtractFunc(
if( p->nErr ) break;
jsonAppendSeparator(&jx);
if( pNode ){
- jsonRenderNode(pNode, &jx, 0);
+ jsonRenderNode(p, pNode, &jx);
}else{
- jsonAppendRaw(&jx, "null", 4);
+ jsonAppendRawNZ(&jx, "null", 4);
}
}
if( i==argc ){
@@ -201904,51 +206882,42 @@ static JsonNode *jsonMergePatch(
assert( pPatch[i].eU==1 );
nKey = pPatch[i].n;
zKey = pPatch[i].u.zJContent;
- assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
for(j=1; jn; j += jsonNodeSize(&pTarget[j+1])+1 ){
assert( pTarget[j].eType==JSON_STRING );
assert( pTarget[j].jnFlags & JNODE_LABEL );
- assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
- if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){
- if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break;
+ if( jsonSameLabel(&pPatch[i], &pTarget[j]) ){
+ if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_REPLACE) ) break;
if( pPatch[i+1].eType==JSON_NULL ){
pTarget[j+1].jnFlags |= JNODE_REMOVE;
}else{
JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]);
if( pNew==0 ) return 0;
- pTarget = &pParse->aNode[iTarget];
- if( pNew!=&pTarget[j+1] ){
- assert( pTarget[j+1].eU==0
- || pTarget[j+1].eU==1
- || pTarget[j+1].eU==2 );
- testcase( pTarget[j+1].eU==1 );
- testcase( pTarget[j+1].eU==2 );
- VVA( pTarget[j+1].eU = 5 );
- pTarget[j+1].u.pPatch = pNew;
- pTarget[j+1].jnFlags |= JNODE_PATCH;
+ if( pNew!=&pParse->aNode[iTarget+j+1] ){
+ jsonParseAddSubstNode(pParse, iTarget+j+1);
+ jsonParseAddNodeArray(pParse, pNew, jsonNodeSize(pNew));
}
+ pTarget = &pParse->aNode[iTarget];
}
break;
}
}
if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){
- int iStart, iPatch;
- iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
+ int iStart;
+ JsonNode *pApnd;
+ u32 nApnd;
+ iStart = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
- iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
+ pApnd = &pPatch[i+1];
+ if( pApnd->eType==JSON_OBJECT ) jsonRemoveAllNulls(pApnd);
+ nApnd = jsonNodeSize(pApnd);
+ jsonParseAddNodeArray(pParse, pApnd, jsonNodeSize(pApnd));
if( pParse->oom ) return 0;
- jsonRemoveAllNulls(pPatch);
- pTarget = &pParse->aNode[iTarget];
- assert( pParse->aNode[iRoot].eU==0 || pParse->aNode[iRoot].eU==2 );
- testcase( pParse->aNode[iRoot].eU==2 );
+ pParse->aNode[iStart].n = 1+nApnd;
pParse->aNode[iRoot].jnFlags |= JNODE_APPEND;
+ pParse->aNode[iRoot].u.iAppend = iStart;
VVA( pParse->aNode[iRoot].eU = 2 );
- pParse->aNode[iRoot].u.iAppend = iStart - iRoot;
iRoot = iStart;
- assert( pParse->aNode[iPatch].eU==0 );
- VVA( pParse->aNode[iPatch].eU = 5 );
- pParse->aNode[iPatch].jnFlags |= JNODE_PATCH;
- pParse->aNode[iPatch].u.pPatch = &pPatch[i+1];
+ pTarget = &pParse->aNode[iTarget];
}
}
return pTarget;
@@ -201964,25 +206933,28 @@ static void jsonPatchFunc(
int argc,
sqlite3_value **argv
){
- JsonParse x; /* The JSON that is being patched */
- JsonParse y; /* The patch */
+ JsonParse *pX; /* The JSON that is being patched */
+ JsonParse *pY; /* The patch */
JsonNode *pResult; /* The result of the merge */
UNUSED_PARAMETER(argc);
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- if( jsonParse(&y, ctx, (const char*)sqlite3_value_text(argv[1])) ){
- jsonParseReset(&x);
- return;
- }
- pResult = jsonMergePatch(&x, 0, y.aNode);
- assert( pResult!=0 || x.oom );
- if( pResult ){
- jsonReturnJson(pResult, ctx, 0);
+ pX = jsonParseCached(ctx, argv[0], ctx, 1);
+ if( pX==0 ) return;
+ assert( pX->hasMod==0 );
+ pX->hasMod = 1;
+ pY = jsonParseCached(ctx, argv[1], ctx, 1);
+ if( pY==0 ) return;
+ pX->useMod = 1;
+ pY->useMod = 1;
+ pResult = jsonMergePatch(pX, 0, pY->aNode);
+ assert( pResult!=0 || pX->oom );
+ if( pResult && pX->oom==0 ){
+ jsonDebugPrintParse(pX);
+ jsonDebugPrintNode(pResult);
+ jsonReturnJson(pX, pResult, ctx, 0);
}else{
sqlite3_result_error_nomem(ctx);
}
- jsonParseReset(&x);
- jsonParseReset(&y);
}
@@ -202038,26 +207010,120 @@ static void jsonRemoveFunc(
int argc,
sqlite3_value **argv
){
- JsonParse x; /* The parse */
+ JsonParse *pParse; /* The parse */
JsonNode *pNode;
const char *zPath;
u32 i;
if( argc<1 ) return;
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
+ pParse = jsonParseCached(ctx, argv[0], ctx, argc>1);
+ if( pParse==0 ) return;
for(i=1; i<(u32)argc; i++){
zPath = (const char*)sqlite3_value_text(argv[i]);
if( zPath==0 ) goto remove_done;
- pNode = jsonLookup(&x, zPath, 0, ctx);
- if( x.nErr ) goto remove_done;
- if( pNode ) pNode->jnFlags |= JNODE_REMOVE;
+ pNode = jsonLookup(pParse, zPath, 0, ctx);
+ if( pParse->nErr ) goto remove_done;
+ if( pNode ){
+ pNode->jnFlags |= JNODE_REMOVE;
+ pParse->hasMod = 1;
+ pParse->useMod = 1;
+ }
}
- if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){
- jsonReturnJson(x.aNode, ctx, 0);
+ if( (pParse->aNode[0].jnFlags & JNODE_REMOVE)==0 ){
+ jsonReturnJson(pParse, pParse->aNode, ctx, 1);
}
remove_done:
- jsonParseReset(&x);
+ jsonDebugPrintParse(p);
+}
+
+/*
+** Substitute the value at iNode with the pValue parameter.
+*/
+static void jsonReplaceNode(
+ sqlite3_context *pCtx,
+ JsonParse *p,
+ int iNode,
+ sqlite3_value *pValue
+){
+ int idx = jsonParseAddSubstNode(p, iNode);
+ if( idx<=0 ){
+ assert( p->oom );
+ return;
+ }
+ switch( sqlite3_value_type(pValue) ){
+ case SQLITE_NULL: {
+ jsonParseAddNode(p, JSON_NULL, 0, 0);
+ break;
+ }
+ case SQLITE_FLOAT: {
+ char *z = sqlite3_mprintf("%!0.15g", sqlite3_value_double(pValue));
+ int n;
+ if( z==0 ){
+ p->oom = 1;
+ break;
+ }
+ n = sqlite3Strlen30(z);
+ jsonParseAddNode(p, JSON_REAL, n, z);
+ jsonParseAddCleanup(p, sqlite3_free, z);
+ break;
+ }
+ case SQLITE_INTEGER: {
+ char *z = sqlite3_mprintf("%lld", sqlite3_value_int64(pValue));
+ int n;
+ if( z==0 ){
+ p->oom = 1;
+ break;
+ }
+ n = sqlite3Strlen30(z);
+ jsonParseAddNode(p, JSON_INT, n, z);
+ jsonParseAddCleanup(p, sqlite3_free, z);
+
+ break;
+ }
+ case SQLITE_TEXT: {
+ const char *z = (const char*)sqlite3_value_text(pValue);
+ u32 n = (u32)sqlite3_value_bytes(pValue);
+ if( z==0 ){
+ p->oom = 1;
+ break;
+ }
+ if( sqlite3_value_subtype(pValue)!=JSON_SUBTYPE ){
+ char *zCopy = sqlite3_malloc64( n+1 );
+ int k;
+ if( zCopy ){
+ memcpy(zCopy, z, n);
+ zCopy[n] = 0;
+ jsonParseAddCleanup(p, sqlite3_free, zCopy);
+ }else{
+ p->oom = 1;
+ sqlite3_result_error_nomem(pCtx);
+ }
+ k = jsonParseAddNode(p, JSON_STRING, n, zCopy);
+ assert( k>0 || p->oom );
+ if( p->oom==0 ) p->aNode[k].jnFlags |= JNODE_RAW;
+ }else{
+ JsonParse *pPatch = jsonParseCached(pCtx, pValue, pCtx, 1);
+ if( pPatch==0 ){
+ p->oom = 1;
+ break;
+ }
+ jsonParseAddNodeArray(p, pPatch->aNode, pPatch->nNode);
+ /* The nodes copied out of pPatch and into p likely contain
+ ** u.zJContent pointers into pPatch->zJson. So preserve the
+ ** content of pPatch until p is destroyed. */
+ assert( pPatch->nJPRef>=1 );
+ pPatch->nJPRef++;
+ jsonParseAddCleanup(p, (void(*)(void*))jsonParseFree, pPatch);
+ }
+ break;
+ }
+ default: {
+ jsonParseAddNode(p, JSON_NULL, 0, 0);
+ sqlite3_result_error(pCtx, "JSON cannot hold BLOB values", -1);
+ p->nErr++;
+ break;
+ }
+ }
}
/*
@@ -202071,7 +207137,7 @@ static void jsonReplaceFunc(
int argc,
sqlite3_value **argv
){
- JsonParse x; /* The parse */
+ JsonParse *pParse; /* The parse */
JsonNode *pNode;
const char *zPath;
u32 i;
@@ -202081,28 +207147,22 @@ static void jsonReplaceFunc(
jsonWrongNumArgs(ctx, "replace");
return;
}
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
+ pParse = jsonParseCached(ctx, argv[0], ctx, argc>1);
+ if( pParse==0 ) return;
+ pParse->nJPRef++;
for(i=1; i<(u32)argc; i+=2){
zPath = (const char*)sqlite3_value_text(argv[i]);
- pNode = jsonLookup(&x, zPath, 0, ctx);
- if( x.nErr ) goto replace_err;
+ pParse->useMod = 1;
+ pNode = jsonLookup(pParse, zPath, 0, ctx);
+ if( pParse->nErr ) goto replace_err;
if( pNode ){
- assert( pNode->eU==0 || pNode->eU==1 || pNode->eU==4 );
- testcase( pNode->eU!=0 && pNode->eU!=1 );
- pNode->jnFlags |= (u8)JNODE_REPLACE;
- VVA( pNode->eU = 4 );
- pNode->u.iReplace = i + 1;
+ jsonReplaceNode(ctx, pParse, (u32)(pNode - pParse->aNode), argv[i+1]);
}
}
- if( x.aNode[0].jnFlags & JNODE_REPLACE ){
- assert( x.aNode[0].eU==4 );
- sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
- }else{
- jsonReturnJson(x.aNode, ctx, argv);
- }
+ jsonReturnJson(pParse, pParse->aNode, ctx, 1);
replace_err:
- jsonParseReset(&x);
+ jsonDebugPrintParse(pParse);
+ jsonParseFree(pParse);
}
@@ -202123,7 +207183,7 @@ static void jsonSetFunc(
int argc,
sqlite3_value **argv
){
- JsonParse x; /* The parse */
+ JsonParse *pParse; /* The parse */
JsonNode *pNode;
const char *zPath;
u32 i;
@@ -202135,33 +207195,27 @@ static void jsonSetFunc(
jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert");
return;
}
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
+ pParse = jsonParseCached(ctx, argv[0], ctx, argc>1);
+ if( pParse==0 ) return;
+ pParse->nJPRef++;
for(i=1; i<(u32)argc; i+=2){
zPath = (const char*)sqlite3_value_text(argv[i]);
bApnd = 0;
- pNode = jsonLookup(&x, zPath, &bApnd, ctx);
- if( x.oom ){
+ pParse->useMod = 1;
+ pNode = jsonLookup(pParse, zPath, &bApnd, ctx);
+ if( pParse->oom ){
sqlite3_result_error_nomem(ctx);
goto jsonSetDone;
- }else if( x.nErr ){
+ }else if( pParse->nErr ){
goto jsonSetDone;
}else if( pNode && (bApnd || bIsSet) ){
- testcase( pNode->eU!=0 && pNode->eU!=1 );
- assert( pNode->eU!=3 && pNode->eU!=5 );
- VVA( pNode->eU = 4 );
- pNode->jnFlags |= (u8)JNODE_REPLACE;
- pNode->u.iReplace = i + 1;
+ jsonReplaceNode(ctx, pParse, (u32)(pNode - pParse->aNode), argv[i+1]);
}
}
- if( x.aNode[0].jnFlags & JNODE_REPLACE ){
- assert( x.aNode[0].eU==4 );
- sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
- }else{
- jsonReturnJson(x.aNode, ctx, argv);
- }
+ jsonDebugPrintParse(pParse);
+ jsonReturnJson(pParse, pParse->aNode, ctx, 1);
jsonSetDone:
- jsonParseReset(&x);
+ jsonParseFree(pParse);
}
/*
@@ -202180,7 +207234,7 @@ static void jsonTypeFunc(
const char *zPath;
JsonNode *pNode;
- p = jsonParseCached(ctx, argv, ctx);
+ p = jsonParseCached(ctx, argv[0], ctx, 0);
if( p==0 ) return;
if( argc==2 ){
zPath = (const char*)sqlite3_value_text(argv[1]);
@@ -202196,8 +207250,8 @@ static void jsonTypeFunc(
/*
** json_valid(JSON)
**
-** Return 1 if JSON is a well-formed JSON string according to RFC-7159.
-** Return 0 otherwise.
+** Return 1 if JSON is a well-formed canonical JSON string according
+** to RFC-7159. Return 0 otherwise.
*/
static void jsonValidFunc(
sqlite3_context *ctx,
@@ -202206,8 +207260,75 @@ static void jsonValidFunc(
){
JsonParse *p; /* The parse */
UNUSED_PARAMETER(argc);
- p = jsonParseCached(ctx, argv, 0);
- sqlite3_result_int(ctx, p!=0);
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
+#ifdef SQLITE_LEGACY_JSON_VALID
+ /* Incorrect legacy behavior was to return FALSE for a NULL input */
+ sqlite3_result_int(ctx, 0);
+#endif
+ return;
+ }
+ p = jsonParseCached(ctx, argv[0], 0, 0);
+ if( p==0 || p->oom ){
+ sqlite3_result_error_nomem(ctx);
+ sqlite3_free(p);
+ }else{
+ sqlite3_result_int(ctx, p->nErr==0 && (p->hasNonstd==0 || p->useMod));
+ if( p->nErr ) jsonParseFree(p);
+ }
+}
+
+/*
+** json_error_position(JSON)
+**
+** If the argument is not an interpretable JSON string, then return the 1-based
+** character position at which the parser first recognized that the input
+** was in error. The left-most character is 1. If the string is valid
+** JSON, then return 0.
+**
+** Note that json_valid() is only true for strictly conforming canonical JSON.
+** But this routine returns zero if the input contains extension. Thus:
+**
+** (1) If the input X is strictly conforming canonical JSON:
+**
+** json_valid(X) returns true
+** json_error_position(X) returns 0
+**
+** (2) If the input X is JSON but it includes extension (such as JSON5) that
+** are not part of RFC-8259:
+**
+** json_valid(X) returns false
+** json_error_position(X) return 0
+**
+** (3) If the input X cannot be interpreted as JSON even taking extensions
+** into account:
+**
+** json_valid(X) return false
+** json_error_position(X) returns 1 or more
+*/
+static void jsonErrorFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse *p; /* The parse */
+ UNUSED_PARAMETER(argc);
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
+ p = jsonParseCached(ctx, argv[0], 0, 0);
+ if( p==0 || p->oom ){
+ sqlite3_result_error_nomem(ctx);
+ sqlite3_free(p);
+ }else if( p->nErr==0 ){
+ sqlite3_result_int(ctx, 0);
+ }else{
+ int n = 1;
+ u32 i;
+ const char *z = (const char*)sqlite3_value_text(argv[0]);
+ for(i=0; iiErr && ALWAYS(z[i]); i++){
+ if( (z[i]&0xc0)!=0x80 ) n++;
+ }
+ sqlite3_result_int(ctx, n);
+ jsonParseFree(p);
+ }
}
@@ -202249,7 +207370,8 @@ static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){
assert( pStr->bStatic );
}else if( isFinal ){
sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
- pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
+ pStr->bStatic ? SQLITE_TRANSIENT :
+ sqlite3RCStrUnref);
pStr->bStatic = 1;
}else{
sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
@@ -202290,7 +207412,7 @@ static void jsonGroupInverse(
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
#ifdef NEVER
/* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will
- ** always have been called to initalize it */
+ ** always have been called to initialize it */
if( NEVER(!pStr) ) return;
#endif
z = pStr->zBuf;
@@ -202357,7 +207479,8 @@ static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
assert( pStr->bStatic );
}else if( isFinal ){
sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
- pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
+ pStr->bStatic ? SQLITE_TRANSIENT :
+ sqlite3RCStrUnref);
pStr->bStatic = 1;
}else{
sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
@@ -202468,7 +207591,6 @@ static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
/* Reset a JsonEachCursor back to its original state. Free any memory
** held. */
static void jsonEachCursorReset(JsonEachCursor *p){
- sqlite3_free(p->zJson);
sqlite3_free(p->zRoot);
jsonParseReset(&p->sParse);
p->iRowid = 0;
@@ -202551,14 +207673,16 @@ static void jsonAppendObjectPathElement(
assert( pNode->eU==1 );
z = pNode->u.zJContent;
nn = pNode->n;
- assert( nn>=2 );
- assert( z[0]=='"' );
- assert( z[nn-1]=='"' );
- if( nn>2 && sqlite3Isalpha(z[1]) ){
- for(jj=2; jjjnFlags & JNODE_RAW)==0 ){
+ assert( nn>=2 );
+ assert( z[0]=='"' || z[0]=='\'' );
+ assert( z[nn-1]=='"' || z[0]=='\'' );
+ if( nn>2 && sqlite3Isalpha(z[1]) ){
+ for(jj=2; jji==0 ) break;
if( p->eType==JSON_OBJECT ){
- jsonReturn(pThis, ctx, 0);
+ jsonReturn(&p->sParse, pThis, ctx);
}else if( p->eType==JSON_ARRAY ){
u32 iKey;
if( p->bRecursive ){
@@ -202620,7 +207744,7 @@ static int jsonEachColumn(
}
case JEACH_VALUE: {
if( pThis->jnFlags & JNODE_LABEL ) pThis++;
- jsonReturn(pThis, ctx, 0);
+ jsonReturn(&p->sParse, pThis, ctx);
break;
}
case JEACH_TYPE: {
@@ -202631,7 +207755,7 @@ static int jsonEachColumn(
case JEACH_ATOM: {
if( pThis->jnFlags & JNODE_LABEL ) pThis++;
if( pThis->eType>=JSON_ARRAY ) break;
- jsonReturn(pThis, ctx, 0);
+ jsonReturn(&p->sParse, pThis, ctx);
break;
}
case JEACH_ID: {
@@ -202786,11 +207910,19 @@ static int jsonEachFilter(
if( idxNum==0 ) return SQLITE_OK;
z = (const char*)sqlite3_value_text(argv[0]);
if( z==0 ) return SQLITE_OK;
- n = sqlite3_value_bytes(argv[0]);
- p->zJson = sqlite3_malloc64( n+1 );
- if( p->zJson==0 ) return SQLITE_NOMEM;
- memcpy(p->zJson, z, (size_t)n+1);
- if( jsonParse(&p->sParse, 0, p->zJson) ){
+ memset(&p->sParse, 0, sizeof(p->sParse));
+ p->sParse.nJPRef = 1;
+ if( sqlite3ValueIsOfClass(argv[0], sqlite3RCStrUnref) ){
+ p->sParse.zJson = sqlite3RCStrRef((char*)z);
+ }else{
+ n = sqlite3_value_bytes(argv[0]);
+ p->sParse.zJson = sqlite3RCStrNew( n+1 );
+ if( p->sParse.zJson==0 ) return SQLITE_NOMEM;
+ memcpy(p->sParse.zJson, z, (size_t)n+1);
+ }
+ p->sParse.bJsonIsRCStr = 1;
+ p->zJson = p->sParse.zJson;
+ if( jsonParse(&p->sParse, 0) ){
int rc = SQLITE_NOMEM;
if( p->sParse.oom==0 ){
sqlite3_free(cur->pVtab->zErrMsg);
@@ -202875,7 +208007,8 @@ static sqlite3_module jsonEachModule = {
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
/* The methods of the json_tree virtual table. */
@@ -202903,7 +208036,8 @@ static sqlite3_module jsonTreeModule = {
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#endif /* !defined(SQLITE_OMIT_JSON) */
@@ -202918,6 +208052,7 @@ SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void){
JFUNCTION(json_array, -1, 0, jsonArrayFunc),
JFUNCTION(json_array_length, 1, 0, jsonArrayLengthFunc),
JFUNCTION(json_array_length, 2, 0, jsonArrayLengthFunc),
+ JFUNCTION(json_error_position,1, 0, jsonErrorFunc),
JFUNCTION(json_extract, -1, 0, jsonExtractFunc),
JFUNCTION(->, 2, JSON_JSON, jsonExtractFunc),
JFUNCTION(->>, 2, JSON_SQL, jsonExtractFunc),
@@ -203067,6 +208202,11 @@ typedef unsigned int u32;
#endif
#endif /* !defined(SQLITE_AMALGAMATION) */
+/* Macro to check for 4-byte alignment. Only used inside of assert() */
+#ifdef SQLITE_DEBUG
+# define FOUR_BYTE_ALIGNED(X) ((((char*)(X) - (char*)0) & 3)==0)
+#endif
+
/* #include */
/* #include */
/* #include */
@@ -203132,6 +208272,7 @@ struct Rtree {
int iDepth; /* Current depth of the r-tree structure */
char *zDb; /* Name of database containing r-tree table */
char *zName; /* Name of r-tree table */
+ char *zNodeName; /* Name of the %_node table */
u32 nBusy; /* Current number of users of this structure */
i64 nRowEst; /* Estimated number of rows in this table */
u32 nCursor; /* Number of open cursors */
@@ -203144,7 +208285,6 @@ struct Rtree {
** headed by the node (leaf nodes have RtreeNode.iNode==0).
*/
RtreeNode *pDeleted;
- int iReinsertHeight; /* Height of sub-trees Reinsert() has run on */
/* Blob I/O on xxx_node */
sqlite3_blob *pNodeBlob;
@@ -203441,17 +208581,23 @@ struct RtreeMatchArg {
** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined
** at run-time.
*/
-#ifndef SQLITE_BYTEORDER
-#if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
- defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
- defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
- defined(__arm__)
-# define SQLITE_BYTEORDER 1234
-#elif defined(sparc) || defined(__ppc__)
-# define SQLITE_BYTEORDER 4321
-#else
-# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */
-#endif
+#ifndef SQLITE_BYTEORDER /* Replicate changes at tag-20230904a */
+# if defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
+# define SQLITE_BYTEORDER 4321
+# elif defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
+# define SQLITE_BYTEORDER 1234
+# elif defined(__BIG_ENDIAN__) && __BIG_ENDIAN__==1
+# define SQLITE_BYTEORDER 4321
+# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
+ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
+ defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64)
+# define SQLITE_BYTEORDER 1234
+# elif defined(sparc) || defined(__ARMEB__) || defined(__AARCH64EB__)
+# define SQLITE_BYTEORDER 4321
+# else
+# define SQLITE_BYTEORDER 0
+# endif
#endif
@@ -203472,7 +208618,7 @@ static int readInt16(u8 *p){
return (p[0]<<8) + p[1];
}
static void readCoord(u8 *p, RtreeCoord *pCoord){
- assert( (((sqlite3_uint64)p)&3)==0 ); /* p is always 4-byte aligned */
+ assert( FOUR_BYTE_ALIGNED(p) );
#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
pCoord->u = _byteswap_ulong(*(u32*)p);
#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
@@ -203526,7 +208672,7 @@ static void writeInt16(u8 *p, int i){
}
static int writeCoord(u8 *p, RtreeCoord *pCoord){
u32 i;
- assert( (((sqlite3_uint64)p)&3)==0 ); /* p is always 4-byte aligned */
+ assert( FOUR_BYTE_ALIGNED(p) );
assert( sizeof(RtreeCoord)==4 );
assert( sizeof(u32)==4 );
#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
@@ -203697,11 +208843,9 @@ static int nodeAcquire(
}
}
if( pRtree->pNodeBlob==0 ){
- char *zTab = sqlite3_mprintf("%s_node", pRtree->zName);
- if( zTab==0 ) return SQLITE_NOMEM;
- rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, zTab, "data", iNode, 0,
+ rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, pRtree->zNodeName,
+ "data", iNode, 0,
&pRtree->pNodeBlob);
- sqlite3_free(zTab);
}
if( rc ){
nodeBlobReset(pRtree);
@@ -204254,7 +209398,7 @@ static void rtreeNonleafConstraint(
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
|| p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE
|| p->op==RTREE_FALSE );
- assert( (((sqlite3_uint64)pCellData)&3)==0 ); /* 4-byte aligned */
+ assert( FOUR_BYTE_ALIGNED(pCellData) );
switch( p->op ){
case RTREE_TRUE: return; /* Always satisfied */
case RTREE_FALSE: break; /* Never satisfied */
@@ -204307,7 +209451,7 @@ static void rtreeLeafConstraint(
|| p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE
|| p->op==RTREE_FALSE );
pCellData += 8 + p->iCoord*4;
- assert( (((sqlite3_uint64)pCellData)&3)==0 ); /* 4-byte aligned */
+ assert( FOUR_BYTE_ALIGNED(pCellData) );
RTREE_DECODE_COORD(eInt, pCellData, xN);
switch( p->op ){
case RTREE_TRUE: return; /* Always satisfied */
@@ -204877,7 +210021,20 @@ static int rtreeFilter(
p->pInfo->nCoord = pRtree->nDim2;
p->pInfo->anQueue = pCsr->anQueue;
p->pInfo->mxLevel = pRtree->iDepth + 1;
- }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+ }else if( eType==SQLITE_INTEGER ){
+ sqlite3_int64 iVal = sqlite3_value_int64(argv[ii]);
+#ifdef SQLITE_RTREE_INT_ONLY
+ p->u.rValue = iVal;
+#else
+ p->u.rValue = (double)iVal;
+ if( iVal>=((sqlite3_int64)1)<<48
+ || iVal<=-(((sqlite3_int64)1)<<48)
+ ){
+ if( p->op==RTREE_LT ) p->op = RTREE_LE;
+ if( p->op==RTREE_GT ) p->op = RTREE_GE;
+ }
+#endif
+ }else if( eType==SQLITE_FLOAT ){
#ifdef SQLITE_RTREE_INT_ONLY
p->u.rValue = sqlite3_value_int64(argv[ii]);
#else
@@ -205008,11 +210165,12 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|| p->op==SQLITE_INDEX_CONSTRAINT_MATCH)
){
u8 op;
+ u8 doOmit = 1;
switch( p->op ){
- case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break;
- case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break;
+ case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; doOmit = 0; break;
+ case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; doOmit = 0; break;
case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break;
- case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break;
+ case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; doOmit = 0; break;
case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break;
case SQLITE_INDEX_CONSTRAINT_MATCH: op = RTREE_MATCH; break;
default: op = 0; break;
@@ -205021,15 +210179,19 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
zIdxStr[iIdx++] = op;
zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0');
pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2);
- pIdxInfo->aConstraintUsage[ii].omit = 1;
+ pIdxInfo->aConstraintUsage[ii].omit = doOmit;
}
}
}
pIdxInfo->idxNum = 2;
pIdxInfo->needToFreeIdxStr = 1;
- if( iIdx>0 && 0==(pIdxInfo->idxStr = sqlite3_mprintf("%s", zIdxStr)) ){
- return SQLITE_NOMEM;
+ if( iIdx>0 ){
+ pIdxInfo->idxStr = sqlite3_malloc( iIdx+1 );
+ if( pIdxInfo->idxStr==0 ){
+ return SQLITE_NOMEM;
+ }
+ memcpy(pIdxInfo->idxStr, zIdxStr, iIdx+1);
}
nRow = pRtree->nRowEst >> (iIdx/2);
@@ -205108,31 +210270,22 @@ static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
*/
static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
int ii;
- int isInt = (pRtree->eCoordType==RTREE_COORD_INT32);
- for(ii=0; iinDim2; ii+=2){
- RtreeCoord *a1 = &p1->aCoord[ii];
- RtreeCoord *a2 = &p2->aCoord[ii];
- if( (!isInt && (a2[0].fa1[1].f))
- || ( isInt && (a2[0].ia1[1].i))
- ){
- return 0;
+ if( pRtree->eCoordType==RTREE_COORD_INT32 ){
+ for(ii=0; iinDim2; ii+=2){
+ RtreeCoord *a1 = &p1->aCoord[ii];
+ RtreeCoord *a2 = &p2->aCoord[ii];
+ if( a2[0].ia1[1].i ) return 0;
+ }
+ }else{
+ for(ii=0; iinDim2; ii+=2){
+ RtreeCoord *a1 = &p1->aCoord[ii];
+ RtreeCoord *a2 = &p2->aCoord[ii];
+ if( a2[0].fa1[1].f ) return 0;
}
}
return 1;
}
-/*
-** Return the amount cell p would grow by if it were unioned with pCell.
-*/
-static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){
- RtreeDValue area;
- RtreeCell cell;
- memcpy(&cell, p, sizeof(RtreeCell));
- area = cellArea(pRtree, &cell);
- cellUnion(pRtree, &cell, pCell);
- return (cellArea(pRtree, &cell)-area);
-}
-
static RtreeDValue cellOverlap(
Rtree *pRtree,
RtreeCell *p,
@@ -205179,38 +210332,52 @@ static int ChooseLeaf(
for(ii=0; rc==SQLITE_OK && ii<(pRtree->iDepth-iHeight); ii++){
int iCell;
sqlite3_int64 iBest = 0;
-
+ int bFound = 0;
RtreeDValue fMinGrowth = RTREE_ZERO;
RtreeDValue fMinArea = RTREE_ZERO;
-
int nCell = NCELL(pNode);
- RtreeCell cell;
RtreeNode *pChild = 0;
- RtreeCell *aCell = 0;
-
- /* Select the child node which will be enlarged the least if pCell
- ** is inserted into it. Resolve ties by choosing the entry with
- ** the smallest area.
+ /* First check to see if there is are any cells in pNode that completely
+ ** contains pCell. If two or more cells in pNode completely contain pCell
+ ** then pick the smallest.
*/
for(iCell=0; iCell1 ){
- int iLeft = 0;
- int iRight = 0;
-
- int nLeft = nIdx/2;
- int nRight = nIdx-nLeft;
- int *aLeft = aIdx;
- int *aRight = &aIdx[nLeft];
-
- SortByDistance(aLeft, nLeft, aDistance, aSpare);
- SortByDistance(aRight, nRight, aDistance, aSpare);
-
- memcpy(aSpare, aLeft, sizeof(int)*nLeft);
- aLeft = aSpare;
-
- while( iLeftnDim; iDim++){
- aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2]);
- aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2+1]);
- }
- }
- for(iDim=0; iDimnDim; iDim++){
- aCenterCoord[iDim] = (aCenterCoord[iDim]/(nCell*(RtreeDValue)2));
- }
-
- for(ii=0; iinDim; iDim++){
- RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) -
- DCOORD(aCell[ii].aCoord[iDim*2]));
- aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]);
- }
- }
-
- SortByDistance(aOrder, nCell, aDistance, aSpare);
- nodeZero(pRtree, pNode);
-
- for(ii=0; rc==SQLITE_OK && ii<(nCell-(RTREE_MINCELLS(pRtree)+1)); ii++){
- RtreeCell *p = &aCell[aOrder[ii]];
- nodeInsertCell(pRtree, pNode, p);
- if( p->iRowid==pCell->iRowid ){
- if( iHeight==0 ){
- rc = rowidWrite(pRtree, p->iRowid, pNode->iNode);
- }else{
- rc = parentWrite(pRtree, p->iRowid, pNode->iNode);
- }
- }
- }
- if( rc==SQLITE_OK ){
- rc = fixBoundingBox(pRtree, pNode);
- }
- for(; rc==SQLITE_OK && iiiNode currently contains
- ** the height of the sub-tree headed by the cell.
- */
- RtreeNode *pInsert;
- RtreeCell *p = &aCell[aOrder[ii]];
- rc = ChooseLeaf(pRtree, p, iHeight, &pInsert);
- if( rc==SQLITE_OK ){
- int rc2;
- rc = rtreeInsertCell(pRtree, pInsert, p, iHeight);
- rc2 = nodeRelease(pRtree, pInsert);
- if( rc==SQLITE_OK ){
- rc = rc2;
- }
- }
- }
-
- sqlite3_free(aCell);
- return rc;
-}
-
/*
** Insert cell pCell into node pNode. Node pNode is the head of a
** subtree iHeight high (leaf nodes have iHeight==0).
@@ -205959,12 +210954,7 @@ static int rtreeInsertCell(
}
}
if( nodeInsertCell(pRtree, pNode, pCell) ){
- if( iHeight<=pRtree->iReinsertHeight || pNode->iNode==1){
- rc = SplitNode(pRtree, pNode, pCell, iHeight);
- }else{
- pRtree->iReinsertHeight = iHeight;
- rc = Reinsert(pRtree, pNode, pCell, iHeight);
- }
+ rc = SplitNode(pRtree, pNode, pCell, iHeight);
}else{
rc = AdjustTree(pRtree, pNode, pCell);
if( ALWAYS(rc==SQLITE_OK) ){
@@ -206307,7 +211297,6 @@ static int rtreeUpdate(
}
if( rc==SQLITE_OK ){
int rc2;
- pRtree->iReinsertHeight = -1;
rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0);
rc2 = nodeRelease(pRtree, pLeaf);
if( rc==SQLITE_OK ){
@@ -206448,8 +211437,11 @@ static int rtreeShadowName(const char *zName){
return 0;
}
+/* Forward declaration */
+static int rtreeIntegrity(sqlite3_vtab*, const char*, const char*, int, char**);
+
static sqlite3_module rtreeModule = {
- 3, /* iVersion */
+ 4, /* iVersion */
rtreeCreate, /* xCreate - create a table */
rtreeConnect, /* xConnect - connect to an existing table */
rtreeBestIndex, /* xBestIndex - Determine search strategy */
@@ -206472,7 +211464,8 @@ static sqlite3_module rtreeModule = {
rtreeSavepoint, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- rtreeShadowName /* xShadowName */
+ rtreeShadowName, /* xShadowName */
+ rtreeIntegrity /* xIntegrity */
};
static int rtreeSqlInit(
@@ -206728,22 +211721,27 @@ static int rtreeInit(
}
sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
+ sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
+
/* Allocate the sqlite3_vtab structure */
nDb = (int)strlen(argv[1]);
nName = (int)strlen(argv[2]);
- pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2);
+ pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName*2+8);
if( !pRtree ){
return SQLITE_NOMEM;
}
- memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2);
+ memset(pRtree, 0, sizeof(Rtree)+nDb+nName*2+8);
pRtree->nBusy = 1;
pRtree->base.pModule = &rtreeModule;
pRtree->zDb = (char *)&pRtree[1];
pRtree->zName = &pRtree->zDb[nDb+1];
+ pRtree->zNodeName = &pRtree->zName[nName+1];
pRtree->eCoordType = (u8)eCoordType;
memcpy(pRtree->zDb, argv[1], nDb);
memcpy(pRtree->zName, argv[2], nName);
+ memcpy(pRtree->zNodeName, argv[2], nName);
+ memcpy(&pRtree->zNodeName[nName], "_node", 6);
/* Create/Connect to the underlying relational database schema. If
@@ -207240,7 +212238,6 @@ static int rtreeCheckTable(
){
RtreeCheck check; /* Common context for various routines */
sqlite3_stmt *pStmt = 0; /* Used to find column count of rtree table */
- int bEnd = 0; /* True if transaction should be closed */
int nAux = 0; /* Number of extra columns. */
/* Initialize the context object */
@@ -207249,14 +212246,6 @@ static int rtreeCheckTable(
check.zDb = zDb;
check.zTab = zTab;
- /* If there is not already an open transaction, open one now. This is
- ** to ensure that the queries run as part of this integrity-check operate
- ** on a consistent snapshot. */
- if( sqlite3_get_autocommit(db) ){
- check.rc = sqlite3_exec(db, "BEGIN", 0, 0, 0);
- bEnd = 1;
- }
-
/* Find the number of auxiliary columns */
if( check.rc==SQLITE_OK ){
pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab);
@@ -207297,15 +212286,34 @@ static int rtreeCheckTable(
sqlite3_finalize(check.aCheckMapping[0]);
sqlite3_finalize(check.aCheckMapping[1]);
- /* If one was opened, close the transaction */
- if( bEnd ){
- int rc = sqlite3_exec(db, "END", 0, 0, 0);
- if( check.rc==SQLITE_OK ) check.rc = rc;
- }
*pzReport = check.zReport;
return check.rc;
}
+/*
+** Implementation of the xIntegrity method for Rtree.
+*/
+static int rtreeIntegrity(
+ sqlite3_vtab *pVtab, /* The virtual table to check */
+ const char *zSchema, /* Schema in which the virtual table lives */
+ const char *zName, /* Name of the virtual table */
+ int isQuick, /* True for a quick_check */
+ char **pzErr /* Write results here */
+){
+ Rtree *pRtree = (Rtree*)pVtab;
+ int rc;
+ assert( pzErr!=0 && *pzErr==0 );
+ UNUSED_PARAMETER(zSchema);
+ UNUSED_PARAMETER(zName);
+ UNUSED_PARAMETER(isQuick);
+ rc = rtreeCheckTable(pRtree->db, pRtree->zDb, pRtree->zName, pzErr);
+ if( rc==SQLITE_OK && *pzErr ){
+ *pzErr = sqlite3_mprintf("In RTree %s.%s:\n%z",
+ pRtree->zDb, pRtree->zName, *pzErr);
+ }
+ return rc;
+}
+
/*
** Usage:
**
@@ -208627,24 +213635,28 @@ static int geopolyInit(
(void)pAux;
sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
+ sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
/* Allocate the sqlite3_vtab structure */
nDb = strlen(argv[1]);
nName = strlen(argv[2]);
- pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2);
+ pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName*2+8);
if( !pRtree ){
return SQLITE_NOMEM;
}
- memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2);
+ memset(pRtree, 0, sizeof(Rtree)+nDb+nName*2+8);
pRtree->nBusy = 1;
pRtree->base.pModule = &rtreeModule;
pRtree->zDb = (char *)&pRtree[1];
pRtree->zName = &pRtree->zDb[nDb+1];
+ pRtree->zNodeName = &pRtree->zName[nName+1];
pRtree->eCoordType = RTREE_COORD_REAL32;
pRtree->nDim = 2;
pRtree->nDim2 = 4;
memcpy(pRtree->zDb, argv[1], nDb);
memcpy(pRtree->zName, argv[2], nName);
+ memcpy(pRtree->zNodeName, argv[2], nName);
+ memcpy(&pRtree->zNodeName[nName], "_node", 6);
/* Create/Connect to the underlying relational database schema. If
@@ -209058,7 +214070,6 @@ static int geopolyUpdate(
}
if( rc==SQLITE_OK ){
int rc2;
- pRtree->iReinsertHeight = -1;
rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0);
rc2 = nodeRelease(pRtree, pLeaf);
if( rc==SQLITE_OK ){
@@ -209155,7 +214166,8 @@ static sqlite3_module geopolyModule = {
rtreeSavepoint, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- rtreeShadowName /* xShadowName */
+ rtreeShadowName, /* xShadowName */
+ rtreeIntegrity /* xIntegrity */
};
static int sqlite3_geopoly_init(sqlite3 *db){
@@ -213996,6 +219008,11 @@ static void rbuCheckpointFrame(sqlite3rbu *p, RbuFrame *pFrame){
p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff);
}
+/*
+** This value is copied from the definition of ZIPVFS_CTRL_FILE_POINTER
+** in zipvfs.h.
+*/
+#define RBU_ZIPVFS_CTRL_FILE_POINTER 230439
/*
** Take an EXCLUSIVE lock on the database file. Return SQLITE_OK if
@@ -214004,9 +219021,20 @@ static void rbuCheckpointFrame(sqlite3rbu *p, RbuFrame *pFrame){
static int rbuLockDatabase(sqlite3 *db){
int rc = SQLITE_OK;
sqlite3_file *fd = 0;
- sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd);
- if( fd->pMethods ){
+ sqlite3_file_control(db, "main", RBU_ZIPVFS_CTRL_FILE_POINTER, &fd);
+ if( fd ){
+ sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd);
+ rc = fd->pMethods->xLock(fd, SQLITE_LOCK_SHARED);
+ if( rc==SQLITE_OK ){
+ rc = fd->pMethods->xUnlock(fd, SQLITE_LOCK_NONE);
+ }
+ sqlite3_file_control(db, "main", RBU_ZIPVFS_CTRL_FILE_POINTER, &fd);
+ }else{
+ sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd);
+ }
+
+ if( rc==SQLITE_OK && fd->pMethods ){
rc = fd->pMethods->xLock(fd, SQLITE_LOCK_SHARED);
if( rc==SQLITE_OK ){
rc = fd->pMethods->xLock(fd, SQLITE_LOCK_EXCLUSIVE);
@@ -217153,7 +222181,8 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
return sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
}
@@ -217243,6 +222272,7 @@ static int dbpageConnect(
(void)pzErr;
sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
+ sqlite3_vtab_config(db, SQLITE_VTAB_USES_ALL_SCHEMAS);
rc = sqlite3_declare_vtab(db,
"CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
if( rc==SQLITE_OK ){
@@ -217326,7 +222356,6 @@ static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
){
pIdxInfo->orderByConsumed = 1;
}
- sqlite3VtabUsesAllSchemas(pIdxInfo);
return SQLITE_OK;
}
@@ -217590,7 +222619,8 @@ SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
}
@@ -217627,6 +222657,8 @@ typedef struct SessionInput SessionInput;
# endif
#endif
+#define SESSIONS_ROWID "_rowid_"
+
static int sessions_strm_chunk_size = SESSIONS_STRM_CHUNK_SIZE;
typedef struct SessionHook SessionHook;
@@ -217648,6 +222680,7 @@ struct sqlite3_session {
int bEnable; /* True if currently recording */
int bIndirect; /* True if all changes are indirect */
int bAutoAttach; /* True to auto-attach tables */
+ int bImplicitPK; /* True to handle tables with implicit PK */
int rc; /* Non-zero if an error has occurred */
void *pFilterCtx; /* First argument to pass to xTableFilter */
int (*xTableFilter)(void *pCtx, const char *zTab);
@@ -217718,17 +222751,32 @@ struct sqlite3_changeset_iter {
** The data associated with each hash-table entry is a structure containing
** a subset of the initial values that the modified row contained at the
** start of the session. Or no initial values if the row was inserted.
+**
+** pDfltStmt:
+** This is only used by the sqlite3changegroup_xxx() APIs, not by
+** regular sqlite3_session objects. It is a SELECT statement that
+** selects the default value for each table column. For example,
+** if the table is
+**
+** CREATE TABLE xx(a DEFAULT 1, b, c DEFAULT 'abc')
+**
+** then this variable is the compiled version of:
+**
+** SELECT 1, NULL, 'abc'
*/
struct SessionTable {
SessionTable *pNext;
char *zName; /* Local name of table */
int nCol; /* Number of columns in table zName */
int bStat1; /* True if this is sqlite_stat1 */
+ int bRowid; /* True if this table uses rowid for PK */
const char **azCol; /* Column names */
+ const char **azDflt; /* Default value expressions */
u8 *abPK; /* Array of primary key flags */
int nEntry; /* Total number of entries in hash table */
int nChange; /* Size of apChange[] array */
SessionChange **apChange; /* Hash table buckets */
+ sqlite3_stmt *pDfltStmt;
};
/*
@@ -217897,6 +222945,7 @@ struct SessionTable {
struct SessionChange {
u8 op; /* One of UPDATE, DELETE, INSERT */
u8 bIndirect; /* True if this change is "indirect" */
+ u16 nRecordField; /* Number of fields in aRecord[] */
int nMaxSize; /* Max size of eventual changeset record */
int nRecord; /* Number of bytes in buffer aRecord[] */
u8 *aRecord; /* Buffer containing old.* record */
@@ -217922,7 +222971,7 @@ static int sessionVarintLen(int iVal){
** Read a varint value from aBuf[] into *piVal. Return the number of
** bytes read.
*/
-static int sessionVarintGet(u8 *aBuf, int *piVal){
+static int sessionVarintGet(const u8 *aBuf, int *piVal){
return getVarint32(aBuf, *piVal);
}
@@ -218116,6 +223165,7 @@ static unsigned int sessionHashAppendType(unsigned int h, int eType){
*/
static int sessionPreupdateHash(
sqlite3_session *pSession, /* Session object that owns pTab */
+ i64 iRowid,
SessionTable *pTab, /* Session table handle */
int bNew, /* True to hash the new.* PK */
int *piHash, /* OUT: Hash value */
@@ -218124,48 +223174,53 @@ static int sessionPreupdateHash(
unsigned int h = 0; /* Hash value to return */
int i; /* Used to iterate through columns */
- assert( *pbNullPK==0 );
- assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) );
- for(i=0; inCol; i++){
- if( pTab->abPK[i] ){
- int rc;
- int eType;
- sqlite3_value *pVal;
-
- if( bNew ){
- rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
- }else{
- rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
- }
- if( rc!=SQLITE_OK ) return rc;
+ if( pTab->bRowid ){
+ assert( pTab->nCol-1==pSession->hook.xCount(pSession->hook.pCtx) );
+ h = sessionHashAppendI64(h, iRowid);
+ }else{
+ assert( *pbNullPK==0 );
+ assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) );
+ for(i=0; inCol; i++){
+ if( pTab->abPK[i] ){
+ int rc;
+ int eType;
+ sqlite3_value *pVal;
- eType = sqlite3_value_type(pVal);
- h = sessionHashAppendType(h, eType);
- if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
- i64 iVal;
- if( eType==SQLITE_INTEGER ){
- iVal = sqlite3_value_int64(pVal);
+ if( bNew ){
+ rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
}else{
- double rVal = sqlite3_value_double(pVal);
- assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
- memcpy(&iVal, &rVal, 8);
+ rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
}
- h = sessionHashAppendI64(h, iVal);
- }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
- const u8 *z;
- int n;
- if( eType==SQLITE_TEXT ){
- z = (const u8 *)sqlite3_value_text(pVal);
+ if( rc!=SQLITE_OK ) return rc;
+
+ eType = sqlite3_value_type(pVal);
+ h = sessionHashAppendType(h, eType);
+ if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+ i64 iVal;
+ if( eType==SQLITE_INTEGER ){
+ iVal = sqlite3_value_int64(pVal);
+ }else{
+ double rVal = sqlite3_value_double(pVal);
+ assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
+ memcpy(&iVal, &rVal, 8);
+ }
+ h = sessionHashAppendI64(h, iVal);
+ }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
+ const u8 *z;
+ int n;
+ if( eType==SQLITE_TEXT ){
+ z = (const u8 *)sqlite3_value_text(pVal);
+ }else{
+ z = (const u8 *)sqlite3_value_blob(pVal);
+ }
+ n = sqlite3_value_bytes(pVal);
+ if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
+ h = sessionHashAppendBlob(h, n, z);
}else{
- z = (const u8 *)sqlite3_value_blob(pVal);
+ assert( eType==SQLITE_NULL );
+ assert( pTab->bStat1==0 || i!=1 );
+ *pbNullPK = 1;
}
- n = sqlite3_value_bytes(pVal);
- if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
- h = sessionHashAppendBlob(h, n, z);
- }else{
- assert( eType==SQLITE_NULL );
- assert( pTab->bStat1==0 || i!=1 );
- *pbNullPK = 1;
}
}
}
@@ -218179,9 +223234,11 @@ static int sessionPreupdateHash(
** Return the number of bytes of space occupied by the value (including
** the type byte).
*/
-static int sessionSerialLen(u8 *a){
- int e = *a;
+static int sessionSerialLen(const u8 *a){
+ int e;
int n;
+ assert( a!=0 );
+ e = *a;
if( e==0 || e==0xFF ) return 1;
if( e==SQLITE_NULL ) return 1;
if( e==SQLITE_INTEGER || e==SQLITE_FLOAT ) return 9;
@@ -218448,6 +223505,7 @@ static int sessionMergeUpdate(
*/
static int sessionPreupdateEqual(
sqlite3_session *pSession, /* Session object that owns SessionTable */
+ i64 iRowid, /* Rowid value if pTab->bRowid */
SessionTable *pTab, /* Table associated with change */
SessionChange *pChange, /* Change to compare to */
int op /* Current pre-update operation */
@@ -218455,6 +223513,11 @@ static int sessionPreupdateEqual(
int iCol; /* Used to iterate through columns */
u8 *a = pChange->aRecord; /* Cursor used to scan change record */
+ if( pTab->bRowid ){
+ if( a[0]!=SQLITE_INTEGER ) return 0;
+ return sessionGetI64(&a[1])==iRowid;
+ }
+
assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );
for(iCol=0; iColnCol; iCol++){
if( !pTab->abPK[iCol] ){
@@ -218477,6 +223540,7 @@ static int sessionPreupdateEqual(
rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal);
}
assert( rc==SQLITE_OK );
+ (void)rc; /* Suppress warning about unused variable */
if( sqlite3_value_type(pVal)!=eType ) return 0;
/* A SessionChange object never has a NULL value in a PK column */
@@ -218579,13 +223643,14 @@ static int sessionGrowHash(
**
** For example, if the table is declared as:
**
-** CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z));
+** CREATE TABLE tbl1(w, x DEFAULT 'abc', y, z, PRIMARY KEY(w, z));
**
-** Then the four output variables are populated as follows:
+** Then the five output variables are populated as follows:
**
** *pnCol = 4
** *pzTab = "tbl1"
** *pazCol = {"w", "x", "y", "z"}
+** *pazDflt = {NULL, 'abc', NULL, NULL}
** *pabPK = {1, 0, 0, 1}
**
** All returned buffers are part of the same single allocation, which must
@@ -218599,7 +223664,9 @@ static int sessionTableInfo(
int *pnCol, /* OUT: number of columns */
const char **pzTab, /* OUT: Copy of zThis */
const char ***pazCol, /* OUT: Array of column names for table */
- u8 **pabPK /* OUT: Array of booleans - true for PK col */
+ const char ***pazDflt, /* OUT: Array of default value expressions */
+ u8 **pabPK, /* OUT: Array of booleans - true for PK col */
+ int *pbRowid /* OUT: True if only PK is a rowid */
){
char *zPragma;
sqlite3_stmt *pStmt;
@@ -218610,10 +223677,18 @@ static int sessionTableInfo(
int i;
u8 *pAlloc = 0;
char **azCol = 0;
+ char **azDflt = 0;
u8 *abPK = 0;
+ int bRowid = 0; /* Set to true to use rowid as PK */
assert( pazCol && pabPK );
+ *pazCol = 0;
+ *pabPK = 0;
+ *pnCol = 0;
+ if( pzTab ) *pzTab = 0;
+ if( pazDflt ) *pazDflt = 0;
+
nThis = sqlite3Strlen30(zThis);
if( nThis==12 && 0==sqlite3_stricmp("sqlite_stat1", zThis) ){
rc = sqlite3_table_column_metadata(db, zDb, zThis, 0, 0, 0, 0, 0, 0);
@@ -218627,50 +223702,47 @@ static int sessionTableInfo(
}else if( rc==SQLITE_ERROR ){
zPragma = sqlite3_mprintf("");
}else{
- *pazCol = 0;
- *pabPK = 0;
- *pnCol = 0;
- if( pzTab ) *pzTab = 0;
return rc;
}
}else{
zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
}
if( !zPragma ){
- *pazCol = 0;
- *pabPK = 0;
- *pnCol = 0;
- if( pzTab ) *pzTab = 0;
return SQLITE_NOMEM;
}
rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
sqlite3_free(zPragma);
if( rc!=SQLITE_OK ){
- *pazCol = 0;
- *pabPK = 0;
- *pnCol = 0;
- if( pzTab ) *pzTab = 0;
return rc;
}
nByte = nThis + 1;
+ bRowid = (pbRowid!=0);
while( SQLITE_ROW==sqlite3_step(pStmt) ){
- nByte += sqlite3_column_bytes(pStmt, 1);
+ nByte += sqlite3_column_bytes(pStmt, 1); /* name */
+ nByte += sqlite3_column_bytes(pStmt, 4); /* dflt_value */
nDbCol++;
+ if( sqlite3_column_int(pStmt, 5) ) bRowid = 0; /* pk */
}
+ if( nDbCol==0 ) bRowid = 0;
+ nDbCol += bRowid;
+ nByte += strlen(SESSIONS_ROWID);
rc = sqlite3_reset(pStmt);
if( rc==SQLITE_OK ){
- nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
+ nByte += nDbCol * (sizeof(const char *)*2 + sizeof(u8) + 1 + 1);
pAlloc = sessionMalloc64(pSession, nByte);
if( pAlloc==0 ){
rc = SQLITE_NOMEM;
+ }else{
+ memset(pAlloc, 0, nByte);
}
}
if( rc==SQLITE_OK ){
azCol = (char **)pAlloc;
- pAlloc = (u8 *)&azCol[nDbCol];
+ azDflt = (char**)&azCol[nDbCol];
+ pAlloc = (u8 *)&azDflt[nDbCol];
abPK = (u8 *)pAlloc;
pAlloc = &abPK[nDbCol];
if( pzTab ){
@@ -218680,43 +223752,57 @@ static int sessionTableInfo(
}
i = 0;
+ if( bRowid ){
+ size_t nName = strlen(SESSIONS_ROWID);
+ memcpy(pAlloc, SESSIONS_ROWID, nName+1);
+ azCol[i] = (char*)pAlloc;
+ pAlloc += nName+1;
+ abPK[i] = 1;
+ i++;
+ }
while( SQLITE_ROW==sqlite3_step(pStmt) ){
int nName = sqlite3_column_bytes(pStmt, 1);
+ int nDflt = sqlite3_column_bytes(pStmt, 4);
const unsigned char *zName = sqlite3_column_text(pStmt, 1);
+ const unsigned char *zDflt = sqlite3_column_text(pStmt, 4);
+
if( zName==0 ) break;
memcpy(pAlloc, zName, nName+1);
azCol[i] = (char *)pAlloc;
pAlloc += nName+1;
+ if( zDflt ){
+ memcpy(pAlloc, zDflt, nDflt+1);
+ azDflt[i] = (char *)pAlloc;
+ pAlloc += nDflt+1;
+ }else{
+ azDflt[i] = 0;
+ }
abPK[i] = sqlite3_column_int(pStmt, 5);
i++;
}
rc = sqlite3_reset(pStmt);
-
}
/* If successful, populate the output variables. Otherwise, zero them and
** free any allocation made. An error code will be returned in this case.
*/
if( rc==SQLITE_OK ){
- *pazCol = (const char **)azCol;
+ *pazCol = (const char**)azCol;
+ if( pazDflt ) *pazDflt = (const char**)azDflt;
*pabPK = abPK;
*pnCol = nDbCol;
}else{
- *pazCol = 0;
- *pabPK = 0;
- *pnCol = 0;
- if( pzTab ) *pzTab = 0;
sessionFree(pSession, azCol);
}
+ if( pbRowid ) *pbRowid = bRowid;
sqlite3_finalize(pStmt);
return rc;
}
/*
-** This function is only called from within a pre-update handler for a
-** write to table pTab, part of session pSession. If this is the first
-** write to this table, initalize the SessionTable.nCol, azCol[] and
-** abPK[] arrays accordingly.
+** This function is called to initialize the SessionTable.nCol, azCol[]
+** abPK[] and azDflt[] members of SessionTable object pTab. If these
+** fields are already initilialized, this function is a no-op.
**
** If an error occurs, an error code is stored in sqlite3_session.rc and
** non-zero returned. Or, if no error occurs but the table has no primary
@@ -218724,14 +223810,22 @@ static int sessionTableInfo(
** indicate that updates on this table should be ignored. SessionTable.abPK
** is set to NULL in this case.
*/
-static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
+static int sessionInitTable(
+ sqlite3_session *pSession, /* Optional session handle */
+ SessionTable *pTab, /* Table object to initialize */
+ sqlite3 *db, /* Database handle to read schema from */
+ const char *zDb /* Name of db - "main", "temp" etc. */
+){
+ int rc = SQLITE_OK;
+
if( pTab->nCol==0 ){
u8 *abPK;
assert( pTab->azCol==0 || pTab->abPK==0 );
- pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb,
- pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK
+ rc = sessionTableInfo(pSession, db, zDb,
+ pTab->zName, &pTab->nCol, 0, &pTab->azCol, &pTab->azDflt, &abPK,
+ ((pSession==0 || pSession->bImplicitPK) ? &pTab->bRowid : 0)
);
- if( pSession->rc==SQLITE_OK ){
+ if( rc==SQLITE_OK ){
int i;
for(i=0; inCol; i++){
if( abPK[i] ){
@@ -218743,14 +223837,321 @@ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
pTab->bStat1 = 1;
}
- if( pSession->bEnableSize ){
+ if( pSession && pSession->bEnableSize ){
pSession->nMaxChangesetSize += (
1 + sessionVarintLen(pTab->nCol) + pTab->nCol + strlen(pTab->zName)+1
);
}
}
}
- return (pSession->rc || pTab->abPK==0);
+
+ if( pSession ){
+ pSession->rc = rc;
+ return (rc || pTab->abPK==0);
+ }
+ return rc;
+}
+
+/*
+** Re-initialize table object pTab.
+*/
+static int sessionReinitTable(sqlite3_session *pSession, SessionTable *pTab){
+ int nCol = 0;
+ const char **azCol = 0;
+ const char **azDflt = 0;
+ u8 *abPK = 0;
+ int bRowid = 0;
+
+ assert( pSession->rc==SQLITE_OK );
+
+ pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb,
+ pTab->zName, &nCol, 0, &azCol, &azDflt, &abPK,
+ (pSession->bImplicitPK ? &bRowid : 0)
+ );
+ if( pSession->rc==SQLITE_OK ){
+ if( pTab->nCol>nCol || pTab->bRowid!=bRowid ){
+ pSession->rc = SQLITE_SCHEMA;
+ }else{
+ int ii;
+ int nOldCol = pTab->nCol;
+ for(ii=0; iinCol ){
+ if( pTab->abPK[ii]!=abPK[ii] ){
+ pSession->rc = SQLITE_SCHEMA;
+ }
+ }else if( abPK[ii] ){
+ pSession->rc = SQLITE_SCHEMA;
+ }
+ }
+
+ if( pSession->rc==SQLITE_OK ){
+ const char **a = pTab->azCol;
+ pTab->azCol = azCol;
+ pTab->nCol = nCol;
+ pTab->azDflt = azDflt;
+ pTab->abPK = abPK;
+ azCol = a;
+ }
+ if( pSession->bEnableSize ){
+ pSession->nMaxChangesetSize += (nCol - nOldCol);
+ pSession->nMaxChangesetSize += sessionVarintLen(nCol);
+ pSession->nMaxChangesetSize -= sessionVarintLen(nOldCol);
+ }
+ }
+ }
+
+ sqlite3_free((char*)azCol);
+ return pSession->rc;
+}
+
+/*
+** Session-change object (*pp) contains an old.* record with fewer than
+** nCol fields. This function updates it with the default values for
+** the missing fields.
+*/
+static void sessionUpdateOneChange(
+ sqlite3_session *pSession, /* For memory accounting */
+ int *pRc, /* IN/OUT: Error code */
+ SessionChange **pp, /* IN/OUT: Change object to update */
+ int nCol, /* Number of columns now in table */
+ sqlite3_stmt *pDflt /* SELECT */
+){
+ SessionChange *pOld = *pp;
+
+ while( pOld->nRecordFieldnRecordField;
+ int eType = sqlite3_column_type(pDflt, iField);
+ switch( eType ){
+ case SQLITE_NULL:
+ nIncr = 1;
+ break;
+ case SQLITE_INTEGER:
+ case SQLITE_FLOAT:
+ nIncr = 9;
+ break;
+ default: {
+ int n = sqlite3_column_bytes(pDflt, iField);
+ nIncr = 1 + sessionVarintLen(n) + n;
+ assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
+ break;
+ }
+ }
+
+ nByte = nIncr + (sizeof(SessionChange) + pOld->nRecord);
+ pNew = sessionMalloc64(pSession, nByte);
+ if( pNew==0 ){
+ *pRc = SQLITE_NOMEM;
+ return;
+ }else{
+ memcpy(pNew, pOld, sizeof(SessionChange));
+ pNew->aRecord = (u8*)&pNew[1];
+ memcpy(pNew->aRecord, pOld->aRecord, pOld->nRecord);
+ pNew->aRecord[pNew->nRecord++] = (u8)eType;
+ switch( eType ){
+ case SQLITE_INTEGER: {
+ i64 iVal = sqlite3_column_int64(pDflt, iField);
+ sessionPutI64(&pNew->aRecord[pNew->nRecord], iVal);
+ pNew->nRecord += 8;
+ break;
+ }
+
+ case SQLITE_FLOAT: {
+ double rVal = sqlite3_column_double(pDflt, iField);
+ i64 iVal = 0;
+ memcpy(&iVal, &rVal, sizeof(rVal));
+ sessionPutI64(&pNew->aRecord[pNew->nRecord], iVal);
+ pNew->nRecord += 8;
+ break;
+ }
+
+ case SQLITE_TEXT: {
+ int n = sqlite3_column_bytes(pDflt, iField);
+ const char *z = (const char*)sqlite3_column_text(pDflt, iField);
+ pNew->nRecord += sessionVarintPut(&pNew->aRecord[pNew->nRecord], n);
+ memcpy(&pNew->aRecord[pNew->nRecord], z, n);
+ pNew->nRecord += n;
+ break;
+ }
+
+ case SQLITE_BLOB: {
+ int n = sqlite3_column_bytes(pDflt, iField);
+ const u8 *z = (const u8*)sqlite3_column_blob(pDflt, iField);
+ pNew->nRecord += sessionVarintPut(&pNew->aRecord[pNew->nRecord], n);
+ memcpy(&pNew->aRecord[pNew->nRecord], z, n);
+ pNew->nRecord += n;
+ break;
+ }
+
+ default:
+ assert( eType==SQLITE_NULL );
+ break;
+ }
+
+ sessionFree(pSession, pOld);
+ *pp = pOld = pNew;
+ pNew->nRecordField++;
+ pNew->nMaxSize += nIncr;
+ if( pSession ){
+ pSession->nMaxChangesetSize += nIncr;
+ }
+ }
+ }
+}
+
+/*
+** Ensure that there is room in the buffer to append nByte bytes of data.
+** If not, use sqlite3_realloc() to grow the buffer so that there is.
+**
+** If successful, return zero. Otherwise, if an OOM condition is encountered,
+** set *pRc to SQLITE_NOMEM and return non-zero.
+*/
+static int sessionBufferGrow(SessionBuffer *p, i64 nByte, int *pRc){
+#define SESSION_MAX_BUFFER_SZ (0x7FFFFF00 - 1)
+ i64 nReq = p->nBuf + nByte;
+ if( *pRc==SQLITE_OK && nReq>p->nAlloc ){
+ u8 *aNew;
+ i64 nNew = p->nAlloc ? p->nAlloc : 128;
+
+ do {
+ nNew = nNew*2;
+ }while( nNewSESSION_MAX_BUFFER_SZ ){
+ nNew = SESSION_MAX_BUFFER_SZ;
+ if( nNewaBuf, nNew);
+ if( 0==aNew ){
+ *pRc = SQLITE_NOMEM;
+ }else{
+ p->aBuf = aNew;
+ p->nAlloc = nNew;
+ }
+ }
+ return (*pRc!=SQLITE_OK);
+}
+
+
+/*
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** called. Otherwise, append a string to the buffer. All bytes in the string
+** up to (but not including) the nul-terminator are written to the buffer.
+**
+** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
+** returning.
+*/
+static void sessionAppendStr(
+ SessionBuffer *p,
+ const char *zStr,
+ int *pRc
+){
+ int nStr = sqlite3Strlen30(zStr);
+ if( 0==sessionBufferGrow(p, nStr+1, pRc) ){
+ memcpy(&p->aBuf[p->nBuf], zStr, nStr);
+ p->nBuf += nStr;
+ p->aBuf[p->nBuf] = 0x00;
+ }
+}
+
+/*
+** Format a string using printf() style formatting and then append it to the
+** buffer using sessionAppendString().
+*/
+static void sessionAppendPrintf(
+ SessionBuffer *p, /* Buffer to append to */
+ int *pRc,
+ const char *zFmt,
+ ...
+){
+ if( *pRc==SQLITE_OK ){
+ char *zApp = 0;
+ va_list ap;
+ va_start(ap, zFmt);
+ zApp = sqlite3_vmprintf(zFmt, ap);
+ if( zApp==0 ){
+ *pRc = SQLITE_NOMEM;
+ }else{
+ sessionAppendStr(p, zApp, pRc);
+ }
+ va_end(ap);
+ sqlite3_free(zApp);
+ }
+}
+
+/*
+** Prepare a statement against database handle db that SELECTs a single
+** row containing the default values for each column in table pTab. For
+** example, if pTab is declared as:
+**
+** CREATE TABLE pTab(a PRIMARY KEY, b DEFAULT 123, c DEFAULT 'abcd');
+**
+** Then this function prepares and returns the SQL statement:
+**
+** SELECT NULL, 123, 'abcd';
+*/
+static int sessionPrepareDfltStmt(
+ sqlite3 *db, /* Database handle */
+ SessionTable *pTab, /* Table to prepare statement for */
+ sqlite3_stmt **ppStmt /* OUT: Statement handle */
+){
+ SessionBuffer sql = {0,0,0};
+ int rc = SQLITE_OK;
+ const char *zSep = " ";
+ int ii = 0;
+
+ *ppStmt = 0;
+ sessionAppendPrintf(&sql, &rc, "SELECT");
+ for(ii=0; iinCol; ii++){
+ const char *zDflt = pTab->azDflt[ii] ? pTab->azDflt[ii] : "NULL";
+ sessionAppendPrintf(&sql, &rc, "%s%s", zSep, zDflt);
+ zSep = ", ";
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_prepare_v2(db, (const char*)sql.aBuf, -1, ppStmt, 0);
+ }
+ sqlite3_free(sql.aBuf);
+
+ return rc;
+}
+
+/*
+** Table pTab has one or more existing change-records with old.* records
+** with fewer than pTab->nCol columns. This function updates all such
+** change-records with the default values for the missing columns.
+*/
+static int sessionUpdateChanges(sqlite3_session *pSession, SessionTable *pTab){
+ sqlite3_stmt *pStmt = 0;
+ int rc = pSession->rc;
+
+ rc = sessionPrepareDfltStmt(pSession->db, pTab, &pStmt);
+ if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ int ii = 0;
+ SessionChange **pp = 0;
+ for(ii=0; iinChange; ii++){
+ for(pp=&pTab->apChange[ii]; *pp; pp=&((*pp)->pNext)){
+ if( (*pp)->nRecordField!=pTab->nCol ){
+ sessionUpdateOneChange(pSession, &rc, pp, pTab->nCol, pStmt);
+ }
+ }
+ }
+ }
+
+ pSession->rc = rc;
+ rc = sqlite3_finalize(pStmt);
+ if( pSession->rc==SQLITE_OK ) pSession->rc = rc;
+ return pSession->rc;
}
/*
@@ -218801,6 +224202,7 @@ static int sessionUpdateMaxSize(
){
i64 nNew = 2;
if( pC->op==SQLITE_INSERT ){
+ if( pTab->bRowid ) nNew += 9;
if( op!=SQLITE_DELETE ){
int ii;
for(ii=0; iinCol; ii++){
@@ -218817,12 +224219,16 @@ static int sessionUpdateMaxSize(
}else{
int ii;
u8 *pCsr = pC->aRecord;
- for(ii=0; iinCol; ii++){
+ if( pTab->bRowid ){
+ nNew += 9 + 1;
+ pCsr += 9;
+ }
+ for(ii=pTab->bRowid; iinCol; ii++){
int bChanged = 1;
int nOld = 0;
int eType;
sqlite3_value *p = 0;
- pSession->hook.xNew(pSession->hook.pCtx, ii, &p);
+ pSession->hook.xNew(pSession->hook.pCtx, ii-pTab->bRowid, &p);
if( p==0 ){
return SQLITE_NOMEM;
}
@@ -218901,22 +224307,29 @@ static int sessionUpdateMaxSize(
*/
static void sessionPreupdateOneChange(
int op, /* One of SQLITE_UPDATE, INSERT, DELETE */
+ i64 iRowid,
sqlite3_session *pSession, /* Session object pTab is attached to */
SessionTable *pTab /* Table that change applies to */
){
int iHash;
int bNull = 0;
int rc = SQLITE_OK;
+ int nExpect = 0;
SessionStat1Ctx stat1 = {{0,0,0,0,0},0};
if( pSession->rc ) return;
/* Load table details if required */
- if( sessionInitTable(pSession, pTab) ) return;
+ if( sessionInitTable(pSession, pTab, pSession->db, pSession->zDb) ) return;
/* Check the number of columns in this xPreUpdate call matches the
** number of columns in the table. */
- if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){
+ nExpect = pSession->hook.xCount(pSession->hook.pCtx);
+ if( (pTab->nCol-pTab->bRowid)nCol-pTab->bRowid)!=nExpect ){
pSession->rc = SQLITE_SCHEMA;
return;
}
@@ -218949,14 +224362,16 @@ static void sessionPreupdateOneChange(
/* Calculate the hash-key for this change. If the primary key of the row
** includes a NULL value, exit early. Such changes are ignored by the
** session module. */
- rc = sessionPreupdateHash(pSession, pTab, op==SQLITE_INSERT, &iHash, &bNull);
+ rc = sessionPreupdateHash(
+ pSession, iRowid, pTab, op==SQLITE_INSERT, &iHash, &bNull
+ );
if( rc!=SQLITE_OK ) goto error_out;
if( bNull==0 ){
/* Search the hash table for an existing record for this row. */
SessionChange *pC;
for(pC=pTab->apChange[iHash]; pC; pC=pC->pNext){
- if( sessionPreupdateEqual(pSession, pTab, pC, op) ) break;
+ if( sessionPreupdateEqual(pSession, iRowid, pTab, pC, op) ) break;
}
if( pC==0 ){
@@ -218971,7 +224386,7 @@ static void sessionPreupdateOneChange(
/* Figure out how large an allocation is required */
nByte = sizeof(SessionChange);
- for(i=0; inCol; i++){
+ for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
sqlite3_value *p = 0;
if( op!=SQLITE_INSERT ){
TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p);
@@ -218986,9 +224401,12 @@ static void sessionPreupdateOneChange(
rc = sessionSerializeValue(0, p, &nByte);
if( rc!=SQLITE_OK ) goto error_out;
}
+ if( pTab->bRowid ){
+ nByte += 9; /* Size of rowid field - an integer */
+ }
/* Allocate the change object */
- pC = (SessionChange *)sessionMalloc64(pSession, nByte);
+ pC = (SessionChange*)sessionMalloc64(pSession, nByte);
if( !pC ){
rc = SQLITE_NOMEM;
goto error_out;
@@ -219002,7 +224420,12 @@ static void sessionPreupdateOneChange(
** required values and encodings have already been cached in memory.
** It is not possible for an OOM to occur in this block. */
nByte = 0;
- for(i=0; inCol; i++){
+ if( pTab->bRowid ){
+ pC->aRecord[0] = SQLITE_INTEGER;
+ sessionPutI64(&pC->aRecord[1], iRowid);
+ nByte = 9;
+ }
+ for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
sqlite3_value *p = 0;
if( op!=SQLITE_INSERT ){
pSession->hook.xOld(pSession->hook.pCtx, i, &p);
@@ -219016,6 +224439,7 @@ static void sessionPreupdateOneChange(
if( pSession->bIndirect || pSession->hook.xDepth(pSession->hook.pCtx) ){
pC->bIndirect = 1;
}
+ pC->nRecordField = pTab->nCol;
pC->nRecord = nByte;
pC->op = op;
pC->pNext = pTab->apChange[iHash];
@@ -219117,9 +224541,10 @@ static void xPreUpdate(
pSession->rc = sessionFindTable(pSession, zName, &pTab);
if( pTab ){
assert( pSession->rc==SQLITE_OK );
- sessionPreupdateOneChange(op, pSession, pTab);
+ assert( op==SQLITE_UPDATE || iKey1==iKey2 );
+ sessionPreupdateOneChange(op, iKey1, pSession, pTab);
if( op==SQLITE_UPDATE ){
- sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab);
+ sessionPreupdateOneChange(SQLITE_INSERT, iKey2, pSession, pTab);
}
}
}
@@ -219158,6 +224583,7 @@ static void sessionPreupdateHooks(
typedef struct SessionDiffCtx SessionDiffCtx;
struct SessionDiffCtx {
sqlite3_stmt *pStmt;
+ int bRowid;
int nOldOff;
};
@@ -219166,17 +224592,17 @@ struct SessionDiffCtx {
*/
static int sessionDiffOld(void *pCtx, int iVal, sqlite3_value **ppVal){
SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
- *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff);
+ *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff+p->bRowid);
return SQLITE_OK;
}
static int sessionDiffNew(void *pCtx, int iVal, sqlite3_value **ppVal){
SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
- *ppVal = sqlite3_column_value(p->pStmt, iVal);
+ *ppVal = sqlite3_column_value(p->pStmt, iVal+p->bRowid);
return SQLITE_OK;
}
static int sessionDiffCount(void *pCtx){
SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
- return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt);
+ return (p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt)) - p->bRowid;
}
static int sessionDiffDepth(void *pCtx){
(void)pCtx;
@@ -219255,14 +224681,16 @@ static char *sessionExprCompareOther(
static char *sessionSelectFindNew(
const char *zDb1, /* Pick rows in this db only */
const char *zDb2, /* But not in this one */
+ int bRowid,
const char *zTbl, /* Table name */
const char *zExpr
){
+ const char *zSel = (bRowid ? SESSIONS_ROWID ", *" : "*");
char *zRet = sqlite3_mprintf(
- "SELECT * FROM \"%w\".\"%w\" WHERE NOT EXISTS ("
+ "SELECT %s FROM \"%w\".\"%w\" WHERE NOT EXISTS ("
" SELECT 1 FROM \"%w\".\"%w\" WHERE %s"
")",
- zDb1, zTbl, zDb2, zTbl, zExpr
+ zSel, zDb1, zTbl, zDb2, zTbl, zExpr
);
return zRet;
}
@@ -219276,7 +224704,9 @@ static int sessionDiffFindNew(
char *zExpr
){
int rc = SQLITE_OK;
- char *zStmt = sessionSelectFindNew(zDb1, zDb2, pTab->zName,zExpr);
+ char *zStmt = sessionSelectFindNew(
+ zDb1, zDb2, pTab->bRowid, pTab->zName, zExpr
+ );
if( zStmt==0 ){
rc = SQLITE_NOMEM;
@@ -219287,8 +224717,10 @@ static int sessionDiffFindNew(
SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
pDiffCtx->pStmt = pStmt;
pDiffCtx->nOldOff = 0;
+ pDiffCtx->bRowid = pTab->bRowid;
while( SQLITE_ROW==sqlite3_step(pStmt) ){
- sessionPreupdateOneChange(op, pSession, pTab);
+ i64 iRowid = (pTab->bRowid ? sqlite3_column_int64(pStmt, 0) : 0);
+ sessionPreupdateOneChange(op, iRowid, pSession, pTab);
}
rc = sqlite3_finalize(pStmt);
}
@@ -219298,6 +224730,27 @@ static int sessionDiffFindNew(
return rc;
}
+/*
+** Return a comma-separated list of the fully-qualified (with both database
+** and table name) column names from table pTab. e.g.
+**
+** "main"."t1"."a", "main"."t1"."b", "main"."t1"."c"
+*/
+static char *sessionAllCols(
+ const char *zDb,
+ SessionTable *pTab
+){
+ int ii;
+ char *zRet = 0;
+ for(ii=0; iinCol; ii++){
+ zRet = sqlite3_mprintf("%z%s\"%w\".\"%w\".\"%w\"",
+ zRet, (zRet ? ", " : ""), zDb, pTab->zName, pTab->azCol[ii]
+ );
+ if( !zRet ) break;
+ }
+ return zRet;
+}
+
static int sessionDiffFindModified(
sqlite3_session *pSession,
SessionTable *pTab,
@@ -219312,11 +224765,13 @@ static int sessionDiffFindModified(
if( zExpr2==0 ){
rc = SQLITE_NOMEM;
}else{
+ char *z1 = sessionAllCols(pSession->zDb, pTab);
+ char *z2 = sessionAllCols(zFrom, pTab);
char *zStmt = sqlite3_mprintf(
- "SELECT * FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)",
- pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2
+ "SELECT %s,%s FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)",
+ z1, z2, pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2
);
- if( zStmt==0 ){
+ if( zStmt==0 || z1==0 || z2==0 ){
rc = SQLITE_NOMEM;
}else{
sqlite3_stmt *pStmt;
@@ -219327,12 +224782,15 @@ static int sessionDiffFindModified(
pDiffCtx->pStmt = pStmt;
pDiffCtx->nOldOff = pTab->nCol;
while( SQLITE_ROW==sqlite3_step(pStmt) ){
- sessionPreupdateOneChange(SQLITE_UPDATE, pSession, pTab);
+ i64 iRowid = (pTab->bRowid ? sqlite3_column_int64(pStmt, 0) : 0);
+ sessionPreupdateOneChange(SQLITE_UPDATE, iRowid, pSession, pTab);
}
rc = sqlite3_finalize(pStmt);
}
- sqlite3_free(zStmt);
}
+ sqlite3_free(zStmt);
+ sqlite3_free(z1);
+ sqlite3_free(z2);
}
return rc;
@@ -219361,7 +224819,7 @@ SQLITE_API int sqlite3session_diff(
/* Locate and if necessary initialize the target table object */
rc = sessionFindTable(pSession, zTbl, &pTo);
if( pTo==0 ) goto diff_out;
- if( sessionInitTable(pSession, pTo) ){
+ if( sessionInitTable(pSession, pTo, pSession->db, pSession->zDb) ){
rc = pSession->rc;
goto diff_out;
}
@@ -219371,9 +224829,12 @@ SQLITE_API int sqlite3session_diff(
int bHasPk = 0;
int bMismatch = 0;
int nCol; /* Columns in zFrom.zTbl */
+ int bRowid = 0;
u8 *abPK;
const char **azCol = 0;
- rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK);
+ rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, 0, &abPK,
+ pSession->bImplicitPK ? &bRowid : 0
+ );
if( rc==SQLITE_OK ){
if( pTo->nCol!=nCol ){
bMismatch = 1;
@@ -219486,6 +224947,7 @@ static void sessionDeleteTable(sqlite3_session *pSession, SessionTable *pList){
sessionFree(pSession, p);
}
}
+ sqlite3_finalize(pTab->pDfltStmt);
sessionFree(pSession, (char*)pTab->azCol); /* cast works around VC++ bug */
sessionFree(pSession, pTab->apChange);
sessionFree(pSession, pTab);
@@ -219520,7 +224982,7 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession){
/* Assert that all allocations have been freed and then free the
** session object itself. */
- assert( pSession->nMalloc==0 );
+ // assert( pSession->nMalloc==0 );
sqlite3_free(pSession);
}
@@ -219591,48 +225053,6 @@ SQLITE_API int sqlite3session_attach(
return rc;
}
-/*
-** Ensure that there is room in the buffer to append nByte bytes of data.
-** If not, use sqlite3_realloc() to grow the buffer so that there is.
-**
-** If successful, return zero. Otherwise, if an OOM condition is encountered,
-** set *pRc to SQLITE_NOMEM and return non-zero.
-*/
-static int sessionBufferGrow(SessionBuffer *p, i64 nByte, int *pRc){
-#define SESSION_MAX_BUFFER_SZ (0x7FFFFF00 - 1)
- i64 nReq = p->nBuf + nByte;
- if( *pRc==SQLITE_OK && nReq>p->nAlloc ){
- u8 *aNew;
- i64 nNew = p->nAlloc ? p->nAlloc : 128;
-
- do {
- nNew = nNew*2;
- }while( nNewSESSION_MAX_BUFFER_SZ ){
- nNew = SESSION_MAX_BUFFER_SZ;
- if( nNewaBuf, nNew);
- if( 0==aNew ){
- *pRc = SQLITE_NOMEM;
- }else{
- p->aBuf = aNew;
- p->nAlloc = nNew;
- }
- }
- return (*pRc!=SQLITE_OK);
-}
-
/*
** Append the value passed as the second argument to the buffer passed
** as the first.
@@ -219701,27 +225121,6 @@ static void sessionAppendBlob(
}
}
-/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
-** called. Otherwise, append a string to the buffer. All bytes in the string
-** up to (but not including) the nul-terminator are written to the buffer.
-**
-** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
-** returning.
-*/
-static void sessionAppendStr(
- SessionBuffer *p,
- const char *zStr,
- int *pRc
-){
- int nStr = sqlite3Strlen30(zStr);
- if( 0==sessionBufferGrow(p, nStr+1, pRc) ){
- memcpy(&p->aBuf[p->nBuf], zStr, nStr);
- p->nBuf += nStr;
- p->aBuf[p->nBuf] = 0x00;
- }
-}
-
/*
** This function is a no-op if *pRc is other than SQLITE_OK when it is
** called. Otherwise, append the string representation of integer iVal
@@ -219740,27 +225139,6 @@ static void sessionAppendInteger(
sessionAppendStr(p, aBuf, pRc);
}
-static void sessionAppendPrintf(
- SessionBuffer *p, /* Buffer to append to */
- int *pRc,
- const char *zFmt,
- ...
-){
- if( *pRc==SQLITE_OK ){
- char *zApp = 0;
- va_list ap;
- va_start(ap, zFmt);
- zApp = sqlite3_vmprintf(zFmt, ap);
- if( zApp==0 ){
- *pRc = SQLITE_NOMEM;
- }else{
- sessionAppendStr(p, zApp, pRc);
- }
- va_end(ap);
- sqlite3_free(zApp);
- }
-}
-
/*
** This function is a no-op if *pRc is other than SQLITE_OK when it is
** called. Otherwise, append the string zStr enclosed in quotes (") and
@@ -219922,7 +225300,7 @@ static int sessionAppendUpdate(
/* If at least one field has been modified, this is not a no-op. */
if( bChanged ) bNoop = 0;
- /* Add a field to the old.* record. This is omitted if this modules is
+ /* Add a field to the old.* record. This is omitted if this module is
** currently generating a patchset. */
if( bPatchset==0 ){
if( bChanged || abPK[i] ){
@@ -220024,6 +225402,7 @@ static int sessionSelectStmt(
int bIgnoreNoop,
const char *zDb, /* Database name */
const char *zTab, /* Table name */
+ int bRowid,
int nCol, /* Number of columns in table */
const char **azCol, /* Names of table columns */
u8 *abPK, /* PRIMARY KEY array */
@@ -220032,7 +225411,7 @@ static int sessionSelectStmt(
int rc = SQLITE_OK;
char *zSql = 0;
const char *zSep = "";
- const char *zCols = "*";
+ const char *zCols = bRowid ? SESSIONS_ROWID ", *" : "*";
int nSql = -1;
int i;
@@ -220051,7 +225430,6 @@ static int sessionSelectStmt(
zCols = "tbl, ?2, stat";
}else{
for(i=0; ipTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
if( pTab->nEntry ){
const char *zName = pTab->zName;
- int nCol = 0; /* Number of columns in table */
- u8 *abPK = 0; /* Primary key array */
- const char **azCol = 0; /* Table columns */
int i; /* Used to iterate through hash buckets */
sqlite3_stmt *pSel = 0; /* SELECT statement to query table pTab */
int nRewind = buf.nBuf; /* Initial size of write buffer */
int nNoop; /* Size of buffer after writing tbl header */
+ int nOldCol = pTab->nCol;
/* Check the table schema is still Ok. */
- rc = sessionTableInfo(0, db, pSession->zDb, zName, &nCol, 0,&azCol,&abPK);
- if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){
- rc = SQLITE_SCHEMA;
+ rc = sessionReinitTable(pSession, pTab);
+ if( rc==SQLITE_OK && pTab->nCol!=nOldCol ){
+ rc = sessionUpdateChanges(pSession, pTab);
}
/* Write a table header */
@@ -220270,8 +225646,8 @@ static int sessionGenerateChangeset(
/* Build and compile a statement to execute: */
if( rc==SQLITE_OK ){
- rc = sessionSelectStmt(
- db, 0, pSession->zDb, zName, nCol, azCol, abPK, &pSel
+ rc = sessionSelectStmt(db, 0, pSession->zDb,
+ zName, pTab->bRowid, pTab->nCol, pTab->azCol, pTab->abPK, &pSel
);
}
@@ -220280,22 +225656,22 @@ static int sessionGenerateChangeset(
SessionChange *p; /* Used to iterate through changes */
for(p=pTab->apChange[i]; rc==SQLITE_OK && p; p=p->pNext){
- rc = sessionSelectBind(pSel, nCol, abPK, p);
+ rc = sessionSelectBind(pSel, pTab->nCol, pTab->abPK, p);
if( rc!=SQLITE_OK ) continue;
if( sqlite3_step(pSel)==SQLITE_ROW ){
if( p->op==SQLITE_INSERT ){
int iCol;
sessionAppendByte(&buf, SQLITE_INSERT, &rc);
sessionAppendByte(&buf, p->bIndirect, &rc);
- for(iCol=0; iColnCol; iCol++){
sessionAppendCol(&buf, pSel, iCol, &rc);
}
}else{
- assert( abPK!=0 ); /* Because sessionSelectStmt() returned ok */
- rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, abPK);
+ assert( pTab->abPK!=0 );
+ rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, pTab->abPK);
}
}else if( p->op!=SQLITE_INSERT ){
- rc = sessionAppendDelete(&buf, bPatchset, p, nCol, abPK);
+ rc = sessionAppendDelete(&buf, bPatchset, p, pTab->nCol,pTab->abPK);
}
if( rc==SQLITE_OK ){
rc = sqlite3_reset(pSel);
@@ -220320,7 +225696,6 @@ static int sessionGenerateChangeset(
if( buf.nBuf==nNoop ){
buf.nBuf = nRewind;
}
- sqlite3_free((char*)azCol); /* cast works around VC++ bug */
}
}
@@ -220355,7 +225730,7 @@ SQLITE_API int sqlite3session_changeset(
int rc;
if( pnChangeset==0 || ppChangeset==0 ) return SQLITE_MISUSE;
- rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset,ppChangeset);
+ rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset, ppChangeset);
assert( rc || pnChangeset==0
|| pSession->bEnableSize==0 || *pnChangeset<=pSession->nMaxChangesetSize
);
@@ -220473,6 +225848,19 @@ SQLITE_API int sqlite3session_object_config(sqlite3_session *pSession, int op, v
break;
}
+ case SQLITE_SESSION_OBJCONFIG_ROWID: {
+ int iArg = *(int*)pArg;
+ if( iArg>=0 ){
+ if( pSession->pTable ){
+ rc = SQLITE_MISUSE;
+ }else{
+ pSession->bImplicitPK = (iArg!=0);
+ }
+ }
+ *(int*)pArg = pSession->bImplicitPK;
+ break;
+ }
+
default:
rc = SQLITE_MISUSE;
}
@@ -220731,15 +226119,19 @@ static int sessionReadRecord(
}
}
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
- sqlite3_int64 v = sessionGetI64(aVal);
- if( eType==SQLITE_INTEGER ){
- sqlite3VdbeMemSetInt64(apOut[i], v);
+ if( (pIn->nData-pIn->iNext)<8 ){
+ rc = SQLITE_CORRUPT_BKPT;
}else{
- double d;
- memcpy(&d, &v, 8);
- sqlite3VdbeMemSetDouble(apOut[i], d);
+ sqlite3_int64 v = sessionGetI64(aVal);
+ if( eType==SQLITE_INTEGER ){
+ sqlite3VdbeMemSetInt64(apOut[i], v);
+ }else{
+ double d;
+ memcpy(&d, &v, 8);
+ sqlite3VdbeMemSetDouble(apOut[i], d);
+ }
+ pIn->iNext += 8;
}
- pIn->iNext += 8;
}
}
}
@@ -221462,6 +226854,7 @@ struct SessionApplyCtx {
u8 bRebaseStarted; /* If table header is already in rebase */
u8 bRebase; /* True to collect rebase information */
u8 bIgnoreNoop; /* True to ignore no-op conflicts */
+ int bRowid;
};
/* Number of prepared UPDATE statements to cache. */
@@ -221712,8 +227105,9 @@ static int sessionSelectRow(
const char *zTab, /* Table name */
SessionApplyCtx *p /* Session changeset-apply context */
){
+ /* TODO */
return sessionSelectStmt(db, p->bIgnoreNoop,
- "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect
+ "main", zTab, p->bRowid, p->nCol, p->azCol, p->abPK, &p->pSelect
);
}
@@ -222409,6 +227803,7 @@ static int sessionChangesetApply(
sApply.bStat1 = 0;
sApply.bDeferConstraints = 1;
sApply.bRebaseStarted = 0;
+ sApply.bRowid = 0;
memset(&sApply.constraints, 0, sizeof(SessionBuffer));
/* If an xFilter() callback was specified, invoke it now. If the
@@ -222428,8 +227823,8 @@ static int sessionChangesetApply(
int i;
sqlite3changeset_pk(pIter, &abPK, 0);
- rc = sessionTableInfo(0,
- db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
+ rc = sessionTableInfo(0, db, "main", zNew,
+ &sApply.nCol, &zTab, &sApply.azCol, 0, &sApply.abPK, &sApply.bRowid
);
if( rc!=SQLITE_OK ) break;
for(i=0; iflags & SQLITE_FkNoAction;
+
+ if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){
+ db->flags |= ((u64)SQLITE_FkNoAction);
+ db->aDb[0].pSchema->schema_cookie -= 32;
+ }
+
if( rc==SQLITE_OK ){
rc = sessionChangesetApply(
db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
);
}
+
+ if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){
+ assert( db->flags & SQLITE_FkNoAction );
+ db->flags &= ~((u64)SQLITE_FkNoAction);
+ db->aDb[0].pSchema->schema_cookie -= 32;
+ }
return rc;
}
@@ -222653,6 +228061,9 @@ struct sqlite3_changegroup {
int rc; /* Error code */
int bPatch; /* True to accumulate patchsets */
SessionTable *pList; /* List of tables in current patch */
+
+ sqlite3 *db; /* Configured by changegroup_schema() */
+ char *zDb; /* Configured by changegroup_schema() */
};
/*
@@ -222673,6 +228084,7 @@ static int sessionChangeMerge(
){
SessionChange *pNew = 0;
int rc = SQLITE_OK;
+ assert( aRec!=0 );
if( !pExist ){
pNew = (SessionChange *)sqlite3_malloc64(sizeof(SessionChange) + nRec);
@@ -222838,6 +228250,114 @@ static int sessionChangeMerge(
return rc;
}
+/*
+** Check if a changeset entry with nCol columns and the PK array passed
+** as the final argument to this function is compatible with SessionTable
+** pTab. If so, return 1. Otherwise, if they are incompatible in some way,
+** return 0.
+*/
+static int sessionChangesetCheckCompat(
+ SessionTable *pTab,
+ int nCol,
+ u8 *abPK
+){
+ if( pTab->azCol && nColnCol ){
+ int ii;
+ for(ii=0; iinCol; ii++){
+ u8 bPK = (ii < nCol) ? abPK[ii] : 0;
+ if( pTab->abPK[ii]!=bPK ) return 0;
+ }
+ return 1;
+ }
+ return (pTab->nCol==nCol && 0==memcmp(abPK, pTab->abPK, nCol));
+}
+
+static int sessionChangesetExtendRecord(
+ sqlite3_changegroup *pGrp,
+ SessionTable *pTab,
+ int nCol,
+ int op,
+ const u8 *aRec,
+ int nRec,
+ SessionBuffer *pOut
+){
+ int rc = SQLITE_OK;
+ int ii = 0;
+
+ assert( pTab->azCol );
+ assert( nColnCol );
+
+ pOut->nBuf = 0;
+ if( op==SQLITE_INSERT || (op==SQLITE_DELETE && pGrp->bPatch==0) ){
+ /* Append the missing default column values to the record. */
+ sessionAppendBlob(pOut, aRec, nRec, &rc);
+ if( rc==SQLITE_OK && pTab->pDfltStmt==0 ){
+ rc = sessionPrepareDfltStmt(pGrp->db, pTab, &pTab->pDfltStmt);
+ }
+ for(ii=nCol; rc==SQLITE_OK && iinCol; ii++){
+ int eType = sqlite3_column_type(pTab->pDfltStmt, ii);
+ sessionAppendByte(pOut, eType, &rc);
+ switch( eType ){
+ case SQLITE_FLOAT:
+ case SQLITE_INTEGER: {
+ i64 iVal;
+ if( eType==SQLITE_INTEGER ){
+ iVal = sqlite3_column_int64(pTab->pDfltStmt, ii);
+ }else{
+ double rVal = sqlite3_column_int64(pTab->pDfltStmt, ii);
+ memcpy(&iVal, &rVal, sizeof(i64));
+ }
+ if( SQLITE_OK==sessionBufferGrow(pOut, 8, &rc) ){
+ sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal);
+ }
+ break;
+ }
+
+ case SQLITE_BLOB:
+ case SQLITE_TEXT: {
+ int n = sqlite3_column_bytes(pTab->pDfltStmt, ii);
+ sessionAppendVarint(pOut, n, &rc);
+ if( eType==SQLITE_TEXT ){
+ const u8 *z = (const u8*)sqlite3_column_text(pTab->pDfltStmt, ii);
+ sessionAppendBlob(pOut, z, n, &rc);
+ }else{
+ const u8 *z = (const u8*)sqlite3_column_blob(pTab->pDfltStmt, ii);
+ sessionAppendBlob(pOut, z, n, &rc);
+ }
+ break;
+ }
+
+ default:
+ assert( eType==SQLITE_NULL );
+ break;
+ }
+ }
+ }else if( op==SQLITE_UPDATE ){
+ /* Append missing "undefined" entries to the old.* record. And, if this
+ ** is an UPDATE, to the new.* record as well. */
+ int iOff = 0;
+ if( pGrp->bPatch==0 ){
+ for(ii=0; iinCol-nCol); ii++){
+ sessionAppendByte(pOut, 0x00, &rc);
+ }
+ }
+
+ sessionAppendBlob(pOut, &aRec[iOff], nRec-iOff, &rc);
+ for(ii=0; ii<(pTab->nCol-nCol); ii++){
+ sessionAppendByte(pOut, 0x00, &rc);
+ }
+ }else{
+ assert( op==SQLITE_DELETE && pGrp->bPatch );
+ sessionAppendBlob(pOut, aRec, nRec, &rc);
+ }
+
+ return rc;
+}
+
/*
** Add all changes in the changeset traversed by the iterator passed as
** the first argument to the changegroup hash tables.
@@ -222851,6 +228371,7 @@ static int sessionChangesetToHash(
int nRec;
int rc = SQLITE_OK;
SessionTable *pTab = 0;
+ SessionBuffer rec = {0, 0, 0};
while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec, 0) ){
const char *zNew;
@@ -222862,6 +228383,9 @@ static int sessionChangesetToHash(
SessionChange *pExist = 0;
SessionChange **pp;
+ /* Ensure that only changesets, or only patchsets, but not a mixture
+ ** of both, are being combined. It is an error to try to combine a
+ ** changeset and a patchset. */
if( pGrp->pList==0 ){
pGrp->bPatch = pIter->bPatchset;
}else if( pIter->bPatchset!=pGrp->bPatch ){
@@ -222894,18 +228418,38 @@ static int sessionChangesetToHash(
pTab->zName = (char*)&pTab->abPK[nCol];
memcpy(pTab->zName, zNew, nNew+1);
+ if( pGrp->db ){
+ pTab->nCol = 0;
+ rc = sessionInitTable(0, pTab, pGrp->db, pGrp->zDb);
+ if( rc ){
+ assert( pTab->azCol==0 );
+ sqlite3_free(pTab);
+ break;
+ }
+ }
+
/* The new object must be linked on to the end of the list, not
** simply added to the start of it. This is to ensure that the
** tables within the output of sqlite3changegroup_output() are in
** the right order. */
for(ppTab=&pGrp->pList; *ppTab; ppTab=&(*ppTab)->pNext);
*ppTab = pTab;
- }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){
+ }
+
+ if( !sessionChangesetCheckCompat(pTab, nCol, abPK) ){
rc = SQLITE_SCHEMA;
break;
}
}
+ if( nColnCol ){
+ assert( pGrp->db );
+ rc = sessionChangesetExtendRecord(pGrp, pTab, nCol, op, aRec, nRec, &rec);
+ if( rc ) break;
+ aRec = rec.aBuf;
+ nRec = rec.nBuf;
+ }
+
if( sessionGrowHash(0, pIter->bPatchset, pTab) ){
rc = SQLITE_NOMEM;
break;
@@ -222943,6 +228487,7 @@ static int sessionChangesetToHash(
}
}
+ sqlite3_free(rec.aBuf);
if( rc==SQLITE_OK ) rc = pIter->rc;
return rc;
}
@@ -223029,6 +228574,31 @@ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp){
return rc;
}
+/*
+** Provide a database schema to the changegroup object.
+*/
+SQLITE_API int sqlite3changegroup_schema(
+ sqlite3_changegroup *pGrp,
+ sqlite3 *db,
+ const char *zDb
+){
+ int rc = SQLITE_OK;
+
+ if( pGrp->pList || pGrp->db ){
+ /* Cannot add a schema after one or more calls to sqlite3changegroup_add(),
+ ** or after sqlite3changegroup_schema() has already been called. */
+ rc = SQLITE_MISUSE;
+ }else{
+ pGrp->zDb = sqlite3_mprintf("%s", zDb);
+ if( pGrp->zDb==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ pGrp->db = db;
+ }
+ }
+ return rc;
+}
+
/*
** Add the changeset currently stored in buffer pData, size nData bytes,
** to changeset-group p.
@@ -223092,6 +228662,7 @@ SQLITE_API int sqlite3changegroup_output_strm(
*/
SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){
if( pGrp ){
+ sqlite3_free(pGrp->zDb);
sessionDeleteTable(0, pGrp->pList);
sqlite3_free(pGrp);
}
@@ -223799,7 +229370,7 @@ struct Fts5PhraseIter {
** See xPhraseFirstColumn above.
*/
struct Fts5ExtensionApi {
- int iVersion; /* Currently always set to 3 */
+ int iVersion; /* Currently always set to 2 */
void *(*xUserData)(Fts5Context*);
@@ -224028,8 +229599,8 @@ struct Fts5ExtensionApi {
** as separate queries of the FTS index are required for each synonym.
**
** When using methods (2) or (3), it is important that the tokenizer only
-** provide synonyms when tokenizing document text (method (2)) or query
-** text (method (3)), not both. Doing so will not cause any errors, but is
+** provide synonyms when tokenizing document text (method (3)) or query
+** text (method (2)), not both. Doing so will not cause any errors, but is
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
@@ -224077,7 +229648,7 @@ struct fts5_api {
int (*xCreateTokenizer)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_tokenizer *pTokenizer,
void (*xDestroy)(void*)
);
@@ -224086,7 +229657,7 @@ struct fts5_api {
int (*xFindTokenizer)(
fts5_api *pApi,
const char *zName,
- void **ppContext,
+ void **ppUserData,
fts5_tokenizer *pTokenizer
);
@@ -224094,7 +229665,7 @@ struct fts5_api {
int (*xCreateFunction)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
@@ -224266,6 +229837,10 @@ typedef struct Fts5Config Fts5Config;
** attempt to merge together. A value of 1 sets the object to use the
** compile time default. Zero disables auto-merge altogether.
**
+** bContentlessDelete:
+** True if the contentless_delete option was present in the CREATE
+** VIRTUAL TABLE statement.
+**
** zContent:
**
** zContentRowid:
@@ -224300,6 +229875,7 @@ struct Fts5Config {
int nPrefix; /* Number of prefix indexes */
int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */
int eContent; /* An FTS5_CONTENT value */
+ int bContentlessDelete; /* "contentless_delete=" option (dflt==0) */
char *zContent; /* content table */
char *zContentRowid; /* "content_rowid=" option value */
int bColumnsize; /* "columnsize=" option value (dflt==1) */
@@ -224311,6 +229887,7 @@ struct Fts5Config {
int ePattern; /* FTS_PATTERN_XXX constant */
/* Values loaded from the %_config table */
+ int iVersion; /* fts5 file format 'version' */
int iCookie; /* Incremented when %_config is modified */
int pgsz; /* Approximate page size used in %_data */
int nAutomerge; /* 'automerge' setting */
@@ -224319,6 +229896,8 @@ struct Fts5Config {
int nHashSize; /* Bytes of memory for in-memory hash */
char *zRank; /* Name of rank function */
char *zRankArgs; /* Arguments to rank function */
+ int bSecureDelete; /* 'secure-delete' */
+ int nDeleteMerge; /* 'deletemerge' */
/* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */
char **pzErrmsg;
@@ -224328,8 +229907,11 @@ struct Fts5Config {
#endif
};
-/* Current expected value of %_config table 'version' field */
-#define FTS5_CURRENT_VERSION 4
+/* Current expected value of %_config table 'version' field. And
+** the expected version if the 'secure-delete' option has ever been
+** set on the table. */
+#define FTS5_CURRENT_VERSION 4
+#define FTS5_CURRENT_VERSION_SECUREDELETE 5
#define FTS5_CONTENT_NORMAL 0
#define FTS5_CONTENT_NONE 1
@@ -224495,6 +230077,7 @@ struct Fts5IndexIter {
** above. */
#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010
#define FTS5INDEX_QUERY_NOOUTPUT 0x0020
+#define FTS5INDEX_QUERY_SKIPHASH 0x0040
/*
** Create/destroy an Fts5Index object.
@@ -224637,6 +230220,9 @@ static int sqlite3Fts5IndexReset(Fts5Index *p);
static int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
+static int sqlite3Fts5IndexGetOrigin(Fts5Index *p, i64 *piOrigin);
+static int sqlite3Fts5IndexContentlessDelete(Fts5Index *p, i64 iOrigin, i64 iRowid);
+
/*
** End of interface to code in fts5_index.c.
**************************************************************************/
@@ -224649,7 +230235,7 @@ static int sqlite3Fts5GetVarintLen(u32 iVal);
static u8 sqlite3Fts5GetVarint(const unsigned char*, u64*);
static int sqlite3Fts5PutVarint(unsigned char *p, u64 v);
-#define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&b)
+#define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&(b))
#define fts5GetVarint sqlite3Fts5GetVarint
#define fts5FastGetVarint32(a, iOff, nVal) { \
@@ -224721,6 +230307,11 @@ static int sqlite3Fts5HashWrite(
*/
static void sqlite3Fts5HashClear(Fts5Hash*);
+/*
+** Return true if the hash is empty, false otherwise.
+*/
+static int sqlite3Fts5HashIsEmpty(Fts5Hash*);
+
static int sqlite3Fts5HashQuery(
Fts5Hash*, /* Hash table to query */
int nPre,
@@ -224742,6 +230333,7 @@ static void sqlite3Fts5HashScanEntry(Fts5Hash *,
);
+
/*
** End of interface to code in fts5_hash.c.
**************************************************************************/
@@ -224985,7 +230577,8 @@ static void sqlite3Fts5UnicodeAscii(u8*, u8*);
#define FTS5_STAR 15
/* This file is automatically generated by Lemon from input grammar
-** source file "fts5parse.y". */
+** source file "fts5parse.y".
+*/
/*
** 2000-05-29
**
@@ -226575,15 +232168,19 @@ static int fts5CInstIterInit(
*/
typedef struct HighlightContext HighlightContext;
struct HighlightContext {
- CInstIter iter; /* Coalesced Instance Iterator */
- int iPos; /* Current token offset in zIn[] */
+ /* Constant parameters to fts5HighlightCb() */
int iRangeStart; /* First token to include */
int iRangeEnd; /* If non-zero, last token to include */
const char *zOpen; /* Opening highlight */
const char *zClose; /* Closing highlight */
const char *zIn; /* Input text */
int nIn; /* Size of input text in bytes */
- int iOff; /* Current offset within zIn[] */
+
+ /* Variables modified by fts5HighlightCb() */
+ CInstIter iter; /* Coalesced Instance Iterator */
+ int iPos; /* Current token offset in zIn[] */
+ int iOff; /* Have copied up to this offset in zIn[] */
+ int bOpen; /* True if highlight is open */
char *zOut; /* Output value */
};
@@ -226616,8 +232213,8 @@ static int fts5HighlightCb(
int tflags, /* Mask of FTS5_TOKEN_* flags */
const char *pToken, /* Buffer containing token */
int nToken, /* Size of token in bytes */
- int iStartOff, /* Start offset of token */
- int iEndOff /* End offset of token */
+ int iStartOff, /* Start byte offset of token */
+ int iEndOff /* End byte offset of token */
){
HighlightContext *p = (HighlightContext*)pContext;
int rc = SQLITE_OK;
@@ -226633,30 +232230,47 @@ static int fts5HighlightCb(
if( p->iRangeStart && iPos==p->iRangeStart ) p->iOff = iStartOff;
}
- if( iPos==p->iter.iStart ){
+ /* If the parenthesis is open, and this token is not part of the current
+ ** phrase, and the starting byte offset of this token is past the point
+ ** that has currently been copied into the output buffer, close the
+ ** parenthesis. */
+ if( p->bOpen
+ && (iPos<=p->iter.iStart || p->iter.iStart<0)
+ && iStartOff>p->iOff
+ ){
+ fts5HighlightAppend(&rc, p, p->zClose, -1);
+ p->bOpen = 0;
+ }
+
+ /* If this is the start of a new phrase, and the highlight is not open:
+ **
+ ** * copy text from the input up to the start of the phrase, and
+ ** * open the highlight.
+ */
+ if( iPos==p->iter.iStart && p->bOpen==0 ){
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iStartOff - p->iOff);
fts5HighlightAppend(&rc, p, p->zOpen, -1);
p->iOff = iStartOff;
+ p->bOpen = 1;
}
if( iPos==p->iter.iEnd ){
- if( p->iRangeEnd>=0 && p->iter.iStartiRangeStart ){
+ if( p->bOpen==0 ){
+ assert( p->iRangeEnd>=0 );
fts5HighlightAppend(&rc, p, p->zOpen, -1);
+ p->bOpen = 1;
}
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
- fts5HighlightAppend(&rc, p, p->zClose, -1);
p->iOff = iEndOff;
+
if( rc==SQLITE_OK ){
rc = fts5CInstIterNext(&p->iter);
}
}
- if( p->iRangeEnd>=0 && iPos==p->iRangeEnd ){
+ if( iPos==p->iRangeEnd ){
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
p->iOff = iEndOff;
- if( iPos>=p->iter.iStart && iPositer.iEnd ){
- fts5HighlightAppend(&rc, p, p->zClose, -1);
- }
}
return rc;
@@ -226697,6 +232311,9 @@ static void fts5HighlightFunction(
if( rc==SQLITE_OK ){
rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
}
+ if( ctx.bOpen ){
+ fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
+ }
fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
if( rc==SQLITE_OK ){
@@ -226975,6 +232592,9 @@ static void fts5SnippetFunction(
if( rc==SQLITE_OK ){
rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
}
+ if( ctx.bOpen ){
+ fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
+ }
if( ctx.iRangeEnd>=(nColSize-1) ){
fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
}else{
@@ -227613,6 +233233,8 @@ static void sqlite3Fts5TermsetFree(Fts5Termset *p){
#define FTS5_DEFAULT_CRISISMERGE 16
#define FTS5_DEFAULT_HASHSIZE (1024*1024)
+#define FTS5_DEFAULT_DELETE_AUTOMERGE 10 /* default 10% */
+
/* Maximum allowed page size */
#define FTS5_MAX_PAGE_SIZE (64*1024)
@@ -227943,6 +233565,16 @@ static int fts5ConfigParseSpecial(
return rc;
}
+ if( sqlite3_strnicmp("contentless_delete", zCmd, nCmd)==0 ){
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
+ *pzErr = sqlite3_mprintf("malformed contentless_delete=... directive");
+ rc = SQLITE_ERROR;
+ }else{
+ pConfig->bContentlessDelete = (zArg[0]=='1');
+ }
+ return rc;
+ }
+
if( sqlite3_strnicmp("content_rowid", zCmd, nCmd)==0 ){
if( pConfig->zContentRowid ){
*pzErr = sqlite3_mprintf("multiple content_rowid=... directives");
@@ -228141,6 +233773,7 @@ static int sqlite3Fts5ConfigParse(
rc = SQLITE_ERROR;
}
+ assert( (pRet->abUnindexed && pRet->azCol) || rc!=SQLITE_OK );
for(i=3; rc==SQLITE_OK && ibContentlessDelete
+ && pRet->eContent!=FTS5_CONTENT_NONE
+ ){
+ *pzErr = sqlite3_mprintf(
+ "contentless_delete=1 requires a contentless table"
+ );
+ rc = SQLITE_ERROR;
+ }
+
+ /* We only allow contentless_delete=1 if columnsize=0 is not present.
+ **
+ ** This restriction may be removed at some point.
+ */
+ if( rc==SQLITE_OK && pRet->bContentlessDelete && pRet->bColumnsize==0 ){
+ *pzErr = sqlite3_mprintf(
+ "contentless_delete=1 is incompatible with columnsize=0"
+ );
+ rc = SQLITE_ERROR;
+ }
+
/* If a tokenizer= option was successfully parsed, the tokenizer has
** already been allocated. Otherwise, allocate an instance of the default
** tokenizer (unicode61) now. */
@@ -228480,6 +234135,18 @@ static int sqlite3Fts5ConfigSetValue(
}
}
+ else if( 0==sqlite3_stricmp(zKey, "deletemerge") ){
+ int nVal = -1;
+ if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
+ nVal = sqlite3_value_int(pVal);
+ }else{
+ *pbBadkey = 1;
+ }
+ if( nVal<0 ) nVal = FTS5_DEFAULT_DELETE_AUTOMERGE;
+ if( nVal>100 ) nVal = 0;
+ pConfig->nDeleteMerge = nVal;
+ }
+
else if( 0==sqlite3_stricmp(zKey, "rank") ){
const char *zIn = (const char*)sqlite3_value_text(pVal);
char *zRank;
@@ -228494,6 +234161,18 @@ static int sqlite3Fts5ConfigSetValue(
rc = SQLITE_OK;
*pbBadkey = 1;
}
+ }
+
+ else if( 0==sqlite3_stricmp(zKey, "secure-delete") ){
+ int bVal = -1;
+ if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
+ bVal = sqlite3_value_int(pVal);
+ }
+ if( bVal<0 ){
+ *pbBadkey = 1;
+ }else{
+ pConfig->bSecureDelete = (bVal ? 1 : 0);
+ }
}else{
*pbBadkey = 1;
}
@@ -228516,6 +234195,7 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
pConfig->nUsermerge = FTS5_DEFAULT_USERMERGE;
pConfig->nCrisisMerge = FTS5_DEFAULT_CRISISMERGE;
pConfig->nHashSize = FTS5_DEFAULT_HASHSIZE;
+ pConfig->nDeleteMerge = FTS5_DEFAULT_DELETE_AUTOMERGE;
zSql = sqlite3Fts5Mprintf(&rc, zSelect, pConfig->zDb, pConfig->zName);
if( zSql ){
@@ -228538,15 +234218,20 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
rc = sqlite3_finalize(p);
}
- if( rc==SQLITE_OK && iVersion!=FTS5_CURRENT_VERSION ){
+ if( rc==SQLITE_OK
+ && iVersion!=FTS5_CURRENT_VERSION
+ && iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE
+ ){
rc = SQLITE_ERROR;
if( pConfig->pzErrmsg ){
assert( 0==*pConfig->pzErrmsg );
- *pConfig->pzErrmsg = sqlite3_mprintf(
- "invalid fts5 file format (found %d, expected %d) - run 'rebuild'",
- iVersion, FTS5_CURRENT_VERSION
+ *pConfig->pzErrmsg = sqlite3_mprintf("invalid fts5 file format "
+ "(found %d, expected %d or %d) - run 'rebuild'",
+ iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE
);
}
+ }else{
+ pConfig->iVersion = iVersion;
}
if( rc==SQLITE_OK ){
@@ -228574,6 +234259,10 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
/* #include "fts5Int.h" */
/* #include "fts5parse.h" */
+#ifndef SQLITE_FTS5_MAX_EXPR_DEPTH
+# define SQLITE_FTS5_MAX_EXPR_DEPTH 256
+#endif
+
/*
** All token types in the generated fts5parse.h file are greater than 0.
*/
@@ -228614,11 +234303,17 @@ struct Fts5Expr {
** FTS5_NOT (nChild, apChild valid)
** FTS5_STRING (pNear valid)
** FTS5_TERM (pNear valid)
+**
+** iHeight:
+** Distance from this node to furthest leaf. This is always 0 for nodes
+** of type FTS5_STRING and FTS5_TERM. For all other nodes it is one
+** greater than the largest child value.
*/
struct Fts5ExprNode {
int eType; /* Node type */
int bEof; /* True at EOF */
int bNomatch; /* True if entry is not a match */
+ int iHeight; /* Distance to tree leaf nodes */
/* Next method for this node. */
int (*xNext)(Fts5Expr*, Fts5ExprNode*, int, i64);
@@ -228688,6 +234383,31 @@ struct Fts5Parse {
int bPhraseToAnd; /* Convert "a+b" to "a AND b" */
};
+/*
+** Check that the Fts5ExprNode.iHeight variables are set correctly in
+** the expression tree passed as the only argument.
+*/
+#ifndef NDEBUG
+static void assert_expr_depth_ok(int rc, Fts5ExprNode *p){
+ if( rc==SQLITE_OK ){
+ if( p->eType==FTS5_TERM || p->eType==FTS5_STRING || p->eType==0 ){
+ assert( p->iHeight==0 );
+ }else{
+ int ii;
+ int iMaxChild = 0;
+ for(ii=0; iinChild; ii++){
+ Fts5ExprNode *pChild = p->apChild[ii];
+ iMaxChild = MAX(iMaxChild, pChild->iHeight);
+ assert_expr_depth_ok(SQLITE_OK, pChild);
+ }
+ assert( p->iHeight==iMaxChild+1 );
+ }
+ }
+}
+#else
+# define assert_expr_depth_ok(rc, p)
+#endif
+
static void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){
va_list ap;
va_start(ap, zFmt);
@@ -228802,6 +234522,8 @@ static int sqlite3Fts5ExprNew(
}while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
+ assert_expr_depth_ok(sParse.rc, sParse.pExpr);
+
/* If the LHS of the MATCH expression was a user column, apply the
** implicit column-filter. */
if( iColnCol && sParse.pExpr && sParse.rc==SQLITE_OK ){
@@ -228964,7 +234686,7 @@ static int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){
Fts5Parse sParse;
memset(&sParse, 0, sizeof(sParse));
- if( *pp1 ){
+ if( *pp1 && p2 ){
Fts5Expr *p1 = *pp1;
int nPhrase = p1->nPhrase + p2->nPhrase;
@@ -228989,7 +234711,7 @@ static int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){
}
sqlite3_free(p2->apExprPhrase);
sqlite3_free(p2);
- }else{
+ }else if( p2 ){
*pp1 = p2;
}
@@ -230763,6 +236485,7 @@ static void fts5ExprAssignXNext(Fts5ExprNode *pNode){
}
static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
+ int ii = p->nChild;
if( p->eType!=FTS5_NOT && pSub->eType==p->eType ){
int nByte = sizeof(Fts5ExprNode*) * pSub->nChild;
memcpy(&p->apChild[p->nChild], pSub->apChild, nByte);
@@ -230771,6 +236494,9 @@ static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
}else{
p->apChild[p->nChild++] = pSub;
}
+ for( ; iinChild; ii++){
+ p->iHeight = MAX(p->iHeight, p->apChild[ii]->iHeight + 1);
+ }
}
/*
@@ -230801,6 +236527,7 @@ static Fts5ExprNode *fts5ParsePhraseToAnd(
if( pRet ){
pRet->eType = FTS5_AND;
pRet->nChild = nTerm;
+ pRet->iHeight = 1;
fts5ExprAssignXNext(pRet);
pParse->nPhrase--;
for(ii=0; iiiHeight>SQLITE_FTS5_MAX_EXPR_DEPTH ){
+ sqlite3Fts5ParseError(pParse,
+ "fts5 expression tree is too large (maximum depth %d)",
+ SQLITE_FTS5_MAX_EXPR_DEPTH
+ );
+ sqlite3_free(pRet);
+ pRet = 0;
+ }
}
}
}
@@ -230984,7 +236719,7 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
return pRet;
}
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
sqlite3_int64 nByte = 0;
Fts5ExprTerm *p;
@@ -231090,6 +236825,8 @@ static char *fts5ExprPrintTcl(
if( zRet==0 ) return 0;
}
+ }else if( pExpr->eType==0 ){
+ zRet = sqlite3_mprintf("{}");
}else{
char const *zOp = 0;
int i;
@@ -231351,14 +237088,14 @@ static void fts5ExprFold(
sqlite3_result_int(pCtx, sqlite3Fts5UnicodeFold(iCode, bRemoveDiacritics));
}
}
-#endif /* ifdef SQLITE_TEST */
+#endif /* if SQLITE_TEST || SQLITE_FTS5_DEBUG */
/*
** This is called during initialization to register the fts5_expr() scalar
** UDF with the SQLite handle passed as the only argument.
*/
static int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
struct Fts5ExprFunc {
const char *z;
void (*x)(sqlite3_context*,int,sqlite3_value**);
@@ -232118,7 +237855,6 @@ static int fts5HashEntrySort(
pList = fts5HashEntryMerge(pList, ap[i]);
}
- pHash->nEntry = 0;
sqlite3_free(ap);
*ppSorted = pList;
return SQLITE_OK;
@@ -232172,6 +237908,28 @@ static int sqlite3Fts5HashScanInit(
return fts5HashEntrySort(p, pTerm, nTerm, &p->pScan);
}
+#ifdef SQLITE_DEBUG
+static int fts5HashCount(Fts5Hash *pHash){
+ int nEntry = 0;
+ int ii;
+ for(ii=0; iinSlot; ii++){
+ Fts5HashEntry *p = 0;
+ for(p=pHash->aSlot[ii]; p; p=p->pHashNext){
+ nEntry++;
+ }
+ }
+ return nEntry;
+}
+#endif
+
+/*
+** Return true if the hash table is empty, false otherwise.
+*/
+static int sqlite3Fts5HashIsEmpty(Fts5Hash *pHash){
+ assert( pHash->nEntry==fts5HashCount(pHash) );
+ return pHash->nEntry==0;
+}
+
static void sqlite3Fts5HashScanNext(Fts5Hash *p){
assert( !sqlite3Fts5HashScanEof(p) );
p->pScan = p->pScan->pScanNext;
@@ -232260,6 +238018,24 @@ static void sqlite3Fts5HashScanEntry(
#define FTS5_MAX_LEVEL 64
+/*
+** There are two versions of the format used for the structure record:
+**
+** 1. the legacy format, that may be read by all fts5 versions, and
+**
+** 2. the V2 format, which is used by contentless_delete=1 databases.
+**
+** Both begin with a 4-byte "configuration cookie" value. Then, a legacy
+** format structure record contains a varint - the number of levels in
+** the structure. Whereas a V2 structure record contains the constant
+** 4 bytes [0xff 0x00 0x00 0x01]. This is unambiguous as the value of a
+** varint has to be at least 16256 to begin with "0xFF". And the default
+** maximum number of levels is 64.
+**
+** See below for more on structure record formats.
+*/
+#define FTS5_STRUCTURE_V2 "\xFF\x00\x00\x01"
+
/*
** Details:
**
@@ -232267,7 +238043,7 @@ static void sqlite3Fts5HashScanEntry(
**
** CREATE TABLE %_data(id INTEGER PRIMARY KEY, block BLOB);
**
-** , contains the following 5 types of records. See the comments surrounding
+** , contains the following 6 types of records. See the comments surrounding
** the FTS5_*_ROWID macros below for a description of how %_data rowids are
** assigned to each fo them.
**
@@ -232276,12 +238052,12 @@ static void sqlite3Fts5HashScanEntry(
** The set of segments that make up an index - the index structure - are
** recorded in a single record within the %_data table. The record consists
** of a single 32-bit configuration cookie value followed by a list of
-** SQLite varints. If the FTS table features more than one index (because
-** there are one or more prefix indexes), it is guaranteed that all share
-** the same cookie value.
+** SQLite varints.
+**
+** If the structure record is a V2 record, the configuration cookie is
+** followed by the following 4 bytes: [0xFF 0x00 0x00 0x01].
**
-** Immediately following the configuration cookie, the record begins with
-** three varints:
+** Next, the record continues with three varints:
**
** + number of levels,
** + total number of segments on all levels,
@@ -232296,6 +238072,12 @@ static void sqlite3Fts5HashScanEntry(
** + first leaf page number (often 1, always greater than 0)
** + final leaf page number
**
+** Then, for V2 structures only:
+**
+** + lower origin counter value,
+** + upper origin counter value,
+** + the number of tombstone hash pages.
+**
** 2. The Averages Record:
**
** A single record within the %_data table. The data is a list of varints.
@@ -232411,6 +238193,38 @@ static void sqlite3Fts5HashScanEntry(
** * A list of delta-encoded varints - the first rowid on each subsequent
** child page.
**
+** 6. Tombstone Hash Page
+**
+** These records are only ever present in contentless_delete=1 tables.
+** There are zero or more of these associated with each segment. They
+** are used to store the tombstone rowids for rows contained in the
+** associated segments.
+**
+** The set of nHashPg tombstone hash pages associated with a single
+** segment together form a single hash table containing tombstone rowids.
+** To find the page of the hash on which a key might be stored:
+**
+** iPg = (rowid % nHashPg)
+**
+** Then, within page iPg, which has nSlot slots:
+**
+** iSlot = (rowid / nHashPg) % nSlot
+**
+** Each tombstone hash page begins with an 8 byte header:
+**
+** 1-byte: Key-size (the size in bytes of each slot). Either 4 or 8.
+** 1-byte: rowid-0-tombstone flag. This flag is only valid on the
+** first tombstone hash page for each segment (iPg=0). If set,
+** the hash table contains rowid 0. If clear, it does not.
+** Rowid 0 is handled specially.
+** 2-bytes: unused.
+** 4-bytes: Big-endian integer containing number of entries on page.
+**
+** Following this are nSlot 4 or 8 byte slots (depending on the key-size
+** in the first byte of the page header). The number of slots may be
+** determined based on the size of the page record and the key-size:
+**
+** nSlot = (nByte - 8) / key-size
*/
/*
@@ -232444,6 +238258,7 @@ static void sqlite3Fts5HashScanEntry(
#define FTS5_SEGMENT_ROWID(segid, pgno) fts5_dri(segid, 0, 0, pgno)
#define FTS5_DLIDX_ROWID(segid, height, pgno) fts5_dri(segid, 1, height, pgno)
+#define FTS5_TOMBSTONE_ROWID(segid,ipg) fts5_dri(segid+(1<<16), 0, 0, ipg)
#ifdef SQLITE_DEBUG
static int sqlite3Fts5Corrupt() { return SQLITE_CORRUPT_VTAB; }
@@ -232479,6 +238294,12 @@ struct Fts5Data {
/*
** One object per %_data table.
+**
+** nContentlessDelete:
+** The number of contentless delete operations since the most recent
+** call to fts5IndexFlush() or fts5IndexDiscardData(). This is tracked
+** so that extra auto-merge work can be done by fts5IndexFlush() to
+** account for the delete operations.
*/
struct Fts5Index {
Fts5Config *pConfig; /* Virtual table configuration */
@@ -232493,6 +238314,8 @@ struct Fts5Index {
int nPendingData; /* Current bytes of pending data */
i64 iWriteRowid; /* Rowid for current doc being written */
int bDelete; /* Current write is a delete */
+ int nContentlessDelete; /* Number of contentless delete ops */
+ int nPendingRow; /* Number of INSERT in hash table */
/* Error state. */
int rc; /* Current error code */
@@ -232506,6 +238329,8 @@ struct Fts5Index {
sqlite3_stmt *pIdxSelect;
int nRead; /* Total number of blocks read */
+ sqlite3_stmt *pDeleteFromIdx;
+
sqlite3_stmt *pDataVersion;
i64 iStructVersion; /* data_version when pStruct read */
Fts5Structure *pStruct; /* Current db structure (or NULL) */
@@ -232525,11 +238350,23 @@ struct Fts5DoclistIter {
** The contents of the "structure" record for each index are represented
** using an Fts5Structure record in memory. Which uses instances of the
** other Fts5StructureXXX types as components.
+**
+** nOriginCntr:
+** This value is set to non-zero for structure records created for
+** contentlessdelete=1 tables only. In that case it represents the
+** origin value to apply to the next top-level segment created.
*/
struct Fts5StructureSegment {
int iSegid; /* Segment id */
int pgnoFirst; /* First leaf page number in segment */
int pgnoLast; /* Last leaf page number in segment */
+
+ /* contentlessdelete=1 tables only: */
+ u64 iOrigin1;
+ u64 iOrigin2;
+ int nPgTombstone; /* Number of tombstone hash table pages */
+ u64 nEntryTombstone; /* Number of tombstone entries that "count" */
+ u64 nEntry; /* Number of rows in this segment */
};
struct Fts5StructureLevel {
int nMerge; /* Number of segments in incr-merge */
@@ -232539,6 +238376,7 @@ struct Fts5StructureLevel {
struct Fts5Structure {
int nRef; /* Object reference count */
u64 nWriteCounter; /* Total leaves written to level 0 */
+ u64 nOriginCntr; /* Origin value for next top-level segment */
int nSegment; /* Total segments in this structure */
int nLevel; /* Number of levels in this index */
Fts5StructureLevel aLevel[1]; /* Array of nLevel level objects */
@@ -232598,9 +238436,6 @@ struct Fts5CResult {
** iLeafOffset:
** Byte offset within the current leaf that is the first byte of the
** position list data (one byte passed the position-list size field).
-** rowid field of the current entry. Usually this is the size field of the
-** position list data. The exception is if the rowid for the current entry
-** is the last thing on the leaf page.
**
** pLeaf:
** Buffer containing current leaf page data. Set to NULL at EOF.
@@ -232630,6 +238465,13 @@ struct Fts5CResult {
**
** iTermIdx:
** Index of current term on iTermLeafPgno.
+**
+** apTombstone/nTombstone:
+** These are used for contentless_delete=1 tables only. When the cursor
+** is first allocated, the apTombstone[] array is allocated so that it
+** is large enough for all tombstones hash pages associated with the
+** segment. The pages themselves are loaded lazily from the database as
+** they are required.
*/
struct Fts5SegIter {
Fts5StructureSegment *pSeg; /* Segment to iterate through */
@@ -232638,6 +238480,8 @@ struct Fts5SegIter {
Fts5Data *pLeaf; /* Current leaf data */
Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */
i64 iLeafOffset; /* Byte offset within current leaf */
+ Fts5Data **apTombstone; /* Array of tombstone pages */
+ int nTombstone;
/* Next method */
void (*xNext)(Fts5Index*, Fts5SegIter*, int*);
@@ -232767,6 +238611,60 @@ static u16 fts5GetU16(const u8 *aIn){
return ((u16)aIn[0] << 8) + aIn[1];
}
+/*
+** The only argument points to a buffer at least 8 bytes in size. This
+** function interprets the first 8 bytes of the buffer as a 64-bit big-endian
+** unsigned integer and returns the result.
+*/
+static u64 fts5GetU64(u8 *a){
+ return ((u64)a[0] << 56)
+ + ((u64)a[1] << 48)
+ + ((u64)a[2] << 40)
+ + ((u64)a[3] << 32)
+ + ((u64)a[4] << 24)
+ + ((u64)a[5] << 16)
+ + ((u64)a[6] << 8)
+ + ((u64)a[7] << 0);
+}
+
+/*
+** The only argument points to a buffer at least 4 bytes in size. This
+** function interprets the first 4 bytes of the buffer as a 32-bit big-endian
+** unsigned integer and returns the result.
+*/
+static u32 fts5GetU32(const u8 *a){
+ return ((u32)a[0] << 24)
+ + ((u32)a[1] << 16)
+ + ((u32)a[2] << 8)
+ + ((u32)a[3] << 0);
+}
+
+/*
+** Write iVal, formated as a 64-bit big-endian unsigned integer, to the
+** buffer indicated by the first argument.
+*/
+static void fts5PutU64(u8 *a, u64 iVal){
+ a[0] = ((iVal >> 56) & 0xFF);
+ a[1] = ((iVal >> 48) & 0xFF);
+ a[2] = ((iVal >> 40) & 0xFF);
+ a[3] = ((iVal >> 32) & 0xFF);
+ a[4] = ((iVal >> 24) & 0xFF);
+ a[5] = ((iVal >> 16) & 0xFF);
+ a[6] = ((iVal >> 8) & 0xFF);
+ a[7] = ((iVal >> 0) & 0xFF);
+}
+
+/*
+** Write iVal, formated as a 32-bit big-endian unsigned integer, to the
+** buffer indicated by the first argument.
+*/
+static void fts5PutU32(u8 *a, u32 iVal){
+ a[0] = ((iVal >> 24) & 0xFF);
+ a[1] = ((iVal >> 16) & 0xFF);
+ a[2] = ((iVal >> 8) & 0xFF);
+ a[3] = ((iVal >> 0) & 0xFF);
+}
+
/*
** Allocate and return a buffer at least nByte bytes in size.
**
@@ -232994,10 +238892,17 @@ static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){
/*
** Remove all records associated with segment iSegid.
*/
-static void fts5DataRemoveSegment(Fts5Index *p, int iSegid){
+static void fts5DataRemoveSegment(Fts5Index *p, Fts5StructureSegment *pSeg){
+ int iSegid = pSeg->iSegid;
i64 iFirst = FTS5_SEGMENT_ROWID(iSegid, 0);
i64 iLast = FTS5_SEGMENT_ROWID(iSegid+1, 0)-1;
fts5DataDelete(p, iFirst, iLast);
+
+ if( pSeg->nPgTombstone ){
+ i64 iTomb1 = FTS5_TOMBSTONE_ROWID(iSegid, 0);
+ i64 iTomb2 = FTS5_TOMBSTONE_ROWID(iSegid, pSeg->nPgTombstone-1);
+ fts5DataDelete(p, iTomb1, iTomb2);
+ }
if( p->pIdxDeleter==0 ){
Fts5Config *pConfig = p->pConfig;
fts5IndexPrepareStmt(p, &p->pIdxDeleter, sqlite3_mprintf(
@@ -233108,11 +239013,19 @@ static int fts5StructureDecode(
int nSegment = 0;
sqlite3_int64 nByte; /* Bytes of space to allocate at pRet */
Fts5Structure *pRet = 0; /* Structure object to return */
+ int bStructureV2 = 0; /* True for FTS5_STRUCTURE_V2 */
+ u64 nOriginCntr = 0; /* Largest origin value seen so far */
/* Grab the cookie value */
if( piCookie ) *piCookie = sqlite3Fts5Get32(pData);
i = 4;
+ /* Check if this is a V2 structure record. Set bStructureV2 if it is. */
+ if( 0==memcmp(&pData[i], FTS5_STRUCTURE_V2, 4) ){
+ i += 4;
+ bStructureV2 = 1;
+ }
+
/* Read the total number of levels and segments from the start of the
** structure record. */
i += fts5GetVarint32(&pData[i], nLevel);
@@ -233159,9 +239072,18 @@ static int fts5StructureDecode(
rc = FTS5_CORRUPT;
break;
}
+ assert( pSeg!=0 );
i += fts5GetVarint32(&pData[i], pSeg->iSegid);
i += fts5GetVarint32(&pData[i], pSeg->pgnoFirst);
i += fts5GetVarint32(&pData[i], pSeg->pgnoLast);
+ if( bStructureV2 ){
+ i += fts5GetVarint(&pData[i], &pSeg->iOrigin1);
+ i += fts5GetVarint(&pData[i], &pSeg->iOrigin2);
+ i += fts5GetVarint32(&pData[i], pSeg->nPgTombstone);
+ i += fts5GetVarint(&pData[i], &pSeg->nEntryTombstone);
+ i += fts5GetVarint(&pData[i], &pSeg->nEntry);
+ nOriginCntr = MAX(nOriginCntr, pSeg->iOrigin2);
+ }
if( pSeg->pgnoLastpgnoFirst ){
rc = FTS5_CORRUPT;
break;
@@ -233172,6 +239094,9 @@ static int fts5StructureDecode(
}
}
if( nSegment!=0 && rc==SQLITE_OK ) rc = FTS5_CORRUPT;
+ if( bStructureV2 ){
+ pRet->nOriginCntr = nOriginCntr+1;
+ }
if( rc!=SQLITE_OK ){
fts5StructureRelease(pRet);
@@ -233189,6 +239114,7 @@ static int fts5StructureDecode(
*/
static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
fts5StructureMakeWritable(pRc, ppStruct);
+ assert( (ppStruct!=0 && (*ppStruct)!=0) || (*pRc)!=SQLITE_OK );
if( *pRc==SQLITE_OK ){
Fts5Structure *pStruct = *ppStruct;
int nLevel = pStruct->nLevel;
@@ -233383,6 +239309,7 @@ static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){
Fts5Buffer buf; /* Buffer to serialize record into */
int iLvl; /* Used to iterate through levels */
int iCookie; /* Cookie value to store */
+ int nHdr = (pStruct->nOriginCntr>0 ? (4+4+9+9+9) : (4+9+9));
assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
memset(&buf, 0, sizeof(Fts5Buffer));
@@ -233391,9 +239318,12 @@ static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){
iCookie = p->pConfig->iCookie;
if( iCookie<0 ) iCookie = 0;
- if( 0==sqlite3Fts5BufferSize(&p->rc, &buf, 4+9+9+9) ){
+ if( 0==sqlite3Fts5BufferSize(&p->rc, &buf, nHdr) ){
sqlite3Fts5Put32(buf.p, iCookie);
buf.n = 4;
+ if( pStruct->nOriginCntr>0 ){
+ fts5BufferSafeAppendBlob(&buf, FTS5_STRUCTURE_V2, 4);
+ }
fts5BufferSafeAppendVarint(&buf, pStruct->nLevel);
fts5BufferSafeAppendVarint(&buf, pStruct->nSegment);
fts5BufferSafeAppendVarint(&buf, (i64)pStruct->nWriteCounter);
@@ -233407,9 +239337,17 @@ static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){
assert( pLvl->nMerge<=pLvl->nSeg );
for(iSeg=0; iSegnSeg; iSeg++){
- fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].iSegid);
- fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoFirst);
- fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoLast);
+ Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->iSegid);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->pgnoFirst);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->pgnoLast);
+ if( pStruct->nOriginCntr>0 ){
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->iOrigin1);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->iOrigin2);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->nPgTombstone);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->nEntryTombstone);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->nEntry);
+ }
}
}
@@ -233647,42 +239585,25 @@ static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){
pLvl->bEof = 1;
}else{
u8 *a = pLvl->pData->p;
- i64 iVal;
- int iLimit;
- int ii;
- int nZero = 0;
-
- /* Currently iOff points to the first byte of a varint. This block
- ** decrements iOff until it points to the first byte of the previous
- ** varint. Taking care not to read any memory locations that occur
- ** before the buffer in memory. */
- iLimit = (iOff>9 ? iOff-9 : 0);
- for(iOff--; iOff>iLimit; iOff--){
- if( (a[iOff-1] & 0x80)==0 ) break;
- }
-
- fts5GetVarint(&a[iOff], (u64*)&iVal);
- pLvl->iRowid -= iVal;
- pLvl->iLeafPgno--;
-
- /* Skip backwards past any 0x00 varints. */
- for(ii=iOff-1; ii>=pLvl->iFirstOff && a[ii]==0x00; ii--){
- nZero++;
- }
- if( ii>=pLvl->iFirstOff && (a[ii] & 0x80) ){
- /* The byte immediately before the last 0x00 byte has the 0x80 bit
- ** set. So the last 0x00 is only a varint 0 if there are 8 more 0x80
- ** bytes before a[ii]. */
- int bZero = 0; /* True if last 0x00 counts */
- if( (ii-8)>=pLvl->iFirstOff ){
- int j;
- for(j=1; j<=8 && (a[ii-j] & 0x80); j++);
- bZero = (j>8);
+
+ pLvl->iOff = 0;
+ fts5DlidxLvlNext(pLvl);
+ while( 1 ){
+ int nZero = 0;
+ int ii = pLvl->iOff;
+ u64 delta = 0;
+
+ while( a[ii]==0 ){
+ nZero++;
+ ii++;
}
- if( bZero==0 ) nZero--;
+ ii += sqlite3Fts5GetVarint(&a[ii], &delta);
+
+ if( ii>=iOff ) break;
+ pLvl->iLeafPgno += nZero+1;
+ pLvl->iRowid += delta;
+ pLvl->iOff = ii;
}
- pLvl->iLeafPgno -= nZero;
- pLvl->iOff = iOff - nZero;
}
return pLvl->bEof;
@@ -233878,7 +239799,7 @@ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){
i64 iOff = pIter->iLeafOffset;
ASSERT_SZLEAF_OK(pIter->pLeaf);
- if( iOff>=pIter->pLeaf->szLeaf ){
+ while( iOff>=pIter->pLeaf->szLeaf ){
fts5SegIterNextPage(p, pIter);
if( pIter->pLeaf==0 ){
if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT;
@@ -233949,6 +239870,23 @@ static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){
}
}
+/*
+** Allocate a tombstone hash page array (pIter->apTombstone) for the
+** iterator passed as the second argument. If an OOM error occurs, leave
+** an error in the Fts5Index object.
+*/
+static void fts5SegIterAllocTombstone(Fts5Index *p, Fts5SegIter *pIter){
+ const int nTomb = pIter->pSeg->nPgTombstone;
+ if( nTomb>0 ){
+ Fts5Data **apTomb = 0;
+ apTomb = (Fts5Data**)sqlite3Fts5MallocZero(&p->rc, sizeof(Fts5Data)*nTomb);
+ if( apTomb ){
+ pIter->apTombstone = apTomb;
+ pIter->nTombstone = nTomb;
+ }
+ }
+}
+
/*
** Initialize the iterator object pIter to iterate through the entries in
** segment pSeg. The iterator is left pointing to the first entry when
@@ -233977,10 +239915,12 @@ static void fts5SegIterInit(
fts5SegIterSetNext(p, pIter);
pIter->pSeg = pSeg;
pIter->iLeafPgno = pSeg->pgnoFirst-1;
- fts5SegIterNextPage(p, pIter);
+ do {
+ fts5SegIterNextPage(p, pIter);
+ }while( p->rc==SQLITE_OK && pIter->pLeaf && pIter->pLeaf->nn==4 );
}
- if( p->rc==SQLITE_OK ){
+ if( p->rc==SQLITE_OK && pIter->pLeaf ){
pIter->iLeafOffset = 4;
assert( pIter->pLeaf!=0 );
assert_nc( pIter->pLeaf->nn>4 );
@@ -233988,6 +239928,7 @@ static void fts5SegIterInit(
pIter->iPgidxOff = pIter->pLeaf->szLeaf+1;
fts5SegIterLoadTerm(p, pIter, 0);
fts5SegIterLoadNPos(p, pIter);
+ fts5SegIterAllocTombstone(p, pIter);
}
}
@@ -234174,7 +240115,7 @@ static void fts5SegIterNext_None(
iOff = pIter->iLeafOffset;
/* Next entry is on the next page */
- if( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
+ while( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
fts5SegIterNextPage(p, pIter);
if( p->rc || pIter->pLeaf==0 ) return;
pIter->iRowid = 0;
@@ -234367,7 +240308,7 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
Fts5Data *pLast = 0;
int pgnoLast = 0;
- if( pDlidx ){
+ if( pDlidx && p->pConfig->iVersion==FTS5_CURRENT_VERSION ){
int iSegid = pIter->pSeg->iSegid;
pgnoLast = fts5DlidxIterPgno(pDlidx);
pLast = fts5LeafRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast));
@@ -234689,6 +240630,7 @@ static void fts5SegIterSeekInit(
}
fts5SegIterSetNext(p, pIter);
+ fts5SegIterAllocTombstone(p, pIter);
/* Either:
**
@@ -234769,6 +240711,20 @@ static void fts5SegIterHashInit(
fts5SegIterSetNext(p, pIter);
}
+/*
+** Array ap[] contains n elements. Release each of these elements using
+** fts5DataRelease(). Then free the array itself using sqlite3_free().
+*/
+static void fts5IndexFreeArray(Fts5Data **ap, int n){
+ if( ap ){
+ int ii;
+ for(ii=0; iiterm);
fts5DataRelease(pIter->pLeaf);
fts5DataRelease(pIter->pNextLeaf);
+ fts5IndexFreeArray(pIter->apTombstone, pIter->nTombstone);
fts5DlidxIterFree(pIter->pDlidx);
sqlite3_free(pIter->aRowidOffset);
memset(pIter, 0, sizeof(Fts5SegIter));
@@ -234909,7 +240866,6 @@ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
assert_nc( i2!=0 );
pRes->bTermEq = 1;
if( p1->iRowid==p2->iRowid ){
- p1->bDel = p2->bDel;
return i2;
}
res = ((p1->iRowid > p2->iRowid)==pIter->bRev) ? -1 : +1;
@@ -234928,7 +240884,8 @@ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
/*
** Move the seg-iter so that it points to the first rowid on page iLeafPgno.
-** It is an error if leaf iLeafPgno does not exist or contains no rowids.
+** It is an error if leaf iLeafPgno does not exist. Unless the db is
+** a 'secure-delete' db, if it contains no rowids then this is also an error.
*/
static void fts5SegIterGotoPage(
Fts5Index *p, /* FTS5 backend object */
@@ -234943,21 +240900,23 @@ static void fts5SegIterGotoPage(
fts5DataRelease(pIter->pNextLeaf);
pIter->pNextLeaf = 0;
pIter->iLeafPgno = iLeafPgno-1;
- fts5SegIterNextPage(p, pIter);
- assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno );
- if( p->rc==SQLITE_OK && ALWAYS(pIter->pLeaf!=0) ){
+ while( p->rc==SQLITE_OK ){
int iOff;
- u8 *a = pIter->pLeaf->p;
- int n = pIter->pLeaf->szLeaf;
-
+ fts5SegIterNextPage(p, pIter);
+ if( pIter->pLeaf==0 ) break;
iOff = fts5LeafFirstRowidOff(pIter->pLeaf);
- if( iOff<4 || iOff>=n ){
- p->rc = FTS5_CORRUPT;
- }else{
- iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid);
- pIter->iLeafOffset = iOff;
- fts5SegIterLoadNPos(p, pIter);
+ if( iOff>0 ){
+ u8 *a = pIter->pLeaf->p;
+ int n = pIter->pLeaf->szLeaf;
+ if( iOff<4 || iOff>=n ){
+ p->rc = FTS5_CORRUPT;
+ }else{
+ iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid);
+ pIter->iLeafOffset = iOff;
+ fts5SegIterLoadNPos(p, pIter);
+ }
+ break;
}
}
}
@@ -235110,6 +241069,84 @@ static void fts5MultiIterSetEof(Fts5Iter *pIter){
pIter->iSwitchRowid = pSeg->iRowid;
}
+/*
+** The argument to this macro must be an Fts5Data structure containing a
+** tombstone hash page. This macro returns the key-size of the hash-page.
+*/
+#define TOMBSTONE_KEYSIZE(pPg) (pPg->p[0]==4 ? 4 : 8)
+
+#define TOMBSTONE_NSLOT(pPg) \
+ ((pPg->nn > 16) ? ((pPg->nn-8) / TOMBSTONE_KEYSIZE(pPg)) : 1)
+
+/*
+** Query a single tombstone hash table for rowid iRowid. Return true if
+** it is found or false otherwise. The tombstone hash table is one of
+** nHashTable tables.
+*/
+static int fts5IndexTombstoneQuery(
+ Fts5Data *pHash, /* Hash table page to query */
+ int nHashTable, /* Number of pages attached to segment */
+ u64 iRowid /* Rowid to query hash for */
+){
+ const int szKey = TOMBSTONE_KEYSIZE(pHash);
+ const int nSlot = TOMBSTONE_NSLOT(pHash);
+ int iSlot = (iRowid / nHashTable) % nSlot;
+ int nCollide = nSlot;
+
+ if( iRowid==0 ){
+ return pHash->p[1];
+ }else if( szKey==4 ){
+ u32 *aSlot = (u32*)&pHash->p[8];
+ while( aSlot[iSlot] ){
+ if( fts5GetU32((u8*)&aSlot[iSlot])==iRowid ) return 1;
+ if( nCollide--==0 ) break;
+ iSlot = (iSlot+1)%nSlot;
+ }
+ }else{
+ u64 *aSlot = (u64*)&pHash->p[8];
+ while( aSlot[iSlot] ){
+ if( fts5GetU64((u8*)&aSlot[iSlot])==iRowid ) return 1;
+ if( nCollide--==0 ) break;
+ iSlot = (iSlot+1)%nSlot;
+ }
+ }
+
+ return 0;
+}
+
+/*
+** Return true if the iterator passed as the only argument points
+** to an segment entry for which there is a tombstone. Return false
+** if there is no tombstone or if the iterator is already at EOF.
+*/
+static int fts5MultiIterIsDeleted(Fts5Iter *pIter){
+ int iFirst = pIter->aFirst[1].iFirst;
+ Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
+
+ if( pSeg->pLeaf && pSeg->nTombstone ){
+ /* Figure out which page the rowid might be present on. */
+ int iPg = ((u64)pSeg->iRowid) % pSeg->nTombstone;
+ assert( iPg>=0 );
+
+ /* If tombstone hash page iPg has not yet been loaded from the
+ ** database, load it now. */
+ if( pSeg->apTombstone[iPg]==0 ){
+ pSeg->apTombstone[iPg] = fts5DataRead(pIter->pIndex,
+ FTS5_TOMBSTONE_ROWID(pSeg->pSeg->iSegid, iPg)
+ );
+ if( pSeg->apTombstone[iPg]==0 ) return 0;
+ }
+
+ return fts5IndexTombstoneQuery(
+ pSeg->apTombstone[iPg],
+ pSeg->nTombstone,
+ pSeg->iRowid
+ );
+ }
+
+ return 0;
+}
+
/*
** Move the iterator to the next entry.
**
@@ -235147,7 +241184,9 @@ static void fts5MultiIterNext(
fts5AssertMultiIterSetup(p, pIter);
assert( pSeg==&pIter->aSeg[pIter->aFirst[1].iFirst] && pSeg->pLeaf );
- if( pIter->bSkipEmpty==0 || pSeg->nPos ){
+ if( (pIter->bSkipEmpty==0 || pSeg->nPos)
+ && 0==fts5MultiIterIsDeleted(pIter)
+ ){
pIter->xSetOutputs(pIter, pSeg);
return;
}
@@ -235179,7 +241218,9 @@ static void fts5MultiIterNext2(
}
fts5AssertMultiIterSetup(p, pIter);
- }while( fts5MultiIterIsEmpty(p, pIter) );
+ }while( (fts5MultiIterIsEmpty(p, pIter) || fts5MultiIterIsDeleted(pIter))
+ && (p->rc==SQLITE_OK)
+ );
}
}
@@ -235192,7 +241233,7 @@ static Fts5Iter *fts5MultiIterAlloc(
int nSeg
){
Fts5Iter *pNew;
- int nSlot; /* Power of two >= nSeg */
+ i64 nSlot; /* Power of two >= nSeg */
for(nSlot=2; nSlotnSegment==fts5StructureCountSegments(pStruct) );
nSeg = pStruct->nSegment;
- nSeg += (p->pHash ? 1 : 0);
+ nSeg += (p->pHash && 0==(flags & FTS5INDEX_QUERY_SKIPHASH));
}else{
nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment);
}
@@ -235693,7 +241734,7 @@ static void fts5MultiIterNew(
if( p->rc==SQLITE_OK ){
if( iLevel<0 ){
Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel];
- if( p->pHash ){
+ if( p->pHash && 0==(flags & FTS5INDEX_QUERY_SKIPHASH) ){
/* Add a segment iterator for the current contents of the hash table. */
Fts5SegIter *pIter = &pNew->aSeg[iIter++];
fts5SegIterHashInit(p, pTerm, nTerm, flags, pIter);
@@ -235734,7 +241775,9 @@ static void fts5MultiIterNew(
fts5MultiIterSetEof(pNew);
fts5AssertMultiIterSetup(p, pNew);
- if( pNew->bSkipEmpty && fts5MultiIterIsEmpty(p, pNew) ){
+ if( (pNew->bSkipEmpty && fts5MultiIterIsEmpty(p, pNew))
+ || fts5MultiIterIsDeleted(pNew)
+ ){
fts5MultiIterNext(p, pNew, 0, 0);
}else if( pNew->base.bEof==0 ){
Fts5SegIter *pSeg = &pNew->aSeg[pNew->aFirst[1].iFirst];
@@ -235912,7 +241955,9 @@ static void fts5IndexDiscardData(Fts5Index *p){
if( p->pHash ){
sqlite3Fts5HashClear(p->pHash);
p->nPendingData = 0;
+ p->nPendingRow = 0;
}
+ p->nContentlessDelete = 0;
}
/*
@@ -236448,7 +242493,7 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr);
fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n);
fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p);
- fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff,&pData->p[iOff]);
+ fts5BufferAppendBlob(&p->rc, &buf,pData->szLeaf-iOff,&pData->p[iOff]);
if( p->rc==SQLITE_OK ){
/* Set the szLeaf field */
fts5PutU16(&buf.p[2], (u16)buf.n);
@@ -236549,6 +242594,12 @@ static void fts5IndexMergeLevel(
/* Read input from all segments in the input level */
nInput = pLvl->nSeg;
+
+ /* Set the range of origins that will go into the output segment. */
+ if( pStruct->nOriginCntr>0 ){
+ pSeg->iOrigin1 = pLvl->aSeg[0].iOrigin1;
+ pSeg->iOrigin2 = pLvl->aSeg[pLvl->nSeg-1].iOrigin2;
+ }
}
bOldest = (pLvlOut->nSeg==1 && pStruct->nLevel==iLvl+2);
@@ -236608,8 +242659,11 @@ static void fts5IndexMergeLevel(
int i;
/* Remove the redundant segments from the %_data table */
+ assert( pSeg->nEntry==0 );
for(i=0; iaSeg[i].iSegid);
+ Fts5StructureSegment *pOld = &pLvl->aSeg[i];
+ pSeg->nEntry += (pOld->nEntry - pOld->nEntryTombstone);
+ fts5DataRemoveSegment(p, pOld);
}
/* Remove the redundant segments from the input level */
@@ -236635,6 +242689,43 @@ static void fts5IndexMergeLevel(
if( pnRem ) *pnRem -= writer.nLeafWritten;
}
+/*
+** If this is not a contentless_delete=1 table, or if the 'deletemerge'
+** configuration option is set to 0, then this function always returns -1.
+** Otherwise, it searches the structure object passed as the second argument
+** for a level suitable for merging due to having a large number of
+** tombstones in the tombstone hash. If one is found, its index is returned.
+** Otherwise, if there is no suitable level, -1.
+*/
+static int fts5IndexFindDeleteMerge(Fts5Index *p, Fts5Structure *pStruct){
+ Fts5Config *pConfig = p->pConfig;
+ int iRet = -1;
+ if( pConfig->bContentlessDelete && pConfig->nDeleteMerge>0 ){
+ int ii;
+ int nBest = 0;
+
+ for(ii=0; iinLevel; ii++){
+ Fts5StructureLevel *pLvl = &pStruct->aLevel[ii];
+ i64 nEntry = 0;
+ i64 nTomb = 0;
+ int iSeg;
+ for(iSeg=0; iSegnSeg; iSeg++){
+ nEntry += pLvl->aSeg[iSeg].nEntry;
+ nTomb += pLvl->aSeg[iSeg].nEntryTombstone;
+ }
+ assert_nc( nEntry>0 || pLvl->nSeg==0 );
+ if( nEntry>0 ){
+ int nPercent = (nTomb * 100) / nEntry;
+ if( nPercent>=pConfig->nDeleteMerge && nPercent>nBest ){
+ iRet = ii;
+ nBest = nPercent;
+ }
+ }
+ }
+ }
+ return iRet;
+}
+
/*
** Do up to nPg pages of automerge work on the index.
**
@@ -236654,14 +242745,15 @@ static int fts5IndexMerge(
int iBestLvl = 0; /* Level offering the most input segments */
int nBest = 0; /* Number of input segments on best level */
- /* Set iBestLvl to the level to read input segments from. */
+ /* Set iBestLvl to the level to read input segments from. Or to -1 if
+ ** there is no level suitable to merge segments from. */
assert( pStruct->nLevel>0 );
for(iLvl=0; iLvlnLevel; iLvl++){
Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
if( pLvl->nMerge ){
if( pLvl->nMerge>nBest ){
iBestLvl = iLvl;
- nBest = pLvl->nMerge;
+ nBest = nMin;
}
break;
}
@@ -236670,22 +242762,18 @@ static int fts5IndexMerge(
iBestLvl = iLvl;
}
}
-
- /* If nBest is still 0, then the index must be empty. */
-#ifdef SQLITE_DEBUG
- for(iLvl=0; nBest==0 && iLvlnLevel; iLvl++){
- assert( pStruct->aLevel[iLvl].nSeg==0 );
+ if( nBestaLevel[iBestLvl].nMerge==0 ){
- break;
- }
+ if( iBestLvl<0 ) break;
bRet = 1;
fts5IndexMergeLevel(p, &pStruct, iBestLvl, &nRem);
if( p->rc==SQLITE_OK && pStruct->aLevel[iBestLvl].nMerge==0 ){
fts5StructurePromote(p, iBestLvl+1, pStruct);
}
+
+ if( nMin==1 ) nMin = 2;
}
*ppStruct = pStruct;
return bRet;
@@ -236726,16 +242814,16 @@ static void fts5IndexCrisismerge(
){
const int nCrisis = p->pConfig->nCrisisMerge;
Fts5Structure *pStruct = *ppStruct;
- int iLvl = 0;
-
- assert( p->rc!=SQLITE_OK || pStruct->nLevel>0 );
- while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){
- fts5IndexMergeLevel(p, &pStruct, iLvl, 0);
- assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) );
- fts5StructurePromote(p, iLvl+1, pStruct);
- iLvl++;
+ if( pStruct && pStruct->nLevel>0 ){
+ int iLvl = 0;
+ while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){
+ fts5IndexMergeLevel(p, &pStruct, iLvl, 0);
+ assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) );
+ fts5StructurePromote(p, iLvl+1, pStruct);
+ iLvl++;
+ }
+ *ppStruct = pStruct;
}
- *ppStruct = pStruct;
}
static int fts5IndexReturn(Fts5Index *p){
@@ -236769,6 +242857,463 @@ static int fts5PoslistPrefix(const u8 *aBuf, int nMax){
return ret;
}
+/*
+** Execute the SQL statement:
+**
+** DELETE FROM %_idx WHERE (segid, (pgno/2)) = ($iSegid, $iPgno);
+**
+** This is used when a secure-delete operation removes the last term
+** from a segment leaf page. In that case the %_idx entry is removed
+** too. This is done to ensure that if all instances of a token are
+** removed from an fts5 database in secure-delete mode, no trace of
+** the token itself remains in the database.
+*/
+static void fts5SecureDeleteIdxEntry(
+ Fts5Index *p, /* FTS5 backend object */
+ int iSegid, /* Id of segment to delete entry for */
+ int iPgno /* Page number within segment */
+){
+ if( iPgno!=1 ){
+ assert( p->pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE );
+ if( p->pDeleteFromIdx==0 ){
+ fts5IndexPrepareStmt(p, &p->pDeleteFromIdx, sqlite3_mprintf(
+ "DELETE FROM '%q'.'%q_idx' WHERE (segid, (pgno/2)) = (?1, ?2)",
+ p->pConfig->zDb, p->pConfig->zName
+ ));
+ }
+ if( p->rc==SQLITE_OK ){
+ sqlite3_bind_int(p->pDeleteFromIdx, 1, iSegid);
+ sqlite3_bind_int(p->pDeleteFromIdx, 2, iPgno);
+ sqlite3_step(p->pDeleteFromIdx);
+ p->rc = sqlite3_reset(p->pDeleteFromIdx);
+ }
+ }
+}
+
+/*
+** This is called when a secure-delete operation removes a position-list
+** that overflows onto segment page iPgno of segment pSeg. This function
+** rewrites node iPgno, and possibly one or more of its right-hand peers,
+** to remove this portion of the position list.
+**
+** Output variable (*pbLastInDoclist) is set to true if the position-list
+** removed is followed by a new term or the end-of-segment, or false if
+** it is followed by another rowid/position list.
+*/
+static void fts5SecureDeleteOverflow(
+ Fts5Index *p,
+ Fts5StructureSegment *pSeg,
+ int iPgno,
+ int *pbLastInDoclist
+){
+ const int bDetailNone = (p->pConfig->eDetail==FTS5_DETAIL_NONE);
+ int pgno;
+ Fts5Data *pLeaf = 0;
+ assert( iPgno!=1 );
+
+ *pbLastInDoclist = 1;
+ for(pgno=iPgno; p->rc==SQLITE_OK && pgno<=pSeg->pgnoLast; pgno++){
+ i64 iRowid = FTS5_SEGMENT_ROWID(pSeg->iSegid, pgno);
+ int iNext = 0;
+ u8 *aPg = 0;
+
+ pLeaf = fts5DataRead(p, iRowid);
+ if( pLeaf==0 ) break;
+ aPg = pLeaf->p;
+
+ iNext = fts5GetU16(&aPg[0]);
+ if( iNext!=0 ){
+ *pbLastInDoclist = 0;
+ }
+ if( iNext==0 && pLeaf->szLeaf!=pLeaf->nn ){
+ fts5GetVarint32(&aPg[pLeaf->szLeaf], iNext);
+ }
+
+ if( iNext==0 ){
+ /* The page contains no terms or rowids. Replace it with an empty
+ ** page and move on to the right-hand peer. */
+ const u8 aEmpty[] = {0x00, 0x00, 0x00, 0x04};
+ assert_nc( bDetailNone==0 || pLeaf->nn==4 );
+ if( bDetailNone==0 ) fts5DataWrite(p, iRowid, aEmpty, sizeof(aEmpty));
+ fts5DataRelease(pLeaf);
+ pLeaf = 0;
+ }else if( bDetailNone ){
+ break;
+ }else if( iNext>=pLeaf->szLeaf || pLeaf->nnszLeaf || iNext<4 ){
+ p->rc = FTS5_CORRUPT;
+ break;
+ }else{
+ int nShift = iNext - 4;
+ int nPg;
+
+ int nIdx = 0;
+ u8 *aIdx = 0;
+
+ /* Unless the current page footer is 0 bytes in size (in which case
+ ** the new page footer will be as well), allocate and populate a
+ ** buffer containing the new page footer. Set stack variables aIdx
+ ** and nIdx accordingly. */
+ if( pLeaf->nn>pLeaf->szLeaf ){
+ int iFirst = 0;
+ int i1 = pLeaf->szLeaf;
+ int i2 = 0;
+
+ i1 += fts5GetVarint32(&aPg[i1], iFirst);
+ if( iFirstrc = FTS5_CORRUPT;
+ break;
+ }
+ aIdx = sqlite3Fts5MallocZero(&p->rc, (pLeaf->nn-pLeaf->szLeaf)+2);
+ if( aIdx==0 ) break;
+ i2 = sqlite3Fts5PutVarint(aIdx, iFirst-nShift);
+ if( i1nn ){
+ memcpy(&aIdx[i2], &aPg[i1], pLeaf->nn-i1);
+ i2 += (pLeaf->nn-i1);
+ }
+ nIdx = i2;
+ }
+
+ /* Modify the contents of buffer aPg[]. Set nPg to the new size
+ ** in bytes. The new page is always smaller than the old. */
+ nPg = pLeaf->szLeaf - nShift;
+ memmove(&aPg[4], &aPg[4+nShift], nPg-4);
+ fts5PutU16(&aPg[2], nPg);
+ if( fts5GetU16(&aPg[0]) ) fts5PutU16(&aPg[0], 4);
+ if( nIdx>0 ){
+ memcpy(&aPg[nPg], aIdx, nIdx);
+ nPg += nIdx;
+ }
+ sqlite3_free(aIdx);
+
+ /* Write the new page to disk and exit the loop */
+ assert( nPg>4 || fts5GetU16(aPg)==0 );
+ fts5DataWrite(p, iRowid, aPg, nPg);
+ break;
+ }
+ }
+ fts5DataRelease(pLeaf);
+}
+
+/*
+** Completely remove the entry that pSeg currently points to from
+** the database.
+*/
+static void fts5DoSecureDelete(
+ Fts5Index *p,
+ Fts5SegIter *pSeg
+){
+ const int bDetailNone = (p->pConfig->eDetail==FTS5_DETAIL_NONE);
+ int iSegid = pSeg->pSeg->iSegid;
+ u8 *aPg = pSeg->pLeaf->p;
+ int nPg = pSeg->pLeaf->nn;
+ int iPgIdx = pSeg->pLeaf->szLeaf;
+
+ u64 iDelta = 0;
+ int iNextOff = 0;
+ int iOff = 0;
+ int nIdx = 0;
+ u8 *aIdx = 0;
+ int bLastInDoclist = 0;
+ int iIdx = 0;
+ int iStart = 0;
+ int iDelKeyOff = 0; /* Offset of deleted key, if any */
+
+ nIdx = nPg-iPgIdx;
+ aIdx = sqlite3Fts5MallocZero(&p->rc, nIdx+16);
+ if( p->rc ) return;
+ memcpy(aIdx, &aPg[iPgIdx], nIdx);
+
+ /* At this point segment iterator pSeg points to the entry
+ ** this function should remove from the b-tree segment.
+ **
+ ** In detail=full or detail=column mode, pSeg->iLeafOffset is the
+ ** offset of the first byte in the position-list for the entry to
+ ** remove. Immediately before this comes two varints that will also
+ ** need to be removed:
+ **
+ ** + the rowid or delta rowid value for the entry, and
+ ** + the size of the position list in bytes.
+ **
+ ** Or, in detail=none mode, there is a single varint prior to
+ ** pSeg->iLeafOffset - the rowid or delta rowid value.
+ **
+ ** This block sets the following variables:
+ **
+ ** iStart:
+ ** The offset of the first byte of the rowid or delta-rowid
+ ** value for the doclist entry being removed.
+ **
+ ** iDelta:
+ ** The value of the rowid or delta-rowid value for the doclist
+ ** entry being removed.
+ **
+ ** iNextOff:
+ ** The offset of the next entry following the position list
+ ** for the one being removed. If the position list for this
+ ** entry overflows onto the next leaf page, this value will be
+ ** greater than pLeaf->szLeaf.
+ */
+ {
+ int iSOP; /* Start-Of-Position-list */
+ if( pSeg->iLeafPgno==pSeg->iTermLeafPgno ){
+ iStart = pSeg->iTermLeafOffset;
+ }else{
+ iStart = fts5GetU16(&aPg[0]);
+ }
+
+ iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
+ assert_nc( iSOP<=pSeg->iLeafOffset );
+
+ if( bDetailNone ){
+ while( iSOPiLeafOffset ){
+ if( aPg[iSOP]==0x00 ) iSOP++;
+ if( aPg[iSOP]==0x00 ) iSOP++;
+ iStart = iSOP;
+ iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
+ }
+
+ iNextOff = iSOP;
+ if( iNextOffiEndofDoclist && aPg[iNextOff]==0x00 ) iNextOff++;
+ if( iNextOffiEndofDoclist && aPg[iNextOff]==0x00 ) iNextOff++;
+
+ }else{
+ int nPos = 0;
+ iSOP += fts5GetVarint32(&aPg[iSOP], nPos);
+ while( iSOPiLeafOffset ){
+ iStart = iSOP + (nPos/2);
+ iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
+ iSOP += fts5GetVarint32(&aPg[iSOP], nPos);
+ }
+ assert_nc( iSOP==pSeg->iLeafOffset );
+ iNextOff = pSeg->iLeafOffset + pSeg->nPos;
+ }
+ }
+
+ iOff = iStart;
+
+ /* Set variable bLastInDoclist to true if this entry happens to be
+ ** the last rowid in the doclist for its term. */
+ if( pSeg->bDel==0 ){
+ if( iNextOff>=iPgIdx ){
+ int pgno = pSeg->iLeafPgno+1;
+ fts5SecureDeleteOverflow(p, pSeg->pSeg, pgno, &bLastInDoclist);
+ iNextOff = iPgIdx;
+ }else{
+ /* Loop through the page-footer. If iNextOff (offset of the
+ ** entry following the one we are removing) is equal to the
+ ** offset of a key on this page, then the entry is the last
+ ** in its doclist. */
+ int iKeyOff = 0;
+ for(iIdx=0; iIdxbDel ){
+ iOff += sqlite3Fts5PutVarint(&aPg[iOff], iDelta);
+ aPg[iOff++] = 0x01;
+ }else if( bLastInDoclist==0 ){
+ if( iNextOff!=iPgIdx ){
+ u64 iNextDelta = 0;
+ iNextOff += fts5GetVarint(&aPg[iNextOff], &iNextDelta);
+ iOff += sqlite3Fts5PutVarint(&aPg[iOff], iDelta + iNextDelta);
+ }
+ }else if(
+ pSeg->iLeafPgno==pSeg->iTermLeafPgno
+ && iStart==pSeg->iTermLeafOffset
+ ){
+ /* The entry being removed was the only position list in its
+ ** doclist. Therefore the term needs to be removed as well. */
+ int iKey = 0;
+ int iKeyOff = 0;
+
+ /* Set iKeyOff to the offset of the term that will be removed - the
+ ** last offset in the footer that is not greater than iStart. */
+ for(iIdx=0; iIdx(u32)iStart ) break;
+ iKeyOff += iVal;
+ }
+ assert_nc( iKey>=1 );
+
+ /* Set iDelKeyOff to the value of the footer entry to remove from
+ ** the page. */
+ iDelKeyOff = iOff = iKeyOff;
+
+ if( iNextOff!=iPgIdx ){
+ /* This is the only position-list associated with the term, and there
+ ** is another term following it on this page. So the subsequent term
+ ** needs to be moved to replace the term associated with the entry
+ ** being removed. */
+ int nPrefix = 0;
+ int nSuffix = 0;
+ int nPrefix2 = 0;
+ int nSuffix2 = 0;
+
+ iDelKeyOff = iNextOff;
+ iNextOff += fts5GetVarint32(&aPg[iNextOff], nPrefix2);
+ iNextOff += fts5GetVarint32(&aPg[iNextOff], nSuffix2);
+
+ if( iKey!=1 ){
+ iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nPrefix);
+ }
+ iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nSuffix);
+
+ nPrefix = MIN(nPrefix, nPrefix2);
+ nSuffix = (nPrefix2 + nSuffix2) - nPrefix;
+
+ if( (iKeyOff+nSuffix)>iPgIdx || (iNextOff+nSuffix2)>iPgIdx ){
+ p->rc = FTS5_CORRUPT;
+ }else{
+ if( iKey!=1 ){
+ iOff += sqlite3Fts5PutVarint(&aPg[iOff], nPrefix);
+ }
+ iOff += sqlite3Fts5PutVarint(&aPg[iOff], nSuffix);
+ if( nPrefix2>pSeg->term.n ){
+ p->rc = FTS5_CORRUPT;
+ }else if( nPrefix2>nPrefix ){
+ memcpy(&aPg[iOff], &pSeg->term.p[nPrefix], nPrefix2-nPrefix);
+ iOff += (nPrefix2-nPrefix);
+ }
+ memmove(&aPg[iOff], &aPg[iNextOff], nSuffix2);
+ iOff += nSuffix2;
+ iNextOff += nSuffix2;
+ }
+ }
+ }else if( iStart==4 ){
+ int iPgno;
+
+ assert_nc( pSeg->iLeafPgno>pSeg->iTermLeafPgno );
+ /* The entry being removed may be the only position list in
+ ** its doclist. */
+ for(iPgno=pSeg->iLeafPgno-1; iPgno>pSeg->iTermLeafPgno; iPgno-- ){
+ Fts5Data *pPg = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, iPgno));
+ int bEmpty = (pPg && pPg->nn==4);
+ fts5DataRelease(pPg);
+ if( bEmpty==0 ) break;
+ }
+
+ if( iPgno==pSeg->iTermLeafPgno ){
+ i64 iId = FTS5_SEGMENT_ROWID(iSegid, pSeg->iTermLeafPgno);
+ Fts5Data *pTerm = fts5DataRead(p, iId);
+ if( pTerm && pTerm->szLeaf==pSeg->iTermLeafOffset ){
+ u8 *aTermIdx = &pTerm->p[pTerm->szLeaf];
+ int nTermIdx = pTerm->nn - pTerm->szLeaf;
+ int iTermIdx = 0;
+ int iTermOff = 0;
+
+ while( 1 ){
+ u32 iVal = 0;
+ int nByte = fts5GetVarint32(&aTermIdx[iTermIdx], iVal);
+ iTermOff += iVal;
+ if( (iTermIdx+nByte)>=nTermIdx ) break;
+ iTermIdx += nByte;
+ }
+ nTermIdx = iTermIdx;
+
+ memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx);
+ fts5PutU16(&pTerm->p[2], iTermOff);
+
+ fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx);
+ if( nTermIdx==0 ){
+ fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno);
+ }
+ }
+ fts5DataRelease(pTerm);
+ }
+ }
+
+ /* Assuming no error has occurred, this block does final edits to the
+ ** leaf page before writing it back to disk. Input variables are:
+ **
+ ** nPg: Total initial size of leaf page.
+ ** iPgIdx: Initial offset of page footer.
+ **
+ ** iOff: Offset to move data to
+ ** iNextOff: Offset to move data from
+ */
+ if( p->rc==SQLITE_OK ){
+ const int nMove = nPg - iNextOff; /* Number of bytes to move */
+ int nShift = iNextOff - iOff; /* Distance to move them */
+
+ int iPrevKeyOut = 0;
+ int iKeyIn = 0;
+
+ memmove(&aPg[iOff], &aPg[iNextOff], nMove);
+ iPgIdx -= nShift;
+ nPg = iPgIdx;
+ fts5PutU16(&aPg[2], iPgIdx);
+
+ for(iIdx=0; iIdxiOff ? nShift : 0));
+ nPg += sqlite3Fts5PutVarint(&aPg[nPg], iKeyOut - iPrevKeyOut);
+ iPrevKeyOut = iKeyOut;
+ }
+ }
+
+ if( iPgIdx==nPg && nIdx>0 && pSeg->iLeafPgno!=1 ){
+ fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iLeafPgno);
+ }
+
+ assert_nc( nPg>4 || fts5GetU16(aPg)==0 );
+ fts5DataWrite(p, FTS5_SEGMENT_ROWID(iSegid,pSeg->iLeafPgno), aPg, nPg);
+ }
+ sqlite3_free(aIdx);
+}
+
+/*
+** This is called as part of flushing a delete to disk in 'secure-delete'
+** mode. It edits the segments within the database described by argument
+** pStruct to remove the entries for term zTerm, rowid iRowid.
+*/
+static void fts5FlushSecureDelete(
+ Fts5Index *p,
+ Fts5Structure *pStruct,
+ const char *zTerm,
+ i64 iRowid
+){
+ const int f = FTS5INDEX_QUERY_SKIPHASH;
+ int nTerm = (int)strlen(zTerm);
+ Fts5Iter *pIter = 0; /* Used to find term instance */
+
+ fts5MultiIterNew(p, pStruct, f, 0, (const u8*)zTerm, nTerm, -1, 0, &pIter);
+ if( fts5MultiIterEof(p, pIter)==0 ){
+ i64 iThis = fts5MultiIterRowid(pIter);
+ if( iThisrc==SQLITE_OK
+ && fts5MultiIterEof(p, pIter)==0
+ && iRowid==fts5MultiIterRowid(pIter)
+ ){
+ Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
+ fts5DoSecureDelete(p, pSeg);
+ }
+ }
+
+ fts5MultiIterFree(pIter);
+}
+
+
/*
** Flush the contents of in-memory hash table iHash to a new level-0
** segment on disk. Also update the corresponding structure record.
@@ -236785,143 +243330,198 @@ static void fts5FlushOneHash(Fts5Index *p){
/* Obtain a reference to the index structure and allocate a new segment-id
** for the new level-0 segment. */
pStruct = fts5StructureRead(p);
- iSegid = fts5AllocateSegid(p, pStruct);
fts5StructureInvalidate(p);
- if( iSegid ){
- const int pgsz = p->pConfig->pgsz;
- int eDetail = p->pConfig->eDetail;
- Fts5StructureSegment *pSeg; /* New segment within pStruct */
- Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */
- Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */
-
- Fts5SegWriter writer;
- fts5WriteInit(p, &writer, iSegid);
-
- pBuf = &writer.writer.buf;
- pPgidx = &writer.writer.pgidx;
+ if( sqlite3Fts5HashIsEmpty(pHash)==0 ){
+ iSegid = fts5AllocateSegid(p, pStruct);
+ if( iSegid ){
+ const int pgsz = p->pConfig->pgsz;
+ int eDetail = p->pConfig->eDetail;
+ int bSecureDelete = p->pConfig->bSecureDelete;
+ Fts5StructureSegment *pSeg; /* New segment within pStruct */
+ Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */
+ Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */
+
+ Fts5SegWriter writer;
+ fts5WriteInit(p, &writer, iSegid);
+
+ pBuf = &writer.writer.buf;
+ pPgidx = &writer.writer.pgidx;
+
+ /* fts5WriteInit() should have initialized the buffers to (most likely)
+ ** the maximum space required. */
+ assert( p->rc || pBuf->nSpace>=(pgsz + FTS5_DATA_PADDING) );
+ assert( p->rc || pPgidx->nSpace>=(pgsz + FTS5_DATA_PADDING) );
+
+ /* Begin scanning through hash table entries. This loop runs once for each
+ ** term/doclist currently stored within the hash table. */
+ if( p->rc==SQLITE_OK ){
+ p->rc = sqlite3Fts5HashScanInit(pHash, 0, 0);
+ }
+ while( p->rc==SQLITE_OK && 0==sqlite3Fts5HashScanEof(pHash) ){
+ const char *zTerm; /* Buffer containing term */
+ int nTerm; /* Size of zTerm in bytes */
+ const u8 *pDoclist; /* Pointer to doclist for this term */
+ int nDoclist; /* Size of doclist in bytes */
+
+ /* Get the term and doclist for this entry. */
+ sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist);
+ nTerm = (int)strlen(zTerm);
+ if( bSecureDelete==0 ){
+ fts5WriteAppendTerm(p, &writer, nTerm, (const u8*)zTerm);
+ if( p->rc!=SQLITE_OK ) break;
+ assert( writer.bFirstRowidInPage==0 );
+ }
+
+ if( !bSecureDelete && pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
+ /* The entire doclist will fit on the current leaf. */
+ fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist);
+ }else{
+ int bTermWritten = !bSecureDelete;
+ i64 iRowid = 0;
+ i64 iPrev = 0;
+ int iOff = 0;
+
+ /* The entire doclist will not fit on this leaf. The following
+ ** loop iterates through the poslists that make up the current
+ ** doclist. */
+ while( p->rc==SQLITE_OK && iOffrc!=SQLITE_OK || pDoclist[iOff]==0x01 ){
+ iOff++;
+ continue;
+ }
+ }
+ }
- /* fts5WriteInit() should have initialized the buffers to (most likely)
- ** the maximum space required. */
- assert( p->rc || pBuf->nSpace>=(pgsz + FTS5_DATA_PADDING) );
- assert( p->rc || pPgidx->nSpace>=(pgsz + FTS5_DATA_PADDING) );
+ if( p->rc==SQLITE_OK && bTermWritten==0 ){
+ fts5WriteAppendTerm(p, &writer, nTerm, (const u8*)zTerm);
+ bTermWritten = 1;
+ assert( p->rc!=SQLITE_OK || writer.bFirstRowidInPage==0 );
+ }
- /* Begin scanning through hash table entries. This loop runs once for each
- ** term/doclist currently stored within the hash table. */
- if( p->rc==SQLITE_OK ){
- p->rc = sqlite3Fts5HashScanInit(pHash, 0, 0);
- }
- while( p->rc==SQLITE_OK && 0==sqlite3Fts5HashScanEof(pHash) ){
- const char *zTerm; /* Buffer containing term */
- const u8 *pDoclist; /* Pointer to doclist for this term */
- int nDoclist; /* Size of doclist in bytes */
-
- /* Write the term for this entry to disk. */
- sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist);
- fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm);
- if( p->rc!=SQLITE_OK ) break;
-
- assert( writer.bFirstRowidInPage==0 );
- if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
- /* The entire doclist will fit on the current leaf. */
- fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist);
- }else{
- i64 iRowid = 0;
- u64 iDelta = 0;
- int iOff = 0;
-
- /* The entire doclist will not fit on this leaf. The following
- ** loop iterates through the poslists that make up the current
- ** doclist. */
- while( p->rc==SQLITE_OK && iOffp[0], (u16)pBuf->n); /* first rowid on page */
- pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
- writer.bFirstRowidInPage = 0;
- fts5WriteDlidxAppend(p, &writer, iRowid);
+ if( writer.bFirstRowidInPage ){
+ fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */
+ pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
+ writer.bFirstRowidInPage = 0;
+ fts5WriteDlidxAppend(p, &writer, iRowid);
+ }else{
+ u64 iRowidDelta = (u64)iRowid - (u64)iPrev;
+ pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowidDelta);
+ }
if( p->rc!=SQLITE_OK ) break;
- }else{
- pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta);
- }
- assert( pBuf->n<=pBuf->nSpace );
+ assert( pBuf->n<=pBuf->nSpace );
+ iPrev = iRowid;
- if( eDetail==FTS5_DETAIL_NONE ){
- if( iOffp[pBuf->n++] = 0;
- iOff++;
+ if( eDetail==FTS5_DETAIL_NONE ){
if( iOffp[pBuf->n++] = 0;
iOff++;
+ if( iOffp[pBuf->n++] = 0;
+ iOff++;
+ }
+ }
+ if( (pBuf->n + pPgidx->n)>=pgsz ){
+ fts5WriteFlushLeaf(p, &writer);
}
- }
- if( (pBuf->n + pPgidx->n)>=pgsz ){
- fts5WriteFlushLeaf(p, &writer);
- }
- }else{
- int bDummy;
- int nPos;
- int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy);
- nCopy += nPos;
- if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
- /* The entire poslist will fit on the current leaf. So copy
- ** it in one go. */
- fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy);
}else{
- /* The entire poslist will not fit on this leaf. So it needs
- ** to be broken into sections. The only qualification being
- ** that each varint must be stored contiguously. */
- const u8 *pPoslist = &pDoclist[iOff];
- int iPos = 0;
- while( p->rc==SQLITE_OK ){
- int nSpace = pgsz - pBuf->n - pPgidx->n;
- int n = 0;
- if( (nCopy - iPos)<=nSpace ){
- n = nCopy - iPos;
- }else{
- n = fts5PoslistPrefix(&pPoslist[iPos], nSpace);
- }
- assert( n>0 );
- fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n);
- iPos += n;
- if( (pBuf->n + pPgidx->n)>=pgsz ){
- fts5WriteFlushLeaf(p, &writer);
+ int bDel = 0;
+ int nPos = 0;
+ int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDel);
+ if( bDel && bSecureDelete ){
+ fts5BufferAppendVarint(&p->rc, pBuf, nPos*2);
+ iOff += nCopy;
+ nCopy = nPos;
+ }else{
+ nCopy += nPos;
+ }
+ if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
+ /* The entire poslist will fit on the current leaf. So copy
+ ** it in one go. */
+ fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy);
+ }else{
+ /* The entire poslist will not fit on this leaf. So it needs
+ ** to be broken into sections. The only qualification being
+ ** that each varint must be stored contiguously. */
+ const u8 *pPoslist = &pDoclist[iOff];
+ int iPos = 0;
+ while( p->rc==SQLITE_OK ){
+ int nSpace = pgsz - pBuf->n - pPgidx->n;
+ int n = 0;
+ if( (nCopy - iPos)<=nSpace ){
+ n = nCopy - iPos;
+ }else{
+ n = fts5PoslistPrefix(&pPoslist[iPos], nSpace);
+ }
+ assert( n>0 );
+ fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n);
+ iPos += n;
+ if( (pBuf->n + pPgidx->n)>=pgsz ){
+ fts5WriteFlushLeaf(p, &writer);
+ }
+ if( iPos>=nCopy ) break;
}
- if( iPos>=nCopy ) break;
}
+ iOff += nCopy;
}
- iOff += nCopy;
}
}
- }
- /* TODO2: Doclist terminator written here. */
- /* pBuf->p[pBuf->n++] = '\0'; */
- assert( pBuf->n<=pBuf->nSpace );
- if( p->rc==SQLITE_OK ) sqlite3Fts5HashScanNext(pHash);
- }
- sqlite3Fts5HashClear(pHash);
- fts5WriteFinish(p, &writer, &pgnoLast);
+ /* TODO2: Doclist terminator written here. */
+ /* pBuf->p[pBuf->n++] = '\0'; */
+ assert( pBuf->n<=pBuf->nSpace );
+ if( p->rc==SQLITE_OK ) sqlite3Fts5HashScanNext(pHash);
+ }
+ fts5WriteFinish(p, &writer, &pgnoLast);
- /* Update the Fts5Structure. It is written back to the database by the
- ** fts5StructureRelease() call below. */
- if( pStruct->nLevel==0 ){
- fts5StructureAddLevel(&p->rc, &pStruct);
- }
- fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0);
- if( p->rc==SQLITE_OK ){
- pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ];
- pSeg->iSegid = iSegid;
- pSeg->pgnoFirst = 1;
- pSeg->pgnoLast = pgnoLast;
- pStruct->nSegment++;
+ assert( p->rc!=SQLITE_OK || bSecureDelete || pgnoLast>0 );
+ if( pgnoLast>0 ){
+ /* Update the Fts5Structure. It is written back to the database by the
+ ** fts5StructureRelease() call below. */
+ if( pStruct->nLevel==0 ){
+ fts5StructureAddLevel(&p->rc, &pStruct);
+ }
+ fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0);
+ if( p->rc==SQLITE_OK ){
+ pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ];
+ pSeg->iSegid = iSegid;
+ pSeg->pgnoFirst = 1;
+ pSeg->pgnoLast = pgnoLast;
+ if( pStruct->nOriginCntr>0 ){
+ pSeg->iOrigin1 = pStruct->nOriginCntr;
+ pSeg->iOrigin2 = pStruct->nOriginCntr;
+ pSeg->nEntry = p->nPendingRow;
+ pStruct->nOriginCntr++;
+ }
+ pStruct->nSegment++;
+ }
+ fts5StructurePromote(p, 0, pStruct);
+ }
}
- fts5StructurePromote(p, 0, pStruct);
}
- fts5IndexAutomerge(p, &pStruct, pgnoLast);
+ fts5IndexAutomerge(p, &pStruct, pgnoLast + p->nContentlessDelete);
fts5IndexCrisismerge(p, &pStruct);
fts5StructureWrite(p, pStruct);
fts5StructureRelease(pStruct);
@@ -236932,10 +243532,15 @@ static void fts5FlushOneHash(Fts5Index *p){
*/
static void fts5IndexFlush(Fts5Index *p){
/* Unless it is empty, flush the hash table to disk */
- if( p->nPendingData ){
+ if( p->nPendingData || p->nContentlessDelete ){
assert( p->pHash );
- p->nPendingData = 0;
fts5FlushOneHash(p);
+ if( p->rc==SQLITE_OK ){
+ sqlite3Fts5HashClear(p->pHash);
+ p->nPendingData = 0;
+ p->nPendingRow = 0;
+ p->nContentlessDelete = 0;
+ }
}
}
@@ -236951,17 +243556,22 @@ static Fts5Structure *fts5IndexOptimizeStruct(
/* Figure out if this structure requires optimization. A structure does
** not require optimization if either:
**
- ** + it consists of fewer than two segments, or
- ** + all segments are on the same level, or
- ** + all segments except one are currently inputs to a merge operation.
+ ** 1. it consists of fewer than two segments, or
+ ** 2. all segments are on the same level, or
+ ** 3. all segments except one are currently inputs to a merge operation.
**
- ** In the first case, return NULL. In the second, increment the ref-count
- ** on *pStruct and return a copy of the pointer to it.
+ ** In the first case, if there are no tombstone hash pages, return NULL. In
+ ** the second, increment the ref-count on *pStruct and return a copy of the
+ ** pointer to it.
*/
- if( nSeg<2 ) return 0;
+ if( nSeg==0 ) return 0;
for(i=0; inLevel; i++){
int nThis = pStruct->aLevel[i].nSeg;
- if( nThis==nSeg || (nThis==nSeg-1 && pStruct->aLevel[i].nMerge==nThis) ){
+ int nMerge = pStruct->aLevel[i].nMerge;
+ if( nThis>0 && (nThis==nSeg || (nThis==nSeg-1 && nMerge==nThis)) ){
+ if( nSeg==1 && nThis==1 && pStruct->aLevel[i].aSeg[0].nPgTombstone==0 ){
+ return 0;
+ }
fts5StructureRef(pStruct);
return pStruct;
}
@@ -236977,6 +243587,7 @@ static Fts5Structure *fts5IndexOptimizeStruct(
pNew->nLevel = MIN(pStruct->nLevel+1, FTS5_MAX_LEVEL);
pNew->nRef = 1;
pNew->nWriteCounter = pStruct->nWriteCounter;
+ pNew->nOriginCntr = pStruct->nOriginCntr;
pLvl = &pNew->aLevel[pNew->nLevel-1];
pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&p->rc, nByte);
if( pLvl->aSeg ){
@@ -237007,6 +243618,7 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){
assert( p->rc==SQLITE_OK );
fts5IndexFlush(p);
+ assert( p->nContentlessDelete==0 );
pStruct = fts5StructureRead(p);
fts5StructureInvalidate(p);
@@ -237036,7 +243648,10 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){
** INSERT command.
*/
static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
- Fts5Structure *pStruct = fts5StructureRead(p);
+ Fts5Structure *pStruct = 0;
+
+ fts5IndexFlush(p);
+ pStruct = fts5StructureRead(p);
if( pStruct ){
int nMin = p->pConfig->nUsermerge;
fts5StructureInvalidate(p);
@@ -237044,7 +243659,7 @@ static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
Fts5Structure *pNew = fts5IndexOptimizeStruct(p, pStruct);
fts5StructureRelease(pStruct);
pStruct = pNew;
- nMin = 2;
+ nMin = 1;
nMerge = nMerge*-1;
}
if( pStruct && pStruct->nLevel ){
@@ -237558,6 +244173,9 @@ static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
p->iWriteRowid = iRowid;
p->bDelete = bDelete;
+ if( bDelete==0 ){
+ p->nPendingRow++;
+ }
return fts5IndexReturn(p);
}
@@ -237595,6 +244213,9 @@ static int sqlite3Fts5IndexReinit(Fts5Index *p){
fts5StructureInvalidate(p);
fts5IndexDiscardData(p);
memset(&s, 0, sizeof(Fts5Structure));
+ if( p->pConfig->bContentlessDelete ){
+ s.nOriginCntr = 1;
+ }
fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0);
fts5StructureWrite(p, &s);
return fts5IndexReturn(p);
@@ -237659,6 +244280,7 @@ static int sqlite3Fts5IndexClose(Fts5Index *p){
sqlite3_finalize(p->pIdxDeleter);
sqlite3_finalize(p->pIdxSelect);
sqlite3_finalize(p->pDataVersion);
+ sqlite3_finalize(p->pDeleteFromIdx);
sqlite3Fts5HashFree(p->pHash);
sqlite3_free(p->zDataTbl);
sqlite3_free(p);
@@ -237985,6 +244607,347 @@ static int sqlite3Fts5IndexLoadConfig(Fts5Index *p){
return fts5IndexReturn(p);
}
+/*
+** Retrieve the origin value that will be used for the segment currently
+** being accumulated in the in-memory hash table when it is flushed to
+** disk. If successful, SQLITE_OK is returned and (*piOrigin) set to
+** the queried value. Or, if an error occurs, an error code is returned
+** and the final value of (*piOrigin) is undefined.
+*/
+static int sqlite3Fts5IndexGetOrigin(Fts5Index *p, i64 *piOrigin){
+ Fts5Structure *pStruct;
+ pStruct = fts5StructureRead(p);
+ if( pStruct ){
+ *piOrigin = pStruct->nOriginCntr;
+ fts5StructureRelease(pStruct);
+ }
+ return fts5IndexReturn(p);
+}
+
+/*
+** Buffer pPg contains a page of a tombstone hash table - one of nPg pages
+** associated with the same segment. This function adds rowid iRowid to
+** the hash table. The caller is required to guarantee that there is at
+** least one free slot on the page.
+**
+** If parameter bForce is false and the hash table is deemed to be full
+** (more than half of the slots are occupied), then non-zero is returned
+** and iRowid not inserted. Or, if bForce is true or if the hash table page
+** is not full, iRowid is inserted and zero returned.
+*/
+static int fts5IndexTombstoneAddToPage(
+ Fts5Data *pPg,
+ int bForce,
+ int nPg,
+ u64 iRowid
+){
+ const int szKey = TOMBSTONE_KEYSIZE(pPg);
+ const int nSlot = TOMBSTONE_NSLOT(pPg);
+ const int nElem = fts5GetU32(&pPg->p[4]);
+ int iSlot = (iRowid / nPg) % nSlot;
+ int nCollide = nSlot;
+
+ if( szKey==4 && iRowid>0xFFFFFFFF ) return 2;
+ if( iRowid==0 ){
+ pPg->p[1] = 0x01;
+ return 0;
+ }
+
+ if( bForce==0 && nElem>=(nSlot/2) ){
+ return 1;
+ }
+
+ fts5PutU32(&pPg->p[4], nElem+1);
+ if( szKey==4 ){
+ u32 *aSlot = (u32*)&pPg->p[8];
+ while( aSlot[iSlot] ){
+ iSlot = (iSlot + 1) % nSlot;
+ if( nCollide--==0 ) return 0;
+ }
+ fts5PutU32((u8*)&aSlot[iSlot], (u32)iRowid);
+ }else{
+ u64 *aSlot = (u64*)&pPg->p[8];
+ while( aSlot[iSlot] ){
+ iSlot = (iSlot + 1) % nSlot;
+ if( nCollide--==0 ) return 0;
+ }
+ fts5PutU64((u8*)&aSlot[iSlot], iRowid);
+ }
+
+ return 0;
+}
+
+/*
+** This function attempts to build a new hash containing all the keys
+** currently in the tombstone hash table for segment pSeg. The new
+** hash will be stored in the nOut buffers passed in array apOut[].
+** All pages of the new hash use key-size szKey (4 or 8).
+**
+** Return 0 if the hash is successfully rebuilt into the nOut pages.
+** Or non-zero if it is not (because one page became overfull). In this
+** case the caller should retry with a larger nOut parameter.
+**
+** Parameter pData1 is page iPg1 of the hash table being rebuilt.
+*/
+static int fts5IndexTombstoneRehash(
+ Fts5Index *p,
+ Fts5StructureSegment *pSeg, /* Segment to rebuild hash of */
+ Fts5Data *pData1, /* One page of current hash - or NULL */
+ int iPg1, /* Which page of the current hash is pData1 */
+ int szKey, /* 4 or 8, the keysize */
+ int nOut, /* Number of output pages */
+ Fts5Data **apOut /* Array of output hash pages */
+){
+ int ii;
+ int res = 0;
+
+ /* Initialize the headers of all the output pages */
+ for(ii=0; iip[0] = szKey;
+ fts5PutU32(&apOut[ii]->p[4], 0);
+ }
+
+ /* Loop through the current pages of the hash table. */
+ for(ii=0; res==0 && iinPgTombstone; ii++){
+ Fts5Data *pData = 0; /* Page ii of the current hash table */
+ Fts5Data *pFree = 0; /* Free this at the end of the loop */
+
+ if( iPg1==ii ){
+ pData = pData1;
+ }else{
+ pFree = pData = fts5DataRead(p, FTS5_TOMBSTONE_ROWID(pSeg->iSegid, ii));
+ }
+
+ if( pData ){
+ int szKeyIn = TOMBSTONE_KEYSIZE(pData);
+ int nSlotIn = (pData->nn - 8) / szKeyIn;
+ int iIn;
+ for(iIn=0; iInp[8];
+ if( aSlot[iIn] ) iVal = fts5GetU32((u8*)&aSlot[iIn]);
+ }else{
+ u64 *aSlot = (u64*)&pData->p[8];
+ if( aSlot[iIn] ) iVal = fts5GetU64((u8*)&aSlot[iIn]);
+ }
+
+ /* If iVal is not 0 at this point, insert it into the new hash table */
+ if( iVal ){
+ Fts5Data *pPg = apOut[(iVal % nOut)];
+ res = fts5IndexTombstoneAddToPage(pPg, 0, nOut, iVal);
+ if( res ) break;
+ }
+ }
+
+ /* If this is page 0 of the old hash, copy the rowid-0-flag from the
+ ** old hash to the new. */
+ if( ii==0 ){
+ apOut[0]->p[1] = pData->p[1];
+ }
+ }
+ fts5DataRelease(pFree);
+ }
+
+ return res;
+}
+
+/*
+** This is called to rebuild the hash table belonging to segment pSeg.
+** If parameter pData1 is not NULL, then one page of the existing hash table
+** has already been loaded - pData1, which is page iPg1. The key-size for
+** the new hash table is szKey (4 or 8).
+**
+** If successful, the new hash table is not written to disk. Instead,
+** output parameter (*pnOut) is set to the number of pages in the new
+** hash table, and (*papOut) to point to an array of buffers containing
+** the new page data.
+**
+** If an error occurs, an error code is left in the Fts5Index object and
+** both output parameters set to 0 before returning.
+*/
+static void fts5IndexTombstoneRebuild(
+ Fts5Index *p,
+ Fts5StructureSegment *pSeg, /* Segment to rebuild hash of */
+ Fts5Data *pData1, /* One page of current hash - or NULL */
+ int iPg1, /* Which page of the current hash is pData1 */
+ int szKey, /* 4 or 8, the keysize */
+ int *pnOut, /* OUT: Number of output pages */
+ Fts5Data ***papOut /* OUT: Output hash pages */
+){
+ const int MINSLOT = 32;
+ int nSlotPerPage = MAX(MINSLOT, (p->pConfig->pgsz - 8) / szKey);
+ int nSlot = 0; /* Number of slots in each output page */
+ int nOut = 0;
+
+ /* Figure out how many output pages (nOut) and how many slots per
+ ** page (nSlot). There are three possibilities:
+ **
+ ** 1. The hash table does not yet exist. In this case the new hash
+ ** table will consist of a single page with MINSLOT slots.
+ **
+ ** 2. The hash table exists but is currently a single page. In this
+ ** case an attempt is made to grow the page to accommodate the new
+ ** entry. The page is allowed to grow up to nSlotPerPage (see above)
+ ** slots.
+ **
+ ** 3. The hash table already consists of more than one page, or of
+ ** a single page already so large that it cannot be grown. In this
+ ** case the new hash consists of (nPg*2+1) pages of nSlotPerPage
+ ** slots each, where nPg is the current number of pages in the
+ ** hash table.
+ */
+ if( pSeg->nPgTombstone==0 ){
+ /* Case 1. */
+ nOut = 1;
+ nSlot = MINSLOT;
+ }else if( pSeg->nPgTombstone==1 ){
+ /* Case 2. */
+ int nElem = (int)fts5GetU32(&pData1->p[4]);
+ assert( pData1 && iPg1==0 );
+ nOut = 1;
+ nSlot = MAX(nElem*4, MINSLOT);
+ if( nSlot>nSlotPerPage ) nOut = 0;
+ }
+ if( nOut==0 ){
+ /* Case 3. */
+ nOut = (pSeg->nPgTombstone * 2 + 1);
+ nSlot = nSlotPerPage;
+ }
+
+ /* Allocate the required array and output pages */
+ while( 1 ){
+ int res = 0;
+ int ii = 0;
+ int szPage = 0;
+ Fts5Data **apOut = 0;
+
+ /* Allocate space for the new hash table */
+ assert( nSlot>=MINSLOT );
+ apOut = (Fts5Data**)sqlite3Fts5MallocZero(&p->rc, sizeof(Fts5Data*) * nOut);
+ szPage = 8 + nSlot*szKey;
+ for(ii=0; ii